aboutsummaryrefslogtreecommitdiff
path: root/drivers/acpi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig356
-rw-r--r--drivers/acpi/Makefile58
-rw-r--r--drivers/acpi/ac.c354
-rw-r--r--drivers/acpi/acpi_memhotplug.c542
-rw-r--r--drivers/acpi/asus_acpi.c1236
-rw-r--r--drivers/acpi/battery.c846
-rw-r--r--drivers/acpi/blacklist.c169
-rw-r--r--drivers/acpi/bus.c775
-rw-r--r--drivers/acpi/button.c558
-rw-r--r--drivers/acpi/container.c303
-rw-r--r--drivers/acpi/debug.c233
-rw-r--r--drivers/acpi/dispatcher/Makefile9
-rw-r--r--drivers/acpi/dispatcher/dsfield.c601
-rw-r--r--drivers/acpi/dispatcher/dsinit.c235
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c597
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c715
-rw-r--r--drivers/acpi/dispatcher/dsobject.c618
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c1151
-rw-r--r--drivers/acpi/dispatcher/dsutils.c744
-rw-r--r--drivers/acpi/dispatcher/dswexec.c751
-rw-r--r--drivers/acpi/dispatcher/dswload.c976
-rw-r--r--drivers/acpi/dispatcher/dswscope.c229
-rw-r--r--drivers/acpi/dispatcher/dswstate.c1100
-rw-r--r--drivers/acpi/ec.c1024
-rw-r--r--drivers/acpi/event.c140
-rw-r--r--drivers/acpi/events/Makefile9
-rw-r--r--drivers/acpi/events/evevent.c297
-rw-r--r--drivers/acpi/events/evgpe.c756
-rw-r--r--drivers/acpi/events/evgpeblk.c1141
-rw-r--r--drivers/acpi/events/evmisc.c588
-rw-r--r--drivers/acpi/events/evregion.c1067
-rw-r--r--drivers/acpi/events/evrgnini.c580
-rw-r--r--drivers/acpi/events/evsci.c199
-rw-r--r--drivers/acpi/events/evxface.c834
-rw-r--r--drivers/acpi/events/evxfevnt.c778
-rw-r--r--drivers/acpi/events/evxfregn.c247
-rw-r--r--drivers/acpi/executer/Makefile10
-rw-r--r--drivers/acpi/executer/exconfig.c487
-rw-r--r--drivers/acpi/executer/exconvrt.c708
-rw-r--r--drivers/acpi/executer/excreate.c646
-rw-r--r--drivers/acpi/executer/exdump.c793
-rw-r--r--drivers/acpi/executer/exfield.c367
-rw-r--r--drivers/acpi/executer/exfldio.c835
-rw-r--r--drivers/acpi/executer/exmisc.c738
-rw-r--r--drivers/acpi/executer/exmutex.c363
-rw-r--r--drivers/acpi/executer/exnames.c427
-rw-r--r--drivers/acpi/executer/exoparg1.c1013
-rw-r--r--drivers/acpi/executer/exoparg2.c608
-rw-r--r--drivers/acpi/executer/exoparg3.c256
-rw-r--r--drivers/acpi/executer/exoparg6.c336
-rw-r--r--drivers/acpi/executer/exprep.c530
-rw-r--r--drivers/acpi/executer/exregion.c528
-rw-r--r--drivers/acpi/executer/exresnte.c289
-rw-r--r--drivers/acpi/executer/exresolv.c546
-rw-r--r--drivers/acpi/executer/exresop.c661
-rw-r--r--drivers/acpi/executer/exstore.c536
-rw-r--r--drivers/acpi/executer/exstoren.c306
-rw-r--r--drivers/acpi/executer/exstorob.c216
-rw-r--r--drivers/acpi/executer/exsystem.c378
-rw-r--r--drivers/acpi/executer/exutils.c378
-rw-r--r--drivers/acpi/fan.c302
-rw-r--r--drivers/acpi/hardware/Makefile9
-rw-r--r--drivers/acpi/hardware/hwacpi.c230
-rw-r--r--drivers/acpi/hardware/hwgpe.c444
-rw-r--r--drivers/acpi/hardware/hwregs.c850
-rw-r--r--drivers/acpi/hardware/hwsleep.c582
-rw-r--r--drivers/acpi/hardware/hwtimer.c203
-rw-r--r--drivers/acpi/ibm_acpi.c1242
-rw-r--r--drivers/acpi/motherboard.c177
-rw-r--r--drivers/acpi/namespace/Makefile12
-rw-r--r--drivers/acpi/namespace/nsaccess.c637
-rw-r--r--drivers/acpi/namespace/nsalloc.c685
-rw-r--r--drivers/acpi/namespace/nsdump.c673
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c146
-rw-r--r--drivers/acpi/namespace/nseval.c487
-rw-r--r--drivers/acpi/namespace/nsinit.c441
-rw-r--r--drivers/acpi/namespace/nsload.c460
-rw-r--r--drivers/acpi/namespace/nsnames.c265
-rw-r--r--drivers/acpi/namespace/nsobject.c461
-rw-r--r--drivers/acpi/namespace/nsparse.c171
-rw-r--r--drivers/acpi/namespace/nssearch.c381
-rw-r--r--drivers/acpi/namespace/nsutils.c1069
-rw-r--r--drivers/acpi/namespace/nswalk.c289
-rw-r--r--drivers/acpi/namespace/nsxfeval.c764
-rw-r--r--drivers/acpi/namespace/nsxfname.c369
-rw-r--r--drivers/acpi/namespace/nsxfobj.c262
-rw-r--r--drivers/acpi/numa.c213
-rw-r--r--drivers/acpi/osl.c1162
-rw-r--r--drivers/acpi/parser/Makefile8
-rw-r--r--drivers/acpi/parser/psargs.c746
-rw-r--r--drivers/acpi/parser/psopcode.c778
-rw-r--r--drivers/acpi/parser/psparse.c1266
-rw-r--r--drivers/acpi/parser/psscope.c290
-rw-r--r--drivers/acpi/parser/pstree.c327
-rw-r--r--drivers/acpi/parser/psutils.c309
-rw-r--r--drivers/acpi/parser/pswalk.c115
-rw-r--r--drivers/acpi/parser/psxface.c243
-rw-r--r--drivers/acpi/pci_bind.c384
-rw-r--r--drivers/acpi/pci_irq.c518
-rw-r--r--drivers/acpi/pci_link.c904
-rw-r--r--drivers/acpi/pci_root.c347
-rw-r--r--drivers/acpi/power.c692
-rw-r--r--drivers/acpi/processor_core.c989
-rw-r--r--drivers/acpi/processor_idle.c1017
-rw-r--r--drivers/acpi/processor_perflib.c666
-rw-r--r--drivers/acpi/processor_thermal.c406
-rw-r--r--drivers/acpi/processor_throttling.c351
-rw-r--r--drivers/acpi/resources/Makefile10
-rw-r--r--drivers/acpi/resources/rsaddr.c1225
-rw-r--r--drivers/acpi/resources/rscalc.c841
-rw-r--r--drivers/acpi/resources/rscreate.c428
-rw-r--r--drivers/acpi/resources/rsdump.c1150
-rw-r--r--drivers/acpi/resources/rsio.c545
-rw-r--r--drivers/acpi/resources/rsirq.c592
-rw-r--r--drivers/acpi/resources/rslist.c518
-rw-r--r--drivers/acpi/resources/rsmemory.c566
-rw-r--r--drivers/acpi/resources/rsmisc.c597
-rw-r--r--drivers/acpi/resources/rsutils.c356
-rw-r--r--drivers/acpi/resources/rsxface.c437
-rw-r--r--drivers/acpi/scan.c1379
-rw-r--r--drivers/acpi/sleep/Makefile5
-rw-r--r--drivers/acpi/sleep/main.c234
-rw-r--r--drivers/acpi/sleep/poweroff.c39
-rw-r--r--drivers/acpi/sleep/proc.c509
-rw-r--r--drivers/acpi/sleep/sleep.h8
-rw-r--r--drivers/acpi/sleep/wakeup.c209
-rw-r--r--drivers/acpi/system.c187
-rw-r--r--drivers/acpi/tables.c609
-rw-r--r--drivers/acpi/tables/Makefile8
-rw-r--r--drivers/acpi/tables/tbconvrt.c564
-rw-r--r--drivers/acpi/tables/tbget.c493
-rw-r--r--drivers/acpi/tables/tbgetall.c313
-rw-r--r--drivers/acpi/tables/tbinstal.c553
-rw-r--r--drivers/acpi/tables/tbrsdt.c324
-rw-r--r--drivers/acpi/tables/tbutils.c240
-rw-r--r--drivers/acpi/tables/tbxface.c448
-rw-r--r--drivers/acpi/tables/tbxfroot.c606
-rw-r--r--drivers/acpi/thermal.c1445
-rw-r--r--drivers/acpi/toshiba_acpi.c575
-rw-r--r--drivers/acpi/utilities/Makefile8
-rw-r--r--drivers/acpi/utilities/utalloc.c988
-rw-r--r--drivers/acpi/utilities/utcopy.c930
-rw-r--r--drivers/acpi/utilities/utdebug.c624
-rw-r--r--drivers/acpi/utilities/utdelete.c700
-rw-r--r--drivers/acpi/utilities/uteval.c696
-rw-r--r--drivers/acpi/utilities/utglobal.c935
-rw-r--r--drivers/acpi/utilities/utinit.c266
-rw-r--r--drivers/acpi/utilities/utmath.c333
-rw-r--r--drivers/acpi/utilities/utmisc.c1516
-rw-r--r--drivers/acpi/utilities/utobject.c671
-rw-r--r--drivers/acpi/utilities/utxface.c525
-rw-r--r--drivers/acpi/utils.c423
-rw-r--r--drivers/acpi/video.c1989
153 files changed, 82730 insertions, 0 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
new file mode 100644
index 000000000000..0400a52d5085
--- /dev/null
+++ b/drivers/acpi/Kconfig
@@ -0,0 +1,356 @@
+#
+# ACPI Configuration
+#
+
+menu "ACPI (Advanced Configuration and Power Interface) Support"
+ depends on !X86_VISWS
+ depends on !IA64_HP_SIM
+ depends on IA64 || X86
+
+config ACPI
+ bool "ACPI Support"
+ depends on IA64 || X86
+
+ default y
+ ---help---
+ Advanced Configuration and Power Interface (ACPI) support for
+ Linux requires an ACPI compliant platform (hardware/firmware),
+ and assumes the presence of OS-directed configuration and power
+ management (OSPM) software. This option will enlarge your
+ kernel by about 70K.
+
+ Linux ACPI provides a robust functional replacement for several
+ legacy configuration and power management interfaces, including
+ the Plug-and-Play BIOS specification (PnP BIOS), the
+ MultiProcessor Specification (MPS), and the Advanced Power
+ Management (APM) specification. If both ACPI and APM support
+ are configured, whichever is loaded first shall be used.
+
+ The ACPI SourceForge project contains the latest source code,
+ documentation, tools, mailing list subscription, and other
+ information. This project is available at:
+ <http://sourceforge.net/projects/acpi>
+
+ Linux support for ACPI is based on Intel Corporation's ACPI
+ Component Architecture (ACPI CA). For more information see:
+ <http://developer.intel.com/technology/iapc/acpi>
+
+ ACPI is an open industry specification co-developed by Compaq,
+ Intel, Microsoft, Phoenix, and Toshiba. The specification is
+ available at:
+ <http://www.acpi.info>
+
+config ACPI_BOOT
+ bool
+ depends on ACPI || X86_HT
+ default y
+
+if ACPI
+
+config ACPI_INTERPRETER
+ bool
+ depends on !IA64_SGI_SN
+ default y
+
+if ACPI_INTERPRETER
+
+config ACPI_SLEEP
+ bool "Sleep States (EXPERIMENTAL)"
+ depends on X86
+ depends on EXPERIMENTAL && PM
+ default y
+ ---help---
+ This option adds support for ACPI suspend states.
+
+ With this option, you will be able to put the system "to sleep".
+ Sleep states are low power states for the system and devices. All
+ of the system operating state is saved to either memory or disk
+ (depending on the state), to allow the system to resume operation
+ quickly at your request.
+
+ Although this option sounds really nifty, barely any of the device
+ drivers have been converted to the new driver model and hence few
+ have proper power management support.
+
+ This option is not recommended for anyone except those doing driver
+ power management development.
+
+config ACPI_SLEEP_PROC_FS
+ bool
+ depends on ACPI_SLEEP && PROC_FS
+ default y
+
+config ACPI_AC
+ tristate "AC Adapter"
+ depends on X86
+ default m
+ help
+ This driver adds support for the AC Adapter object, which indicates
+ whether a system is on AC, or not. Typically, only mobile systems
+ have this object, since desktops are always on AC.
+
+config ACPI_BATTERY
+ tristate "Battery"
+ depends on X86
+ default m
+ help
+ This driver adds support for battery information through
+ /proc/acpi/battery. If you have a mobile system with a battery,
+ say Y.
+
+config ACPI_BUTTON
+ tristate "Button"
+ depends on !IA64_SGI_SN
+ default m
+ help
+ This driver registers for events based on buttons, such as the
+ power, sleep, and lid switch. In the future, a daemon will read
+ /proc/acpi/event and perform user-defined actions such as shutting
+ down the system. Until then, you can cat it, and see output when
+ a button is pressed.
+
+config ACPI_VIDEO
+ tristate "Video"
+ depends on EXPERIMENTAL
+ depends on !IA64_SGI_SN
+ default m
+ help
+ This driver implement the ACPI Extensions For Display Adapters
+ for integrated graphics devices on motherboard, as specified in
+ ACPI 2.0 Specification, Appendix B, allowing to perform some basic
+ control like defining the video POST device, retrieving EDID information
+ or to setup a video output, etc.
+ Note that this is an ref. implementation only. It may or may not work
+ for your integrated video device.
+
+config ACPI_FAN
+ tristate "Fan"
+ depends on !IA64_SGI_SN
+ default m
+ help
+ This driver adds support for ACPI fan devices, allowing user-mode
+ applications to perform basic fan control (on, off, status).
+
+config ACPI_PROCESSOR
+ tristate "Processor"
+ depends on !IA64_SGI_SN
+ default m
+ help
+ This driver installs ACPI as the idle handler for Linux, and uses
+ ACPI C2 and C3 processor states to save power, on systems that
+ support it.
+
+config ACPI_HOTPLUG_CPU
+ bool "Processor Hotplug (EXPERIMENTAL)"
+ depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
+ depends on !IA64_SGI_SN
+ select ACPI_CONTAINER
+ default n
+ ---help---
+ Select this option if your platform support physical CPU hotplug.
+
+config ACPI_THERMAL
+ tristate "Thermal Zone"
+ depends on ACPI_PROCESSOR
+ default m
+ help
+ This driver adds support for ACPI thermal zones. Most mobile and
+ some desktop systems support ACPI thermal zones. It is HIGHLY
+ recommended that this option be enabled, as your processor(s)
+ may be damaged without it.
+
+config ACPI_NUMA
+ bool "NUMA support"
+ depends on NUMA
+ depends on (IA64 || X86_64)
+ default y if IA64_GENERIC || IA64_SGI_SN2
+
+config ACPI_ASUS
+ tristate "ASUS/Medion Laptop Extras"
+ depends on X86
+ default m
+ ---help---
+ This driver provides support for extra features of ACPI-compatible
+ ASUS laptops. As some of Medion laptops are made by ASUS, it may also
+ support some Medion laptops (such as 9675 for example). It makes all
+ the extra buttons generate standard ACPI events that go through
+ /proc/acpi/events, and (on some models) adds support for changing the
+ display brightness and output, switching the LCD backlight on and off,
+ and most importantly, allows you to blink those fancy LEDs intended
+ for reporting mail and wireless status.
+
+ Note: display switching code is currently considered EXPERIMENTAL,
+ toying with these values may even lock your machine.
+
+ All settings are changed via /proc/acpi/asus directory entries. Owner
+ and group for these entries can be set with asus_uid and asus_gid
+ parameters.
+
+ More information and a userspace daemon for handling the extra buttons
+ at <http://sourceforge.net/projects/acpi4asus/>.
+
+ If you have an ACPI-compatible ASUS laptop, say Y or M here. This
+ driver is still under development, so if your laptop is unsupported or
+ something works not quite as expected, please use the mailing list
+ available on the above page (acpi4asus-user@lists.sourceforge.net)
+
+config ACPI_IBM
+ tristate "IBM ThinkPad Laptop Extras"
+ depends on X86
+ default m
+ ---help---
+ This is a Linux ACPI driver for the IBM ThinkPad laptops. It adds
+ support for Fn-Fx key combinations, Bluetooth control, video
+ output switching, ThinkLight control, UltraBay eject and more.
+ For more information about this driver see <file:Documentation/ibm-acpi.txt>
+ and <http://ibm-acpi.sf.net/> .
+
+ If you have an IBM ThinkPad laptop, say Y or M here.
+
+config ACPI_TOSHIBA
+ tristate "Toshiba Laptop Extras"
+ depends on X86
+ default m
+ ---help---
+ This driver adds support for access to certain system settings
+ on "legacy free" Toshiba laptops. These laptops can be recognized by
+ their lack of a BIOS setup menu and APM support.
+
+ On these machines, all system configuration is handled through the
+ ACPI. This driver is required for access to controls not covered
+ by the general ACPI drivers, such as LCD brightness, video output,
+ etc.
+
+ This driver differs from the non-ACPI Toshiba laptop driver (located
+ under "Processor type and features") in several aspects.
+ Configuration is accessed by reading and writing text files in the
+ /proc tree instead of by program interface to /dev. Furthermore, no
+ power management functions are exposed, as those are handled by the
+ general ACPI drivers.
+
+ More information about this driver is available at
+ <http://memebeam.org/toys/ToshibaAcpiDriver>.
+
+ If you have a legacy free Toshiba laptop (such as the Libretto L1
+ series), say Y.
+
+config ACPI_CUSTOM_DSDT
+ bool "Include Custom DSDT"
+ depends on !STANDALONE
+ default n
+ help
+ Thist option is to load a custom ACPI DSDT
+ If you don't know what that is, say N.
+
+config ACPI_CUSTOM_DSDT_FILE
+ string "Custom DSDT Table file to include"
+ depends on ACPI_CUSTOM_DSDT
+ default ""
+ help
+ Enter the full path name to the file wich includes the AmlCode declaration.
+
+config ACPI_BLACKLIST_YEAR
+ int "Disable ACPI for systems before Jan 1st this year"
+ depends on ACPI_INTERPRETER
+ default 0
+ help
+ enter a 4-digit year, eg. 2001 to disable ACPI by default
+ on platforms with DMI BIOS date before January 1st that year.
+ "acpi=force" can be used to override this mechanism.
+
+ Enter 0 to disable this mechanism and allow ACPI to
+ run by default no matter what the year. (default)
+
+config ACPI_DEBUG
+ bool "Debug Statements"
+ depends on !IA64_SGI_SN
+ default n
+ help
+ The ACPI driver can optionally report errors with a great deal
+ of verbosity. Saying Y enables these statements. This will increase
+ your kernel size by around 50K.
+
+config ACPI_BUS
+ bool
+ depends on !IA64_SGI_SN
+ default y
+
+config ACPI_EC
+ bool
+ depends on X86
+ default y
+ help
+ This driver is required on some systems for the proper operation of
+ the battery and thermal drivers. If you are compiling for a
+ mobile system, say Y.
+
+config ACPI_POWER
+ bool
+ depends on !IA64_SGI_SN
+ default y
+
+config ACPI_PCI
+ bool
+ depends on !IA64_SGI_SN
+ default PCI
+
+config ACPI_SYSTEM
+ bool
+ depends on !IA64_SGI_SN
+ default y
+ help
+ This driver will enable your system to shut down using ACPI, and
+ dump your ACPI DSDT table using /proc/acpi/dsdt.
+
+endif # ACPI_INTERPRETER
+
+config X86_PM_TIMER
+ bool "Power Management Timer Support"
+ depends on X86
+ depends on ACPI_BOOT && EXPERIMENTAL
+ depends on !X86_64
+ default n
+ help
+ The Power Management Timer is available on all ACPI-capable,
+ in most cases even if ACPI is unusable or blacklisted.
+
+ This timing source is not affected by powermanagement features
+ like aggressive processor idling, throttling, frequency and/or
+ voltage scaling, unlike the commonly used Time Stamp Counter
+ (TSC) timing source.
+
+ So, if you see messages like 'Losing too many ticks!' in the
+ kernel logs, and/or you are using this on a notebook which
+ does not yet have an HPET, you should say "Y" here.
+
+config ACPI_CONTAINER
+ tristate "ACPI0004,PNP0A05 and PNP0A06 Container Driver (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
+ ---help---
+ This is the ACPI generic container driver which supports
+ ACPI0004, PNP0A05 and PNP0A06 devices
+
+config ACPI_HOTPLUG_MEMORY
+ tristate "Memory Hotplug"
+ depends on ACPI
+ depends on MEMORY_HOTPLUG
+ default n
+ help
+ This driver adds supports for ACPI Memory Hotplug. This driver
+ provides support for fielding notifications on ACPI memory
+ devices (PNP0C80) which represent memory ranges that may be
+ onlined or offlined during runtime.
+
+ Enabling this driver assumes that your platform hardware
+ and firmware have support for hot-plugging physical memory. If
+ your system does not support physically adding or ripping out
+ memory DIMMs at some platfrom defined granularity (individually
+ or as a bank) at runtime, then you need not enable this driver.
+
+ If one selects "m," this driver can be loaded using the following
+ command:
+ $>modprobe acpi_memhotplug
+endif # ACPI
+
+endmenu
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
new file mode 100644
index 000000000000..65c92e20566d
--- /dev/null
+++ b/drivers/acpi/Makefile
@@ -0,0 +1,58 @@
+#
+# Makefile for the Linux ACPI interpreter
+#
+
+export ACPI_CFLAGS
+
+ACPI_CFLAGS := -Os
+
+ifdef CONFIG_ACPI_DEBUG
+ ACPI_CFLAGS += -DACPI_DEBUG_OUTPUT
+endif
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
+
+#
+# ACPI Boot-Time Table Parsing
+#
+obj-$(CONFIG_ACPI_BOOT) += tables.o
+obj-$(CONFIG_ACPI_INTERPRETER) += blacklist.o
+
+#
+# ACPI Core Subsystem (Interpreter)
+#
+obj-$(CONFIG_ACPI_INTERPRETER) += osl.o utils.o \
+ dispatcher/ events/ executer/ hardware/ \
+ namespace/ parser/ resources/ tables/ \
+ utilities/
+
+#
+# ACPI Bus and Device Drivers
+#
+processor-objs += processor_core.o processor_throttling.o \
+ processor_idle.o processor_thermal.o
+ifdef CONFIG_CPU_FREQ
+processor-objs += processor_perflib.o
+endif
+
+obj-$(CONFIG_ACPI_BUS) += sleep/
+obj-$(CONFIG_ACPI_BUS) += bus.o
+obj-$(CONFIG_ACPI_AC) += ac.o
+obj-$(CONFIG_ACPI_BATTERY) += battery.o
+obj-$(CONFIG_ACPI_BUTTON) += button.o
+obj-$(CONFIG_ACPI_EC) += ec.o
+obj-$(CONFIG_ACPI_FAN) += fan.o
+obj-$(CONFIG_ACPI_VIDEO) += video.o
+obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o
+obj-$(CONFIG_ACPI_POWER) += power.o
+obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
+obj-$(CONFIG_ACPI_CONTAINER) += container.o
+obj-$(CONFIG_ACPI_THERMAL) += thermal.o
+obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
+obj-$(CONFIG_ACPI_DEBUG) += debug.o
+obj-$(CONFIG_ACPI_NUMA) += numa.o
+obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
+obj-$(CONFIG_ACPI_IBM) += ibm_acpi.o
+obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
+obj-$(CONFIG_ACPI_BUS) += scan.o motherboard.o
+obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
new file mode 100644
index 000000000000..23ab761dd721
--- /dev/null
+++ b/drivers/acpi/ac.c
@@ -0,0 +1,354 @@
+/*
+ * acpi_ac.c - ACPI AC Adapter Driver ($Revision: 27 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/proc_fs.h>
+#include <linux/seq_file.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define ACPI_AC_COMPONENT 0x00020000
+#define ACPI_AC_CLASS "ac_adapter"
+#define ACPI_AC_HID "ACPI0003"
+#define ACPI_AC_DRIVER_NAME "ACPI AC Adapter Driver"
+#define ACPI_AC_DEVICE_NAME "AC Adapter"
+#define ACPI_AC_FILE_STATE "state"
+#define ACPI_AC_NOTIFY_STATUS 0x80
+#define ACPI_AC_STATUS_OFFLINE 0x00
+#define ACPI_AC_STATUS_ONLINE 0x01
+#define ACPI_AC_STATUS_UNKNOWN 0xFF
+
+#define _COMPONENT ACPI_AC_COMPONENT
+ACPI_MODULE_NAME ("acpi_ac")
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION(ACPI_AC_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int acpi_ac_add (struct acpi_device *device);
+static int acpi_ac_remove (struct acpi_device *device, int type);
+static int acpi_ac_open_fs(struct inode *inode, struct file *file);
+
+static struct acpi_driver acpi_ac_driver = {
+ .name = ACPI_AC_DRIVER_NAME,
+ .class = ACPI_AC_CLASS,
+ .ids = ACPI_AC_HID,
+ .ops = {
+ .add = acpi_ac_add,
+ .remove = acpi_ac_remove,
+ },
+};
+
+struct acpi_ac {
+ acpi_handle handle;
+ unsigned long state;
+};
+
+static struct file_operations acpi_ac_fops = {
+ .open = acpi_ac_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* --------------------------------------------------------------------------
+ AC Adapter Management
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_ac_get_state (
+ struct acpi_ac *ac)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_ac_get_state");
+
+ if (!ac)
+ return_VALUE(-EINVAL);
+
+ status = acpi_evaluate_integer(ac->handle, "_PSR", NULL, &ac->state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error reading AC Adapter state\n"));
+ ac->state = ACPI_AC_STATUS_UNKNOWN;
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_ac_dir;
+
+static int acpi_ac_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_ac *ac = (struct acpi_ac *) seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_ac_seq_show");
+
+ if (!ac)
+ return_VALUE(0);
+
+ if (acpi_ac_get_state(ac)) {
+ seq_puts(seq, "ERROR: Unable to read AC Adapter state\n");
+ return_VALUE(0);
+ }
+
+ seq_puts(seq, "state: ");
+ switch (ac->state) {
+ case ACPI_AC_STATUS_OFFLINE:
+ seq_puts(seq, "off-line\n");
+ break;
+ case ACPI_AC_STATUS_ONLINE:
+ seq_puts(seq, "on-line\n");
+ break;
+ default:
+ seq_puts(seq, "unknown\n");
+ break;
+ }
+
+ return_VALUE(0);
+}
+
+static int acpi_ac_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_ac_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_ac_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ac_add_fs");
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_ac_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ acpi_device_dir(device)->owner = THIS_MODULE;
+ }
+
+ /* 'state' [R] */
+ entry = create_proc_entry(ACPI_AC_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_AC_FILE_STATE));
+ else {
+ entry->proc_fops = &acpi_ac_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_ac_remove_fs (
+ struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_ac_remove_fs");
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_AC_FILE_STATE,
+ acpi_device_dir(device));
+
+ remove_proc_entry(acpi_device_bid(device), acpi_ac_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Model
+ -------------------------------------------------------------------------- */
+
+static void
+acpi_ac_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_ac *ac = (struct acpi_ac *) data;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ac_notify");
+
+ if (!ac)
+ return_VOID;
+
+ if (acpi_bus_get_device(ac->handle, &device))
+ return_VOID;
+
+ switch (event) {
+ case ACPI_AC_NOTIFY_STATUS:
+ acpi_ac_get_state(ac);
+ acpi_bus_generate_event(device, event, (u32) ac->state);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+
+static int
+acpi_ac_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_ac *ac = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ac_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ ac = kmalloc(sizeof(struct acpi_ac), GFP_KERNEL);
+ if (!ac)
+ return_VALUE(-ENOMEM);
+ memset(ac, 0, sizeof(struct acpi_ac));
+
+ ac->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_AC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_AC_CLASS);
+ acpi_driver_data(device) = ac;
+
+ result = acpi_ac_get_state(ac);
+ if (result)
+ goto end;
+
+ result = acpi_ac_add_fs(device);
+ if (result)
+ goto end;
+
+ status = acpi_install_notify_handler(ac->handle,
+ ACPI_DEVICE_NOTIFY, acpi_ac_notify, ac);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
+ acpi_device_name(device), acpi_device_bid(device),
+ ac->state?"on-line":"off-line");
+
+end:
+ if (result) {
+ acpi_ac_remove_fs(device);
+ kfree(ac);
+ }
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_ac_remove (
+ struct acpi_device *device,
+ int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_ac *ac = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ac_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ ac = (struct acpi_ac *) acpi_driver_data(device);
+
+ status = acpi_remove_notify_handler(ac->handle,
+ ACPI_DEVICE_NOTIFY, acpi_ac_notify);
+ if (ACPI_FAILURE(status))
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+
+ acpi_ac_remove_fs(device);
+
+ kfree(ac);
+
+ return_VALUE(0);
+}
+
+
+static int __init
+acpi_ac_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ac_init");
+
+ acpi_ac_dir = proc_mkdir(ACPI_AC_CLASS, acpi_root_dir);
+ if (!acpi_ac_dir)
+ return_VALUE(-ENODEV);
+ acpi_ac_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&acpi_ac_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+
+static void __exit
+acpi_ac_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_ac_exit");
+
+ acpi_bus_unregister_driver(&acpi_ac_driver);
+
+ remove_proc_entry(ACPI_AC_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+
+
+module_init(acpi_ac_init);
+module_exit(acpi_ac_exit);
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
new file mode 100644
index 000000000000..77285ffe41c5
--- /dev/null
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
+ *
+ * All rights reserved.
+ *
+ * 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, GOOD TITLE or
+ * NON INFRINGEMENT. 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * ACPI based HotPlug driver that supports Memory Hotplug
+ * This driver fields notifications from firmare for memory add
+ * and remove operations and alerts the VM of the affected memory
+ * ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/memory_hotplug.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define ACPI_MEMORY_DEVICE_COMPONENT 0x08000000UL
+#define ACPI_MEMORY_DEVICE_CLASS "memory"
+#define ACPI_MEMORY_DEVICE_HID "PNP0C80"
+#define ACPI_MEMORY_DEVICE_DRIVER_NAME "Hotplug Mem Driver"
+#define ACPI_MEMORY_DEVICE_NAME "Hotplug Mem Device"
+
+#define _COMPONENT ACPI_MEMORY_DEVICE_COMPONENT
+
+ACPI_MODULE_NAME ("acpi_memory")
+MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
+MODULE_DESCRIPTION(ACPI_MEMORY_DEVICE_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+/* ACPI _STA method values */
+#define ACPI_MEMORY_STA_PRESENT (0x00000001UL)
+#define ACPI_MEMORY_STA_ENABLED (0x00000002UL)
+#define ACPI_MEMORY_STA_FUNCTIONAL (0x00000008UL)
+
+/* Memory Device States */
+#define MEMORY_INVALID_STATE 0
+#define MEMORY_POWER_ON_STATE 1
+#define MEMORY_POWER_OFF_STATE 2
+
+static int acpi_memory_device_add (struct acpi_device *device);
+static int acpi_memory_device_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_memory_device_driver = {
+ .name = ACPI_MEMORY_DEVICE_DRIVER_NAME,
+ .class = ACPI_MEMORY_DEVICE_CLASS,
+ .ids = ACPI_MEMORY_DEVICE_HID,
+ .ops = {
+ .add = acpi_memory_device_add,
+ .remove = acpi_memory_device_remove,
+ },
+};
+
+struct acpi_memory_device {
+ acpi_handle handle;
+ unsigned int state; /* State of the memory device */
+ unsigned short cache_attribute; /* memory cache attribute */
+ unsigned short read_write_attribute;/* memory read/write attribute */
+ u64 start_addr; /* Memory Range start physical addr */
+ u64 end_addr; /* Memory Range end physical addr */
+};
+
+
+static int
+acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_resource *resource = NULL;
+ struct acpi_resource_address64 address64;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_get_device_resources");
+
+ /* Get the range from the _CRS */
+ status = acpi_get_current_resources(mem_device->handle, &buffer);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-EINVAL);
+
+ resource = (struct acpi_resource *) buffer.pointer;
+ status = acpi_resource_to_address64(resource, &address64);
+ if (ACPI_SUCCESS(status)) {
+ if (address64.resource_type == ACPI_MEMORY_RANGE) {
+ /* Populate the structure */
+ mem_device->cache_attribute =
+ address64.attribute.memory.cache_attribute;
+ mem_device->read_write_attribute =
+ address64.attribute.memory.read_write_attribute;
+ mem_device->start_addr = address64.min_address_range;
+ mem_device->end_addr = address64.max_address_range;
+ }
+ }
+
+ acpi_os_free(buffer.pointer);
+ return_VALUE(0);
+}
+
+static int
+acpi_memory_get_device(acpi_handle handle,
+ struct acpi_memory_device **mem_device)
+{
+ acpi_status status;
+ acpi_handle phandle;
+ struct acpi_device *device = NULL;
+ struct acpi_device *pdevice = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_get_device");
+
+ if (!acpi_bus_get_device(handle, &device) && device)
+ goto end;
+
+ status = acpi_get_parent(handle, &phandle);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error in acpi_get_parent\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ /* Get the parent device */
+ status = acpi_bus_get_device(phandle, &pdevice);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error in acpi_bus_get_device\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ /*
+ * Now add the notified device. This creates the acpi_device
+ * and invokes .add function
+ */
+ status = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error in acpi_bus_add\n"));
+ return_VALUE(-EINVAL);
+ }
+
+end:
+ *mem_device = acpi_driver_data(device);
+ if (!(*mem_device)) {
+ printk(KERN_ERR "\n driver data not found" );
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+static int
+acpi_memory_check_device(struct acpi_memory_device *mem_device)
+{
+ unsigned long current_status;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_check_device");
+
+ /* Get device present/absent information from the _STA */
+ if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->handle, "_STA",
+ NULL, &current_status)))
+ return_VALUE(-ENODEV);
+ /*
+ * Check for device status. Device should be
+ * present/enabled/functioning.
+ */
+ if (!((current_status & ACPI_MEMORY_STA_PRESENT)
+ && (current_status & ACPI_MEMORY_STA_ENABLED)
+ && (current_status & ACPI_MEMORY_STA_FUNCTIONAL)))
+ return_VALUE(-ENODEV);
+
+ return_VALUE(0);
+}
+
+static int
+acpi_memory_enable_device(struct acpi_memory_device *mem_device)
+{
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_enable_device");
+
+ /* Get the range from the _CRS */
+ result = acpi_memory_get_device_resources(mem_device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "\nget_device_resources failed\n"));
+ mem_device->state = MEMORY_INVALID_STATE;
+ return result;
+ }
+
+ /*
+ * Tell the VM there is more memory here...
+ * Note: Assume that this function returns zero on success
+ */
+ result = add_memory(mem_device->start_addr,
+ (mem_device->end_addr - mem_device->start_addr) + 1,
+ mem_device->read_write_attribute);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "\nadd_memory failed\n"));
+ mem_device->state = MEMORY_INVALID_STATE;
+ return result;
+ }
+
+ return result;
+}
+
+static int
+acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
+{
+ acpi_status status;
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ unsigned long current_status;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_powerdown_device");
+
+ /* Issue the _EJ0 command */
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+ status = acpi_evaluate_object(mem_device->handle,
+ "_EJ0", &arg_list, NULL);
+ /* Return on _EJ0 failure */
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"_EJ0 failed.\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ /* Evalute _STA to check if the device is disabled */
+ status = acpi_evaluate_integer(mem_device->handle, "_STA",
+ NULL, &current_status);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ /* Check for device status. Device should be disabled */
+ if (current_status & ACPI_MEMORY_STA_ENABLED)
+ return_VALUE(-EINVAL);
+
+ return_VALUE(0);
+}
+
+static int
+acpi_memory_disable_device(struct acpi_memory_device *mem_device)
+{
+ int result;
+ u64 start = mem_device->start_addr;
+ u64 len = mem_device->end_addr - start + 1;
+ unsigned long attr = mem_device->read_write_attribute;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_disable_device");
+
+ /*
+ * Ask the VM to offline this memory range.
+ * Note: Assume that this function returns zero on success
+ */
+ result = remove_memory(start, len, attr);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Hot-Remove failed.\n"));
+ return_VALUE(result);
+ }
+
+ /* Power-off and eject the device */
+ result = acpi_memory_powerdown_device(mem_device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Device Power Down failed.\n"));
+ /* Set the status of the device to invalid */
+ mem_device->state = MEMORY_INVALID_STATE;
+ return result;
+ }
+
+ mem_device->state = MEMORY_POWER_OFF_STATE;
+ return result;
+}
+
+static void
+acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_memory_device *mem_device;
+ struct acpi_device *device;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_device_notify");
+
+ switch (event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "\nReceived BUS CHECK notification for device\n"));
+ /* Fall Through */
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ if (event == ACPI_NOTIFY_DEVICE_CHECK)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "\nReceived DEVICE CHECK notification for device\n"));
+ if (acpi_memory_get_device(handle, &mem_device)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error in finding driver data\n"));
+ return_VOID;
+ }
+
+ if (!acpi_memory_check_device(mem_device)) {
+ if (acpi_memory_enable_device(mem_device))
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error in acpi_memory_enable_device\n"));
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "\nReceived EJECT REQUEST notification for device\n"));
+
+ if (acpi_bus_get_device(handle, &device)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Device doesn't exist\n"));
+ break;
+ }
+ mem_device = acpi_driver_data(device);
+ if (!mem_device) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Driver Data is NULL\n"));
+ break;
+ }
+
+ /*
+ * Currently disabling memory device from kernel mode
+ * TBD: Can also be disabled from user mode scripts
+ * TBD: Can also be disabled by Callback registration
+ * with generic sysfs driver
+ */
+ if (acpi_memory_disable_device(mem_device))
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error in acpi_memory_disable_device\n"));
+ /*
+ * TBD: Invoke acpi_bus_remove to cleanup data structures
+ */
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+static int
+acpi_memory_device_add(struct acpi_device *device)
+{
+ int result;
+ struct acpi_memory_device *mem_device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_device_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ mem_device = kmalloc(sizeof(struct acpi_memory_device), GFP_KERNEL);
+ if (!mem_device)
+ return_VALUE(-ENOMEM);
+ memset(mem_device, 0, sizeof(struct acpi_memory_device));
+
+ mem_device->handle = device->handle;
+ sprintf(acpi_device_name(device), "%s", ACPI_MEMORY_DEVICE_NAME);
+ sprintf(acpi_device_class(device), "%s", ACPI_MEMORY_DEVICE_CLASS);
+ acpi_driver_data(device) = mem_device;
+
+ /* Get the range from the _CRS */
+ result = acpi_memory_get_device_resources(mem_device);
+ if (result) {
+ kfree(mem_device);
+ return_VALUE(result);
+ }
+
+ /* Set the device state */
+ mem_device->state = MEMORY_POWER_ON_STATE;
+
+ printk(KERN_INFO "%s \n", acpi_device_name(device));
+
+ return_VALUE(result);
+}
+
+static int
+acpi_memory_device_remove (struct acpi_device *device, int type)
+{
+ struct acpi_memory_device *mem_device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_device_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ mem_device = (struct acpi_memory_device *) acpi_driver_data(device);
+ kfree(mem_device);
+
+ return_VALUE(0);
+}
+
+/*
+ * Helper function to check for memory device
+ */
+static acpi_status
+is_memory_device(acpi_handle handle)
+{
+ char *hardware_id;
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_device_info *info;
+
+ ACPI_FUNCTION_TRACE("is_memory_device");
+
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(AE_ERROR);
+
+ info = buffer.pointer;
+ if (!(info->valid & ACPI_VALID_HID)) {
+ acpi_os_free(buffer.pointer);
+ return_ACPI_STATUS(AE_ERROR);
+ }
+
+ hardware_id = info->hardware_id.value;
+ if ((hardware_id == NULL) ||
+ (strcmp(hardware_id, ACPI_MEMORY_DEVICE_HID)))
+ status = AE_ERROR;
+
+ acpi_os_free(buffer.pointer);
+ return_ACPI_STATUS(status);
+}
+
+static acpi_status
+acpi_memory_register_notify_handler (acpi_handle handle,
+ u32 level, void *ctxt, void **retv)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_register_notify_handler");
+
+ status = is_memory_device(handle);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(AE_OK); /* continue */
+
+ status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ acpi_memory_device_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ return_ACPI_STATUS(AE_OK); /* continue */
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+static acpi_status
+acpi_memory_deregister_notify_handler (acpi_handle handle,
+ u32 level, void *ctxt, void **retv)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_deregister_notify_handler");
+
+ status = is_memory_device(handle);
+ if (ACPI_FAILURE(status))
+ return_ACPI_STATUS(AE_OK); /* continue */
+
+ status = acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY, acpi_memory_device_notify);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+ return_ACPI_STATUS(AE_OK); /* continue */
+ }
+
+ return_ACPI_STATUS(status);
+}
+
+static int __init
+acpi_memory_device_init (void)
+{
+ int result;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_device_init");
+
+ result = acpi_bus_register_driver(&acpi_memory_device_driver);
+
+ if (result < 0)
+ return_VALUE(-ENODEV);
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ acpi_memory_register_notify_handler,
+ NULL, NULL);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed\n"));
+ acpi_bus_unregister_driver(&acpi_memory_device_driver);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+static void __exit
+acpi_memory_device_exit (void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_memory_device_exit");
+
+ /*
+ * Adding this to un-install notification handlers for all the device
+ * handles.
+ */
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ acpi_memory_deregister_notify_handler,
+ NULL, NULL);
+
+ if (ACPI_FAILURE (status))
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed\n"));
+
+ acpi_bus_unregister_driver(&acpi_memory_device_driver);
+
+ return_VOID;
+}
+
+module_init(acpi_memory_device_init);
+module_exit(acpi_memory_device_exit);
+
+
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
new file mode 100644
index 000000000000..a75cb565caeb
--- /dev/null
+++ b/drivers/acpi/asus_acpi.c
@@ -0,0 +1,1236 @@
+/*
+ * asus_acpi.c - Asus Laptop ACPI Extras
+ *
+ *
+ * Copyright (C) 2002, 2003, 2004 Julien Lerouge, Karol Kozimor
+ *
+ * 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
+ *
+ *
+ * The development page for this driver is located at
+ * http://sourceforge.net/projects/acpi4asus/
+ *
+ * Credits:
+ * Pontus Fuchs - Helper functions, cleanup
+ * Johann Wiesner - Small compile fixes
+ * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
+ *
+ * TODO:
+ * add Fn key status
+ * Add mode selection on module loading (parameter) -> still necessary?
+ * Complete display switching -- may require dirty hacks or calling _DOS?
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ASUS_ACPI_VERSION "0.29"
+
+#define PROC_ASUS "asus" //the directory
+#define PROC_MLED "mled"
+#define PROC_WLED "wled"
+#define PROC_TLED "tled"
+#define PROC_INFO "info"
+#define PROC_LCD "lcd"
+#define PROC_BRN "brn"
+#define PROC_DISP "disp"
+
+#define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver"
+#define ACPI_HOTK_CLASS "hotkey"
+#define ACPI_HOTK_DEVICE_NAME "Hotkey"
+#define ACPI_HOTK_HID "ATK0100"
+
+/*
+ * Some events we use, same for all Asus
+ */
+#define BR_UP 0x10
+#define BR_DOWN 0x20
+
+/*
+ * Flags for hotk status
+ */
+#define MLED_ON 0x01 //is MLED ON ?
+#define WLED_ON 0x02
+#define TLED_ON 0x04
+
+MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
+MODULE_DESCRIPTION(ACPI_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+
+static uid_t asus_uid;
+static gid_t asus_gid;
+module_param(asus_uid, uint, 0);
+MODULE_PARM_DESC(uid, "UID for entries in /proc/acpi/asus.\n");
+module_param(asus_gid, uint, 0);
+MODULE_PARM_DESC(gid, "GID for entries in /proc/acpi/asus.\n");
+
+
+/* For each model, all features implemented,
+ * those marked with R are relative to HOTK, A for absolute */
+struct model_data {
+ char *name; //name of the laptop________________A
+ char *mt_mled; //method to handle mled_____________R
+ char *mled_status; //node to handle mled reading_______A
+ char *mt_wled; //method to handle wled_____________R
+ char *wled_status; //node to handle wled reading_______A
+ char *mt_tled; //method to handle tled_____________R
+ char *tled_status; //node to handle tled reading_______A
+ char *mt_lcd_switch; //method to turn LCD ON/OFF_________A
+ char *lcd_status; //node to read LCD panel state______A
+ char *brightness_up; //method to set brightness up_______A
+ char *brightness_down; //guess what ?______________________A
+ char *brightness_set; //method to set absolute brightness_R
+ char *brightness_get; //method to get absolute brightness_R
+ char *brightness_status; //node to get brightness____________A
+ char *display_set; //method to set video output________R
+ char *display_get; //method to get video output________R
+};
+
+/*
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
+ */
+struct asus_hotk {
+ struct acpi_device *device; //the device we are in
+ acpi_handle handle; //the handle of the hotk device
+ char status; //status of the hotk, for LEDs, ...
+ struct model_data *methods; //methods available on the laptop
+ u8 brightness; //brightness level
+ enum {
+ A1x = 0, //A1340D, A1300F
+ A2x, //A2500H
+ D1x, //D1
+ L2D, //L2000D
+ L3C, //L3800C
+ L3D, //L3400D
+ L3H, //L3H, but also L2000E
+ L4R, //L4500R
+ L5x, //L5800C
+ L8L, //L8400L
+ M1A, //M1300A
+ M2E, //M2400E, L4400L
+ M6N, //M6800N
+ M6R, //M6700R
+ P30, //Samsung P30
+ S1x, //S1300A, but also L1400B and M2400A (L84F)
+ S2x, //S200 (J1 reported), Victor MP-XP7210
+ xxN, //M2400N, M3700N, M5200N, S1300N, S5200N, W1OOON
+ //(Centrino)
+ END_MODEL
+ } model; //Models currently supported
+ u16 event_count[128]; //count for each event TODO make this better
+};
+
+/* Here we go */
+#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
+#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
+#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
+#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
+#define S1x_PREFIX "\\_SB.PCI0.PX40."
+#define S2x_PREFIX A1x_PREFIX
+#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
+
+static struct model_data model_conf[END_MODEL] = {
+ /*
+ * Those pathnames are relative to the HOTK / ATKD device :
+ * - mt_mled
+ * - mt_wled
+ * - brightness_set
+ * - brightness_get
+ * - display_set
+ * - display_get
+ *
+ * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
+ * it seems to be a kind of switch, but what for ?
+ *
+ */
+
+ {
+ .name = "A1x",
+ .mt_mled = "MLED",
+ .mled_status = "\\MAIL",
+ .mt_lcd_switch = A1x_PREFIX "_Q10",
+ .lcd_status = "\\BKLI",
+ .brightness_up = A1x_PREFIX "_Q0E",
+ .brightness_down = A1x_PREFIX "_Q0F"
+ },
+
+ {
+ .name = "A2x",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .wled_status = "\\SG66",
+ .mt_lcd_switch = "\\Q10",
+ .lcd_status = "\\BAOF",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "D1x",
+ .mt_mled = "MLED",
+ .mt_lcd_switch = "\\Q0D",
+ .lcd_status = "\\GP11",
+ .brightness_up = "\\Q0C",
+ .brightness_down = "\\Q0B",
+ .brightness_status = "\\BLVL",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "L2D",
+ .mt_mled = "MLED",
+ .mled_status = "\\SGP6",
+ .mt_wled = "WLED",
+ .wled_status = "\\RCP3",
+ .mt_lcd_switch = "\\Q10",
+ .lcd_status = "\\SGP0",
+ .brightness_up = "\\Q0E",
+ .brightness_down = "\\Q0F",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "L3C",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = L3C_PREFIX "_Q10",
+ .lcd_status = "\\GL32",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP"
+ },
+
+ {
+ .name = "L3D",
+ .mt_mled = "MLED",
+ .mled_status = "\\MALD",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = "\\Q10",
+ .lcd_status = "\\BKLG",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "L3H",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = "EHK",
+ .lcd_status = "\\_SB.PCI0.PM.PBC",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "L4R",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .wled_status = "\\_SB.PCI0.SBRG.SG13",
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"
+ },
+
+ {
+ .name = "L5x",
+ .mt_mled = "MLED",
+/* WLED present, but not controlled by ACPI */
+ .mt_tled = "TLED",
+ .mt_lcd_switch = "\\Q0D",
+ .lcd_status = "\\BAOF",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "L8L"
+/* No features, but at least support the hotkeys */
+ },
+
+ {
+ .name = "M1A",
+ .mt_mled = "MLED",
+ .mt_lcd_switch = M1A_PREFIX "Q10",
+ .lcd_status = "\\PNOF",
+ .brightness_up = M1A_PREFIX "Q0E",
+ .brightness_down = M1A_PREFIX "Q0F",
+ .brightness_status = "\\BRIT",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "M2E",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = "\\Q10",
+ .lcd_status = "\\GP06",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\INFB"
+ },
+
+ {
+ .name = "M6N",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .wled_status = "\\_SB.PCI0.SBRG.SG13",
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .lcd_status = "\\_SB.BKLT",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\SSTE"
+ },
+ {
+ .name = "M6R",
+ .mt_mled = "MLED",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\SSTE"
+ },
+
+
+ {
+ .name = "P30",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = P30_PREFIX "_Q0E",
+ .lcd_status = "\\BKLT",
+ .brightness_up = P30_PREFIX "_Q68",
+ .brightness_down = P30_PREFIX "_Q69",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\DNXT"
+ },
+
+ {
+ .name = "S1x",
+ .mt_mled = "MLED",
+ .mled_status = "\\EMLE",
+ .mt_wled = "WLED",
+ .mt_lcd_switch = S1x_PREFIX "Q10" ,
+ .lcd_status = "\\PNOF",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV"
+ },
+
+ {
+ .name = "S2x",
+ .mt_mled = "MLED",
+ .mled_status = "\\MAIL",
+ .mt_lcd_switch = S2x_PREFIX "_Q10",
+ .lcd_status = "\\BKLI",
+ .brightness_up = S2x_PREFIX "_Q0B",
+ .brightness_down = S2x_PREFIX "_Q0A"
+ },
+
+ {
+ .name = "xxN",
+ .mt_mled = "MLED",
+/* WLED present, but not controlled by ACPI */
+ .mt_lcd_switch = xxN_PREFIX "_Q10",
+ .lcd_status = "\\BKLT",
+ .brightness_set = "SPLV",
+ .brightness_get = "GPLV",
+ .display_set = "SDSP",
+ .display_get = "\\ADVG"
+ }
+};
+
+/* procdir we use */
+static struct proc_dir_entry *asus_proc_dir;
+
+/*
+ * This header is made available to allow proper configuration given model,
+ * revision number , ... this info cannot go in struct asus_hotk because it is
+ * available before the hotk
+ */
+static struct acpi_table_header *asus_info;
+
+/* The actual device the driver binds to */
+static struct asus_hotk *hotk;
+
+/*
+ * The hotkey driver declaration
+ */
+static int asus_hotk_add(struct acpi_device *device);
+static int asus_hotk_remove(struct acpi_device *device, int type);
+static struct acpi_driver asus_hotk_driver = {
+ .name = ACPI_HOTK_NAME,
+ .class = ACPI_HOTK_CLASS,
+ .ids = ACPI_HOTK_HID,
+ .ops = {
+ .add = asus_hotk_add,
+ .remove = asus_hotk_remove,
+ },
+};
+
+/*
+ * This function evaluates an ACPI method, given an int as parameter, the
+ * method is searched within the scope of the handle, can be NULL. The output
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params; //list of input parameters (an int here)
+ union acpi_object in_obj; //the only param we use
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+
+ status = acpi_evaluate_object(handle, (char *) method, &params, output);
+ return (status == AE_OK);
+}
+
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val)
+{
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, (char *) method, NULL, &output);
+ *val = out_obj.integer.value;
+ return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+}
+
+/*
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+static int
+proc_read_info(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ int len = 0;
+ int temp;
+ char buf[16]; //enough for all info
+ /*
+ * We use the easy way, we don't care of off and count, so we don't set eof
+ * to 1
+ */
+
+ len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
+ len += sprintf(page + len, "Model reference : %s\n",
+ hotk->methods->name);
+ /*
+ * The SFUN method probably allows the original driver to get the list
+ * of features supported by a given model. For now, 0x0100 or 0x0800
+ * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
+ * The significance of others is yet to be found.
+ */
+ if (read_acpi_int(hotk->handle, "SFUN", &temp))
+ len += sprintf(page + len, "SFUN value : 0x%04x\n", temp);
+ /*
+ * Another value for userspace: the ASYM method returns 0x02 for
+ * battery low and 0x04 for battery critical, its readings tend to be
+ * more accurate than those provided by _BST.
+ * Note: since not all the laptops provide this method, errors are
+ * silently ignored.
+ */
+ if (read_acpi_int(hotk->handle, "ASYM", &temp))
+ len += sprintf(page + len, "ASYM value : 0x%04x\n", temp);
+ if (asus_info) {
+ snprintf(buf, 16, "%d", asus_info->length);
+ len += sprintf(page + len, "DSDT length : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->checksum);
+ len += sprintf(page + len, "DSDT checksum : %s\n", buf);
+ snprintf(buf, 16, "%d", asus_info->revision);
+ len += sprintf(page + len, "DSDT revision : %s\n", buf);
+ snprintf(buf, 7, "%s", asus_info->oem_id);
+ len += sprintf(page + len, "OEM id : %s\n", buf);
+ snprintf(buf, 9, "%s", asus_info->oem_table_id);
+ len += sprintf(page + len, "OEM table id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->oem_revision);
+ len += sprintf(page + len, "OEM revision : 0x%s\n", buf);
+ snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+ len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+ snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+ len += sprintf(page + len, "ASL comp revision : 0x%s\n", buf);
+ }
+
+ return len;
+}
+
+
+/*
+ * /proc handlers
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+
+/* Generic LED functions */
+static int
+read_led(const char *ledname, int ledmask)
+{
+ if (ledname) {
+ int led_status;
+
+ if (read_acpi_int(NULL, ledname, &led_status))
+ return led_status;
+ else
+ printk(KERN_WARNING "Asus ACPI: Error reading LED "
+ "status\n");
+ }
+ return (hotk->status & ledmask) ? 1 : 0;
+}
+
+static int parse_arg(const char __user *buf, unsigned long count, int *val)
+{
+ char s[32];
+ if (!count)
+ return 0;
+ if (count > 31)
+ return -EINVAL;
+ if (copy_from_user(s, buf, count))
+ return -EFAULT;
+ s[count] = 0;
+ if (sscanf(s, "%i", val) != 1)
+ return -EINVAL;
+ return count;
+}
+
+/* FIXME: kill extraneous args so it can be called independently */
+static int
+write_led(const char __user *buffer, unsigned long count,
+ char *ledname, int ledmask, int invert)
+{
+ int value;
+ int led_out = 0;
+
+ count = parse_arg(buffer, count, &value);
+ if (count > 0)
+ led_out = value ? 1 : 0;
+
+ hotk->status =
+ (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask);
+
+ if (invert) /* invert target value */
+ led_out = !led_out & 0x1;
+
+ if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
+ printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n", ledname);
+
+ return count;
+}
+
+
+/*
+ * Proc handlers for MLED
+ */
+static int
+proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ return sprintf(page, "%d\n", read_led(hotk->methods->mled_status, MLED_ON));
+}
+
+
+static int
+proc_write_mled(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
+}
+
+/*
+ * Proc handlers for WLED
+ */
+static int
+proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ return sprintf(page, "%d\n", read_led(hotk->methods->wled_status, WLED_ON));
+}
+
+static int
+proc_write_wled(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
+}
+
+/*
+ * Proc handlers for TLED
+ */
+static int
+proc_read_tled(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ return sprintf(page, "%d\n", read_led(hotk->methods->tled_status, TLED_ON));
+}
+
+static int
+proc_write_tled(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
+}
+
+
+static int get_lcd_state(void)
+{
+ int lcd = 0;
+
+ if (hotk->model != L3H) {
+ /* We don't have to check anything if we are here */
+ if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
+ printk(KERN_WARNING "Asus ACPI: Error reading LCD status\n");
+
+ if (hotk->model == L2D)
+ lcd = ~lcd;
+ } else { /* L3H and the like have to be handled differently */
+ acpi_status status = 0;
+ struct acpi_object_list input;
+ union acpi_object mt_params[2];
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+
+ input.count = 2;
+ input.pointer = mt_params;
+ /* Note: the following values are partly guessed up, but
+ otherwise they seem to work */
+ mt_params[0].type = ACPI_TYPE_INTEGER;
+ mt_params[0].integer.value = 0x02;
+ mt_params[1].type = ACPI_TYPE_INTEGER;
+ mt_params[1].integer.value = 0x02;
+
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(NULL, hotk->methods->lcd_status, &input, &output);
+ if (status != AE_OK)
+ return -1;
+ if (out_obj.type == ACPI_TYPE_INTEGER)
+ /* That's what the AML code does */
+ lcd = out_obj.integer.value >> 8;
+ }
+
+ return (lcd & 1);
+}
+
+static int set_lcd_state(int value)
+{
+ int lcd = 0;
+ acpi_status status = 0;
+
+ lcd = value ? 1 : 0;
+ if (lcd != get_lcd_state()) {
+ /* switch */
+ if (hotk->model != L3H) {
+ status =
+ acpi_evaluate_object(NULL, hotk->methods->mt_lcd_switch,
+ NULL, NULL);
+ } else { /* L3H and the like have to be handled differently */
+ if (!write_acpi_int(hotk->handle, hotk->methods->mt_lcd_switch, 0x07, NULL))
+ status = AE_ERROR;
+ /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
+ the exact behaviour is simulated here */
+ }
+ if (ACPI_FAILURE(status))
+ printk(KERN_WARNING "Asus ACPI: Error switching LCD\n");
+ }
+ return 0;
+
+}
+
+static int
+proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ return sprintf(page, "%d\n", get_lcd_state());
+}
+
+
+static int
+proc_write_lcd(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int value;
+
+ count = parse_arg(buffer, count, &value);
+ if (count > 0)
+ set_lcd_state(value);
+ return count;
+}
+
+
+static int read_brightness(void)
+{
+ int value;
+
+ if(hotk->methods->brightness_get) { /* SPLV/GPLV laptop */
+ if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
+ &value))
+ printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
+ } else if (hotk->methods->brightness_status) { /* For D1 for example */
+ if (!read_acpi_int(NULL, hotk->methods->brightness_status,
+ &value))
+ printk(KERN_WARNING "Asus ACPI: Error reading brightness\n");
+ } else /* No GPLV method */
+ value = hotk->brightness;
+ return value;
+}
+
+/*
+ * Change the brightness level
+ */
+static void set_brightness(int value)
+{
+ acpi_status status = 0;
+
+ /* SPLV laptop */
+ if(hotk->methods->brightness_set) {
+ if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
+ value, NULL))
+ printk(KERN_WARNING "Asus ACPI: Error changing brightness\n");
+ return;
+ }
+
+ /* No SPLV method if we are here, act as appropriate */
+ value -= read_brightness();
+ while (value != 0) {
+ status = acpi_evaluate_object(NULL, (value > 0) ?
+ hotk->methods->brightness_up :
+ hotk->methods->brightness_down,
+ NULL, NULL);
+ (value > 0) ? value-- : value++;
+ if (ACPI_FAILURE(status))
+ printk(KERN_WARNING "Asus ACPI: Error changing brightness\n");
+ }
+ return;
+}
+
+static int
+proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ return sprintf(page, "%d\n", read_brightness());
+}
+
+static int
+proc_write_brn(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int value;
+
+ count = parse_arg(buffer, count, &value);
+ if (count > 0) {
+ value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+ /* 0 <= value <= 15 */
+ set_brightness(value);
+ } else if (count < 0) {
+ printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+ }
+
+ return count;
+}
+
+static void set_display(int value)
+{
+ /* no sanity check needed for now */
+ if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
+ value, NULL))
+ printk(KERN_WARNING "Asus ACPI: Error setting display\n");
+ return;
+}
+
+/*
+ * Now, *this* one could be more user-friendly, but so far, no-one has
+ * complained. The significance of bits is the same as in proc_write_disp()
+ */
+static int
+proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
+ void *data)
+{
+ int value = 0;
+
+ if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
+ printk(KERN_WARNING "Asus ACPI: Error reading display status\n");
+ value &= 0x07; /* needed for some models, shouldn't hurt others */
+ return sprintf(page, "%d\n", value);
+}
+
+/*
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
+ * (bitwise) of these will suffice. I never actually tested 3 displays hooked up
+ * simultaneously, so be warned. See the acpi4asus README for more info.
+ */
+static int
+proc_write_disp(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ int value;
+
+ count = parse_arg(buffer, count, &value);
+ if (count > 0)
+ set_display(value);
+ else if (count < 0)
+ printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
+
+ return count;
+}
+
+
+typedef int (proc_readfunc)(char *page, char **start, off_t off, int count,
+ int *eof, void *data);
+typedef int (proc_writefunc)(struct file *file, const char __user *buffer,
+ unsigned long count, void *data);
+
+static int
+__init asus_proc_add(char *name, proc_writefunc *writefunc,
+ proc_readfunc *readfunc, mode_t mode,
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *proc = create_proc_entry(name, mode, acpi_device_dir(device));
+ if(!proc) {
+ printk(KERN_WARNING " Unable to create %s fs entry\n", name);
+ return -1;
+ }
+ proc->write_proc = writefunc;
+ proc->read_proc = readfunc;
+ proc->data = acpi_driver_data(device);
+ proc->owner = THIS_MODULE;
+ proc->uid = asus_uid;
+ proc->gid = asus_gid;
+ return 0;
+}
+
+static int __init asus_hotk_add_fs(struct acpi_device *device)
+{
+ struct proc_dir_entry *proc;
+ mode_t mode;
+
+ /*
+ * If parameter uid or gid is not changed, keep the default setting for
+ * our proc entries (-rw-rw-rw-) else, it means we care about security,
+ * and then set to -rw-rw----
+ */
+
+ if ((asus_uid == 0) && (asus_gid == 0)){
+ mode = S_IFREG | S_IRUGO | S_IWUGO;
+ } else {
+ mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
+ }
+
+ acpi_device_dir(device) = asus_proc_dir;
+ if (!acpi_device_dir(device))
+ return -ENODEV;
+
+ proc = create_proc_entry(PROC_INFO, mode, acpi_device_dir(device));
+ if (proc) {
+ proc->read_proc = proc_read_info;
+ proc->data = acpi_driver_data(device);
+ proc->owner = THIS_MODULE;
+ proc->uid = asus_uid;
+ proc->gid = asus_gid;
+ } else {
+ printk(KERN_WARNING " Unable to create " PROC_INFO
+ " fs entry\n");
+ }
+
+ if (hotk->methods->mt_wled) {
+ asus_proc_add(PROC_WLED, &proc_write_wled, &proc_read_wled, mode, device);
+ }
+
+ if (hotk->methods->mt_mled) {
+ asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled, mode, device);
+ }
+
+ if (hotk->methods->mt_tled) {
+ asus_proc_add(PROC_TLED, &proc_write_tled, &proc_read_tled, mode, device);
+ }
+
+ /*
+ * We need both read node and write method as LCD switch is also accessible
+ * from keyboard
+ */
+ if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
+ asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode, device);
+ }
+
+ if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
+ (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
+ asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode, device);
+ }
+
+ if (hotk->methods->display_set) {
+ asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp, mode, device);
+ }
+
+ return 0;
+}
+
+static int asus_hotk_remove_fs(struct acpi_device* device)
+{
+ if(acpi_device_dir(device)) {
+ remove_proc_entry(PROC_INFO,acpi_device_dir(device));
+ if (hotk->methods->mt_wled)
+ remove_proc_entry(PROC_WLED,acpi_device_dir(device));
+ if (hotk->methods->mt_mled)
+ remove_proc_entry(PROC_MLED,acpi_device_dir(device));
+ if (hotk->methods->mt_tled)
+ remove_proc_entry(PROC_TLED,acpi_device_dir(device));
+ if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
+ remove_proc_entry(PROC_LCD, acpi_device_dir(device));
+ if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
+ (hotk->methods->brightness_get && hotk->methods->brightness_set))
+ remove_proc_entry(PROC_BRN, acpi_device_dir(device));
+ if (hotk->methods->display_set)
+ remove_proc_entry(PROC_DISP, acpi_device_dir(device));
+ }
+ return 0;
+}
+
+
+static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+ /* TODO Find a better way to handle events count.*/
+ if (!hotk)
+ return;
+
+ if ((event & ~((u32) BR_UP)) < 16) {
+ hotk->brightness = (event & ~((u32) BR_UP));
+ } else if ((event & ~((u32) BR_DOWN)) < 16 ) {
+ hotk->brightness = (event & ~((u32) BR_DOWN));
+ }
+
+ acpi_bus_generate_event(hotk->device, event,
+ hotk->event_count[event % 128]++);
+
+ return;
+}
+
+/*
+ * This function is used to initialize the hotk with right values. In this
+ * method, we can make all the detection we want, and modify the hotk struct
+ */
+static int __init asus_hotk_get_info(void)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *model = NULL;
+ int bsts_result;
+ acpi_status status;
+
+ /*
+ * Get DSDT headers early enough to allow for differentiating between
+ * models, but late enough to allow acpi_bus_register_driver() to fail
+ * before doing anything ACPI-specific. Should we encounter a machine,
+ * which needs special handling (i.e. its hotkey device has a different
+ * HID), this bit will be moved. A global variable asus_info contains
+ * the DSDT header.
+ */
+ status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
+ if (ACPI_FAILURE(status))
+ printk(KERN_WARNING " Couldn't get the DSDT table header\n");
+ else
+ asus_info = (struct acpi_table_header *) dsdt.pointer;
+
+ /* We have to write 0 on init this far for all ASUS models */
+ if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+ printk(KERN_ERR " Hotkey initialization failed\n");
+ return -ENODEV;
+ }
+
+ /* This needs to be called for some laptops to init properly */
+ if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
+ printk(KERN_WARNING " Error calling BSTS\n");
+ else if (bsts_result)
+ printk(KERN_NOTICE " BSTS called, 0x%02x returned\n", bsts_result);
+
+ /* Samsung P30 has a device with a valid _HID whose INIT does not
+ * return anything. Catch this one and any similar here */
+ if (buffer.pointer == NULL) {
+ if (asus_info && /* Samsung P30 */
+ strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
+ hotk->model = P30;
+ printk(KERN_NOTICE " Samsung P30 detected, supported\n");
+ } else {
+ hotk->model = M2E;
+ printk(KERN_WARNING " no string returned by INIT\n");
+ printk(KERN_WARNING " trying default values, supply "
+ "the developers with your DSDT\n");
+ }
+ hotk->methods = &model_conf[hotk->model];
+ return AE_OK;
+ }
+
+ model = (union acpi_object *) buffer.pointer;
+ if (model->type == ACPI_TYPE_STRING) {
+ printk(KERN_NOTICE " %s model detected, ", model->string.pointer);
+ }
+
+ hotk->model = END_MODEL;
+ if (strncmp(model->string.pointer, "L3D", 3) == 0)
+ hotk->model = L3D;
+ else if (strncmp(model->string.pointer, "L3H", 3) == 0 ||
+ strncmp(model->string.pointer, "L2E", 3) == 0)
+ hotk->model = L3H;
+ else if (strncmp(model->string.pointer, "L3", 2) == 0 ||
+ strncmp(model->string.pointer, "L2B", 3) == 0)
+ hotk->model = L3C;
+ else if (strncmp(model->string.pointer, "L8L", 3) == 0)
+ hotk->model = L8L;
+ else if (strncmp(model->string.pointer, "L4R", 3) == 0)
+ hotk->model = L4R;
+ else if (strncmp(model->string.pointer, "M6N", 3) == 0)
+ hotk->model = M6N;
+ else if (strncmp(model->string.pointer, "M6R", 3) == 0)
+ hotk->model = M6R;
+ else if (strncmp(model->string.pointer, "M2N", 3) == 0 ||
+ strncmp(model->string.pointer, "M3N", 3) == 0 ||
+ strncmp(model->string.pointer, "M5N", 3) == 0 ||
+ strncmp(model->string.pointer, "M6N", 3) == 0 ||
+ strncmp(model->string.pointer, "S1N", 3) == 0 ||
+ strncmp(model->string.pointer, "S5N", 3) == 0 ||
+ strncmp(model->string.pointer, "W1N", 3) == 0)
+ hotk->model = xxN;
+ else if (strncmp(model->string.pointer, "M1", 2) == 0)
+ hotk->model = M1A;
+ else if (strncmp(model->string.pointer, "M2", 2) == 0 ||
+ strncmp(model->string.pointer, "L4E", 3) == 0)
+ hotk->model = M2E;
+ else if (strncmp(model->string.pointer, "L2", 2) == 0)
+ hotk->model = L2D;
+ else if (strncmp(model->string.pointer, "L8", 2) == 0)
+ hotk->model = S1x;
+ else if (strncmp(model->string.pointer, "D1", 2) == 0)
+ hotk->model = D1x;
+ else if (strncmp(model->string.pointer, "A1", 2) == 0)
+ hotk->model = A1x;
+ else if (strncmp(model->string.pointer, "A2", 2) == 0)
+ hotk->model = A2x;
+ else if (strncmp(model->string.pointer, "J1", 2) == 0)
+ hotk->model = S2x;
+ else if (strncmp(model->string.pointer, "L5", 2) == 0)
+ hotk->model = L5x;
+
+ if (hotk->model == END_MODEL) {
+ printk("unsupported, trying default values, supply the "
+ "developers with your DSDT\n");
+ hotk->model = M2E;
+ } else {
+ printk("supported\n");
+ }
+
+ hotk->methods = &model_conf[hotk->model];
+
+ /* Sort of per-model blacklist */
+ if (strncmp(model->string.pointer, "L2B", 3) == 0)
+ hotk->methods->lcd_status = NULL;
+ /* L2B is similar enough to L3C to use its settings, with this only
+ exception */
+ else if (strncmp(model->string.pointer, "S5N", 3) == 0 ||
+ strncmp(model->string.pointer, "M5N", 3) == 0)
+ hotk->methods->mt_mled = NULL;
+ /* S5N and M5N have no MLED */
+ else if (strncmp(model->string.pointer, "M2N", 3) == 0 ||
+ strncmp(model->string.pointer, "W1N", 3) == 0)
+ hotk->methods->mt_wled = "WLED";
+ /* M2N and W1N have a usable WLED */
+ else if (asus_info) {
+ if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
+ hotk->methods->mled_status = NULL;
+ /* S1300A reports L84F, but L1400B too, account for that */
+ }
+
+ acpi_os_free(model);
+
+ return AE_OK;
+}
+
+
+static int __init asus_hotk_check(void)
+{
+ int result = 0;
+
+ result = acpi_bus_get_status(hotk->device);
+ if (result)
+ return result;
+
+ if (hotk->device->status.present) {
+ result = asus_hotk_get_info();
+ } else {
+ printk(KERN_ERR " Hotkey device not present, aborting\n");
+ return -EINVAL;
+ }
+
+ return result;
+}
+
+
+static int __init asus_hotk_add(struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ int result;
+
+ if (!device)
+ return -EINVAL;
+
+ printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
+ ASUS_ACPI_VERSION);
+
+ hotk =
+ (struct asus_hotk *) kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+ if (!hotk)
+ return -ENOMEM;
+ memset(hotk, 0, sizeof(struct asus_hotk));
+
+ hotk->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
+ acpi_driver_data(device) = hotk;
+ hotk->device = device;
+
+
+ result = asus_hotk_check();
+ if (result)
+ goto end;
+
+ result = asus_hotk_add_fs(device);
+ if (result)
+ goto end;
+
+ /*
+ * We install the handler, it will receive the hotk in parameter, so, we
+ * could add other data to the hotk struct
+ */
+ status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify, hotk);
+ if (ACPI_FAILURE(status))
+ printk(KERN_ERR " Error installing notify handler\n");
+
+ /* For laptops without GPLV: init the hotk->brightness value */
+ if ((!hotk->methods->brightness_get) && (!hotk->methods->brightness_status) &&
+ (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
+ status = acpi_evaluate_object(NULL, hotk->methods->brightness_down,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ printk(KERN_WARNING " Error changing brightness\n");
+ else {
+ status = acpi_evaluate_object(NULL, hotk->methods->brightness_up,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ printk(KERN_WARNING " Strange, error changing"
+ " brightness\n");
+ }
+ }
+
+ end:
+ if (result) {
+ kfree(hotk);
+ }
+
+ return result;
+}
+
+
+static int asus_hotk_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+
+ if (!device || !acpi_driver_data(device))
+ return -EINVAL;
+
+ status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+ asus_hotk_notify);
+ if (ACPI_FAILURE(status))
+ printk(KERN_ERR "Asus ACPI: Error removing notify handler\n");
+
+ asus_hotk_remove_fs(device);
+
+ kfree(hotk);
+
+ return 0;
+}
+
+
+static int __init asus_acpi_init(void)
+{
+ int result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
+ if (!asus_proc_dir) {
+ printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
+ return -ENODEV;
+ }
+ asus_proc_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&asus_hotk_driver);
+ if (result < 1) {
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ remove_proc_entry(PROC_ASUS, acpi_root_dir);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+
+static void __exit asus_acpi_exit(void)
+{
+ acpi_bus_unregister_driver(&asus_hotk_driver);
+ remove_proc_entry(PROC_ASUS, acpi_root_dir);
+
+ acpi_os_free(asus_info);
+
+ return;
+}
+
+module_init(asus_acpi_init);
+module_exit(asus_acpi_exit);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
new file mode 100644
index 000000000000..c55feca9b7d5
--- /dev/null
+++ b/drivers/acpi/battery.c
@@ -0,0 +1,846 @@
+/*
+ * acpi_battery.c - ACPI Battery Driver ($Revision: 37 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define ACPI_BATTERY_VALUE_UNKNOWN 0xFFFFFFFF
+
+#define ACPI_BATTERY_FORMAT_BIF "NNNNNNNNNSSSS"
+#define ACPI_BATTERY_FORMAT_BST "NNNN"
+
+#define ACPI_BATTERY_COMPONENT 0x00040000
+#define ACPI_BATTERY_CLASS "battery"
+#define ACPI_BATTERY_HID "PNP0C0A"
+#define ACPI_BATTERY_DRIVER_NAME "ACPI Battery Driver"
+#define ACPI_BATTERY_DEVICE_NAME "Battery"
+#define ACPI_BATTERY_FILE_INFO "info"
+#define ACPI_BATTERY_FILE_STATUS "state"
+#define ACPI_BATTERY_FILE_ALARM "alarm"
+#define ACPI_BATTERY_NOTIFY_STATUS 0x80
+#define ACPI_BATTERY_NOTIFY_INFO 0x81
+#define ACPI_BATTERY_UNITS_WATTS "mW"
+#define ACPI_BATTERY_UNITS_AMPS "mA"
+
+
+#define _COMPONENT ACPI_BATTERY_COMPONENT
+ACPI_MODULE_NAME ("acpi_battery")
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION(ACPI_BATTERY_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int acpi_battery_add (struct acpi_device *device);
+static int acpi_battery_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_battery_driver = {
+ .name = ACPI_BATTERY_DRIVER_NAME,
+ .class = ACPI_BATTERY_CLASS,
+ .ids = ACPI_BATTERY_HID,
+ .ops = {
+ .add = acpi_battery_add,
+ .remove = acpi_battery_remove,
+ },
+};
+
+struct acpi_battery_status {
+ acpi_integer state;
+ acpi_integer present_rate;
+ acpi_integer remaining_capacity;
+ acpi_integer present_voltage;
+};
+
+struct acpi_battery_info {
+ acpi_integer power_unit;
+ acpi_integer design_capacity;
+ acpi_integer last_full_capacity;
+ acpi_integer battery_technology;
+ acpi_integer design_voltage;
+ acpi_integer design_capacity_warning;
+ acpi_integer design_capacity_low;
+ acpi_integer battery_capacity_granularity_1;
+ acpi_integer battery_capacity_granularity_2;
+ acpi_string model_number;
+ acpi_string serial_number;
+ acpi_string battery_type;
+ acpi_string oem_info;
+};
+
+struct acpi_battery_flags {
+ u8 present:1; /* Bay occupied? */
+ u8 power_unit:1; /* 0=watts, 1=apms */
+ u8 alarm:1; /* _BTP present? */
+ u8 reserved:5;
+};
+
+struct acpi_battery_trips {
+ unsigned long warning;
+ unsigned long low;
+};
+
+struct acpi_battery {
+ acpi_handle handle;
+ struct acpi_battery_flags flags;
+ struct acpi_battery_trips trips;
+ unsigned long alarm;
+ struct acpi_battery_info *info;
+};
+
+
+/* --------------------------------------------------------------------------
+ Battery Management
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_battery_get_info (
+ struct acpi_battery *battery,
+ struct acpi_battery_info **bif)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_buffer format = {sizeof(ACPI_BATTERY_FORMAT_BIF),
+ ACPI_BATTERY_FORMAT_BIF};
+ struct acpi_buffer data = {0, NULL};
+ union acpi_object *package = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_get_info");
+
+ if (!battery || !bif)
+ return_VALUE(-EINVAL);
+
+ /* Evalute _BIF */
+
+ status = acpi_evaluate_object(battery->handle, "_BIF", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BIF\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ package = (union acpi_object *) buffer.pointer;
+
+ /* Extract Package Data */
+
+ status = acpi_extract_package(package, &format, &data);
+ if (status != AE_BUFFER_OVERFLOW) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ data.pointer = kmalloc(data.length, GFP_KERNEL);
+ if (!data.pointer) {
+ result = -ENOMEM;
+ goto end;
+ }
+ memset(data.pointer, 0, data.length);
+
+ status = acpi_extract_package(package, &format, &data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
+ kfree(data.pointer);
+ result = -ENODEV;
+ goto end;
+ }
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ if (!result)
+ (*bif) = (struct acpi_battery_info *) data.pointer;
+
+ return_VALUE(result);
+}
+
+static int
+acpi_battery_get_status (
+ struct acpi_battery *battery,
+ struct acpi_battery_status **bst)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_buffer format = {sizeof(ACPI_BATTERY_FORMAT_BST),
+ ACPI_BATTERY_FORMAT_BST};
+ struct acpi_buffer data = {0, NULL};
+ union acpi_object *package = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_get_status");
+
+ if (!battery || !bst)
+ return_VALUE(-EINVAL);
+
+ /* Evalute _BST */
+
+ status = acpi_evaluate_object(battery->handle, "_BST", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BST\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ package = (union acpi_object *) buffer.pointer;
+
+ /* Extract Package Data */
+
+ status = acpi_extract_package(package, &format, &data);
+ if (status != AE_BUFFER_OVERFLOW) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ data.pointer = kmalloc(data.length, GFP_KERNEL);
+ if (!data.pointer) {
+ result = -ENOMEM;
+ goto end;
+ }
+ memset(data.pointer, 0, data.length);
+
+ status = acpi_extract_package(package, &format, &data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
+ kfree(data.pointer);
+ result = -ENODEV;
+ goto end;
+ }
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ if (!result)
+ (*bst) = (struct acpi_battery_status *) data.pointer;
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_battery_set_alarm (
+ struct acpi_battery *battery,
+ unsigned long alarm)
+{
+ acpi_status status = 0;
+ union acpi_object arg0 = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list arg_list = {1, &arg0};
+
+ ACPI_FUNCTION_TRACE("acpi_battery_set_alarm");
+
+ if (!battery)
+ return_VALUE(-EINVAL);
+
+ if (!battery->flags.alarm)
+ return_VALUE(-ENODEV);
+
+ arg0.integer.value = alarm;
+
+ status = acpi_evaluate_object(battery->handle, "_BTP", &arg_list, NULL);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Alarm set to %d\n", (u32) alarm));
+
+ battery->alarm = alarm;
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_battery_check (
+ struct acpi_battery *battery)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ acpi_handle handle = NULL;
+ struct acpi_device *device = NULL;
+ struct acpi_battery_info *bif = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_check");
+
+ if (!battery)
+ return_VALUE(-EINVAL);
+
+ result = acpi_bus_get_device(battery->handle, &device);
+ if (result)
+ return_VALUE(result);
+
+ result = acpi_bus_get_status(device);
+ if (result)
+ return_VALUE(result);
+
+ /* Insertion? */
+
+ if (!battery->flags.present && device->status.battery_present) {
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery inserted\n"));
+
+ /* Evalute _BIF to get certain static information */
+
+ result = acpi_battery_get_info(battery, &bif);
+ if (result)
+ return_VALUE(result);
+
+ battery->flags.power_unit = bif->power_unit;
+ battery->trips.warning = bif->design_capacity_warning;
+ battery->trips.low = bif->design_capacity_low;
+ kfree(bif);
+
+ /* See if alarms are supported, and if so, set default */
+
+ status = acpi_get_handle(battery->handle, "_BTP", &handle);
+ if (ACPI_SUCCESS(status)) {
+ battery->flags.alarm = 1;
+ acpi_battery_set_alarm(battery, battery->trips.warning);
+ }
+ }
+
+ /* Removal? */
+
+ else if (battery->flags.present && !device->status.battery_present) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Battery removed\n"));
+ }
+
+ battery->flags.present = device->status.battery_present;
+
+ return_VALUE(result);
+}
+
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_battery_dir;
+static int acpi_battery_read_info(struct seq_file *seq, void *offset)
+{
+ int result = 0;
+ struct acpi_battery *battery = (struct acpi_battery *) seq->private;
+ struct acpi_battery_info *bif = NULL;
+ char *units = "?";
+
+ ACPI_FUNCTION_TRACE("acpi_battery_read_info");
+
+ if (!battery)
+ goto end;
+
+ if (battery->flags.present)
+ seq_printf(seq, "present: yes\n");
+ else {
+ seq_printf(seq, "present: no\n");
+ goto end;
+ }
+
+ /* Battery Info (_BIF) */
+
+ result = acpi_battery_get_info(battery, &bif);
+ if (result || !bif) {
+ seq_printf(seq, "ERROR: Unable to read battery information\n");
+ goto end;
+ }
+
+ units = bif->power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+
+ if (bif->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ seq_printf(seq, "design capacity: unknown\n");
+ else
+ seq_printf(seq, "design capacity: %d %sh\n",
+ (u32) bif->design_capacity, units);
+
+ if (bif->last_full_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ seq_printf(seq, "last full capacity: unknown\n");
+ else
+ seq_printf(seq, "last full capacity: %d %sh\n",
+ (u32) bif->last_full_capacity, units);
+
+ switch ((u32) bif->battery_technology) {
+ case 0:
+ seq_printf(seq, "battery technology: non-rechargeable\n");
+ break;
+ case 1:
+ seq_printf(seq, "battery technology: rechargeable\n");
+ break;
+ default:
+ seq_printf(seq, "battery technology: unknown\n");
+ break;
+ }
+
+ if (bif->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+ seq_printf(seq, "design voltage: unknown\n");
+ else
+ seq_printf(seq, "design voltage: %d mV\n",
+ (u32) bif->design_voltage);
+
+ seq_printf(seq, "design capacity warning: %d %sh\n",
+ (u32) bif->design_capacity_warning, units);
+ seq_printf(seq, "design capacity low: %d %sh\n",
+ (u32) bif->design_capacity_low, units);
+ seq_printf(seq, "capacity granularity 1: %d %sh\n",
+ (u32) bif->battery_capacity_granularity_1, units);
+ seq_printf(seq, "capacity granularity 2: %d %sh\n",
+ (u32) bif->battery_capacity_granularity_2, units);
+ seq_printf(seq, "model number: %s\n",
+ bif->model_number);
+ seq_printf(seq, "serial number: %s\n",
+ bif->serial_number);
+ seq_printf(seq, "battery type: %s\n",
+ bif->battery_type);
+ seq_printf(seq, "OEM info: %s\n",
+ bif->oem_info);
+
+end:
+ kfree(bif);
+
+ return_VALUE(0);
+}
+
+static int acpi_battery_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_info, PDE(inode)->data);
+}
+
+
+static int
+acpi_battery_read_state (struct seq_file *seq, void *offset)
+{
+ int result = 0;
+ struct acpi_battery *battery = (struct acpi_battery *) seq->private;
+ struct acpi_battery_status *bst = NULL;
+ char *units = "?";
+
+ ACPI_FUNCTION_TRACE("acpi_battery_read_state");
+
+ if (!battery)
+ goto end;
+
+ if (battery->flags.present)
+ seq_printf(seq, "present: yes\n");
+ else {
+ seq_printf(seq, "present: no\n");
+ goto end;
+ }
+
+ /* Battery Units */
+
+ units = battery->flags.power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+
+ /* Battery Status (_BST) */
+
+ result = acpi_battery_get_status(battery, &bst);
+ if (result || !bst) {
+ seq_printf(seq, "ERROR: Unable to read battery status\n");
+ goto end;
+ }
+
+ if (!(bst->state & 0x04))
+ seq_printf(seq, "capacity state: ok\n");
+ else
+ seq_printf(seq, "capacity state: critical\n");
+
+ if ((bst->state & 0x01) && (bst->state & 0x02)){
+ seq_printf(seq, "charging state: charging/discharging\n");
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Battery Charging and Discharging?\n"));
+ }
+ else if (bst->state & 0x01)
+ seq_printf(seq, "charging state: discharging\n");
+ else if (bst->state & 0x02)
+ seq_printf(seq, "charging state: charging\n");
+ else {
+ seq_printf(seq, "charging state: charged\n");
+ }
+
+ if (bst->present_rate == ACPI_BATTERY_VALUE_UNKNOWN)
+ seq_printf(seq, "present rate: unknown\n");
+ else
+ seq_printf(seq, "present rate: %d %s\n",
+ (u32) bst->present_rate, units);
+
+ if (bst->remaining_capacity == ACPI_BATTERY_VALUE_UNKNOWN)
+ seq_printf(seq, "remaining capacity: unknown\n");
+ else
+ seq_printf(seq, "remaining capacity: %d %sh\n",
+ (u32) bst->remaining_capacity, units);
+
+ if (bst->present_voltage == ACPI_BATTERY_VALUE_UNKNOWN)
+ seq_printf(seq, "present voltage: unknown\n");
+ else
+ seq_printf(seq, "present voltage: %d mV\n",
+ (u32) bst->present_voltage);
+
+end:
+ kfree(bst);
+
+ return_VALUE(0);
+}
+
+static int acpi_battery_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_state, PDE(inode)->data);
+}
+
+
+static int
+acpi_battery_read_alarm (struct seq_file *seq, void *offset)
+{
+ struct acpi_battery *battery = (struct acpi_battery *) seq->private;
+ char *units = "?";
+
+ ACPI_FUNCTION_TRACE("acpi_battery_read_alarm");
+
+ if (!battery)
+ goto end;
+
+ if (!battery->flags.present) {
+ seq_printf(seq, "present: no\n");
+ goto end;
+ }
+
+ /* Battery Units */
+
+ units = battery->flags.power_unit ? ACPI_BATTERY_UNITS_AMPS : ACPI_BATTERY_UNITS_WATTS;
+
+ /* Battery Alarm */
+
+ seq_printf(seq, "alarm: ");
+ if (!battery->alarm)
+ seq_printf(seq, "unsupported\n");
+ else
+ seq_printf(seq, "%d %sh\n", (u32) battery->alarm, units);
+
+end:
+ return_VALUE(0);
+}
+
+
+static ssize_t
+acpi_battery_write_alarm (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ int result = 0;
+ char alarm_string[12] = {'\0'};
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_battery *battery = (struct acpi_battery *)m->private;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_write_alarm");
+
+ if (!battery || (count > sizeof(alarm_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (!battery->flags.present)
+ return_VALUE(-ENODEV);
+
+ if (copy_from_user(alarm_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ alarm_string[count] = '\0';
+
+ result = acpi_battery_set_alarm(battery,
+ simple_strtoul(alarm_string, NULL, 0));
+ if (result)
+ return_VALUE(result);
+
+ return_VALUE(count);
+}
+
+static int acpi_battery_alarm_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_battery_read_alarm, PDE(inode)->data);
+}
+
+static struct file_operations acpi_battery_info_ops = {
+ .open = acpi_battery_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct file_operations acpi_battery_state_ops = {
+ .open = acpi_battery_state_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static struct file_operations acpi_battery_alarm_ops = {
+ .open = acpi_battery_alarm_open_fs,
+ .read = seq_read,
+ .write = acpi_battery_write_alarm,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int
+acpi_battery_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_add_fs");
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_battery_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ acpi_device_dir(device)->owner = THIS_MODULE;
+ }
+
+ /* 'info' [R] */
+ entry = create_proc_entry(ACPI_BATTERY_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_BATTERY_FILE_INFO));
+ else {
+ entry->proc_fops = &acpi_battery_info_ops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'status' [R] */
+ entry = create_proc_entry(ACPI_BATTERY_FILE_STATUS,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_BATTERY_FILE_STATUS));
+ else {
+ entry->proc_fops = &acpi_battery_state_ops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'alarm' [R/W] */
+ entry = create_proc_entry(ACPI_BATTERY_FILE_ALARM,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_BATTERY_FILE_ALARM));
+ else {
+ entry->proc_fops = &acpi_battery_alarm_ops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_battery_remove_fs (
+ struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_battery_remove_fs");
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_BATTERY_FILE_ALARM,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_BATTERY_FILE_STATUS,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_BATTERY_FILE_INFO,
+ acpi_device_dir(device));
+
+ remove_proc_entry(acpi_device_bid(device), acpi_battery_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static void
+acpi_battery_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_battery *battery = (struct acpi_battery *) data;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_notify");
+
+ if (!battery)
+ return_VOID;
+
+ if (acpi_bus_get_device(handle, &device))
+ return_VOID;
+
+ switch (event) {
+ case ACPI_BATTERY_NOTIFY_STATUS:
+ case ACPI_BATTERY_NOTIFY_INFO:
+ acpi_battery_check(battery);
+ acpi_bus_generate_event(device, event, battery->flags.present);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+
+static int
+acpi_battery_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_battery *battery = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ battery = kmalloc(sizeof(struct acpi_battery), GFP_KERNEL);
+ if (!battery)
+ return_VALUE(-ENOMEM);
+ memset(battery, 0, sizeof(struct acpi_battery));
+
+ battery->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS);
+ acpi_driver_data(device) = battery;
+
+ result = acpi_battery_check(battery);
+ if (result)
+ goto end;
+
+ result = acpi_battery_add_fs(device);
+ if (result)
+ goto end;
+
+ status = acpi_install_notify_handler(battery->handle,
+ ACPI_DEVICE_NOTIFY, acpi_battery_notify, battery);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n",
+ ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device),
+ device->status.battery_present?"present":"absent");
+
+end:
+ if (result) {
+ acpi_battery_remove_fs(device);
+ kfree(battery);
+ }
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_battery_remove (
+ struct acpi_device *device,
+ int type)
+{
+ acpi_status status = 0;
+ struct acpi_battery *battery = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ battery = (struct acpi_battery *) acpi_driver_data(device);
+
+ status = acpi_remove_notify_handler(battery->handle,
+ ACPI_DEVICE_NOTIFY, acpi_battery_notify);
+ if (ACPI_FAILURE(status))
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+
+ acpi_battery_remove_fs(device);
+
+ kfree(battery);
+
+ return_VALUE(0);
+}
+
+
+static int __init
+acpi_battery_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_battery_init");
+
+ acpi_battery_dir = proc_mkdir(ACPI_BATTERY_CLASS, acpi_root_dir);
+ if (!acpi_battery_dir)
+ return_VALUE(-ENODEV);
+ acpi_battery_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&acpi_battery_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+
+static void __exit
+acpi_battery_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_battery_exit");
+
+ acpi_bus_unregister_driver(&acpi_battery_driver);
+
+ remove_proc_entry(ACPI_BATTERY_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+
+
+module_init(acpi_battery_init);
+module_exit(acpi_battery_exit);
diff --git a/drivers/acpi/blacklist.c b/drivers/acpi/blacklist.c
new file mode 100644
index 000000000000..4c010e7f11b8
--- /dev/null
+++ b/drivers/acpi/blacklist.c
@@ -0,0 +1,169 @@
+/*
+ * blacklist.c
+ *
+ * Check to see if the given machine has a known bad ACPI BIOS
+ * or if the BIOS is too old.
+ *
+ * Copyright (C) 2004 Len Brown <len.brown@intel.com>
+ * Copyright (C) 2002 Andy Grover <andrew.grover@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/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <linux/dmi.h>
+
+enum acpi_blacklist_predicates
+{
+ all_versions,
+ less_than_or_equal,
+ equal,
+ greater_than_or_equal,
+};
+
+struct acpi_blacklist_item
+{
+ char oem_id[7];
+ char oem_table_id[9];
+ u32 oem_revision;
+ acpi_table_type table;
+ enum acpi_blacklist_predicates oem_revision_predicate;
+ char *reason;
+ u32 is_critical_error;
+};
+
+/*
+ * POLICY: If *anything* doesn't work, put it on the blacklist.
+ * If they are critical errors, mark it critical, and abort driver load.
+ */
+static struct acpi_blacklist_item acpi_blacklist[] __initdata =
+{
+ /* Compaq Presario 1700 */
+ {"PTLTD ", " DSDT ", 0x06040000, ACPI_DSDT, less_than_or_equal, "Multiple problems", 1},
+ /* Sony FX120, FX140, FX150? */
+ {"SONY ", "U0 ", 0x20010313, ACPI_DSDT, less_than_or_equal, "ACPI driver problem", 1},
+ /* Compaq Presario 800, Insyde BIOS */
+ {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1},
+ /* IBM 600E - _ADR should return 7, but it returns 1 */
+ {"IBM ", "TP600E ", 0x00000105, ACPI_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
+ {"ASUS\0\0", "P2B-S ", 0, ACPI_DSDT, all_versions, "Bogus PCI routing", 1},
+
+ {""}
+};
+
+
+#if CONFIG_ACPI_BLACKLIST_YEAR
+
+static int __init
+blacklist_by_year(void)
+{
+ int year;
+ char *s = dmi_get_system_info(DMI_BIOS_DATE);
+
+ if (!s)
+ return 0;
+ if (!*s)
+ return 0;
+
+ s = strrchr(s, '/');
+ if (!s)
+ return 0;
+
+ s += 1;
+
+ year = simple_strtoul(s,NULL,0);
+
+ if (year < 100) { /* 2-digit year */
+ year += 1900;
+ if (year < 1996) /* no dates < spec 1.0 */
+ year += 100;
+ }
+
+ if (year < CONFIG_ACPI_BLACKLIST_YEAR) {
+ printk(KERN_ERR PREFIX "BIOS age (%d) fails cutoff (%d), "
+ "acpi=force is required to enable ACPI\n",
+ year, CONFIG_ACPI_BLACKLIST_YEAR);
+ return 1;
+ }
+ return 0;
+}
+#else
+static inline int blacklist_by_year(void) { return 0; }
+#endif
+
+int __init
+acpi_blacklisted(void)
+{
+ int i = 0;
+ int blacklisted = 0;
+ struct acpi_table_header *table_header;
+
+ while (acpi_blacklist[i].oem_id[0] != '\0')
+ {
+ if (acpi_get_table_header_early(acpi_blacklist[i].table, &table_header)) {
+ i++;
+ continue;
+ }
+
+ if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+ i++;
+ continue;
+ }
+
+ if (strncmp(acpi_blacklist[i].oem_table_id, table_header->oem_table_id, 8)) {
+ i++;
+ continue;
+ }
+
+ if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
+ || (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal
+ && table_header->oem_revision <= acpi_blacklist[i].oem_revision)
+ || (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal
+ && table_header->oem_revision >= acpi_blacklist[i].oem_revision)
+ || (acpi_blacklist[i].oem_revision_predicate == equal
+ && table_header->oem_revision == acpi_blacklist[i].oem_revision)) {
+
+ printk(KERN_ERR PREFIX "Vendor \"%6.6s\" System \"%8.8s\" "
+ "Revision 0x%x has a known ACPI BIOS problem.\n",
+ acpi_blacklist[i].oem_id,
+ acpi_blacklist[i].oem_table_id,
+ acpi_blacklist[i].oem_revision);
+
+ printk(KERN_ERR PREFIX "Reason: %s. This is a %s error\n",
+ acpi_blacklist[i].reason,
+ (acpi_blacklist[i].is_critical_error ? "non-recoverable" : "recoverable"));
+
+ blacklisted = acpi_blacklist[i].is_critical_error;
+ break;
+ }
+ else {
+ i++;
+ }
+ }
+
+ blacklisted += blacklist_by_year();
+
+ return blacklisted;
+}
+
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
new file mode 100644
index 000000000000..4edff1738579
--- /dev/null
+++ b/drivers/acpi/bus.c
@@ -0,0 +1,775 @@
+/*
+ * acpi_bus.c - ACPI Bus Driver ($Revision: 80 $)
+ *
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+#include <linux/pm.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+#ifdef CONFIG_X86
+#include <asm/mpspec.h>
+#endif
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_BUS_COMPONENT
+ACPI_MODULE_NAME ("acpi_bus")
+
+#ifdef CONFIG_X86
+extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
+#endif
+
+FADT_DESCRIPTOR acpi_fadt;
+EXPORT_SYMBOL(acpi_fadt);
+
+struct acpi_device *acpi_root;
+struct proc_dir_entry *acpi_root_dir;
+EXPORT_SYMBOL(acpi_root_dir);
+
+#define STRUCT_TO_INT(s) (*((int*)&s))
+
+/* --------------------------------------------------------------------------
+ Device Management
+ -------------------------------------------------------------------------- */
+
+int
+acpi_bus_get_device (
+ acpi_handle handle,
+ struct acpi_device **device)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_get_device");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ /* TBD: Support fixed-feature devices */
+
+ status = acpi_get_data(handle, acpi_bus_data_handler, (void**) device);
+ if (ACPI_FAILURE(status) || !*device) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "No context for object [%p]\n",
+ handle));
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_bus_get_device);
+
+int
+acpi_bus_get_status (
+ struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ unsigned long sta = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_get_status");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ /*
+ * Evaluate _STA if present.
+ */
+ if (device->flags.dynamic_status) {
+ status = acpi_evaluate_integer(device->handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+ STRUCT_TO_INT(device->status) = (int) sta;
+ }
+
+ /*
+ * Otherwise we assume the status of our parent (unless we don't
+ * have one, in which case status is implied).
+ */
+ else if (device->parent)
+ device->status = device->parent->status;
+ else
+ STRUCT_TO_INT(device->status) = 0x0F;
+
+ if (device->status.functional && !device->status.present) {
+ printk(KERN_WARNING PREFIX "Device [%s] status [%08x]: "
+ "functional but not present; setting present\n",
+ device->pnp.bus_id,
+ (u32) STRUCT_TO_INT(device->status));
+ device->status.present = 1;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n",
+ device->pnp.bus_id, (u32) STRUCT_TO_INT(device->status)));
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_bus_get_status);
+
+
+/* --------------------------------------------------------------------------
+ Power Management
+ -------------------------------------------------------------------------- */
+
+int
+acpi_bus_get_power (
+ acpi_handle handle,
+ int *state)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_device *device = NULL;
+ unsigned long psc = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_get_power");
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return_VALUE(result);
+
+ *state = ACPI_STATE_UNKNOWN;
+
+ if (!device->flags.power_manageable) {
+ /* TBD: Non-recursive algorithm for walking up hierarchy */
+ if (device->parent)
+ *state = device->parent->power.state;
+ else
+ *state = ACPI_STATE_D0;
+ }
+ else {
+ /*
+ * Get the device's power state either directly (via _PSC) or
+ * indirectly (via power resources).
+ */
+ if (device->power.flags.explicit_get) {
+ status = acpi_evaluate_integer(device->handle, "_PSC",
+ NULL, &psc);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+ device->power.state = (int) psc;
+ }
+ else if (device->power.flags.power_resources) {
+ result = acpi_power_get_inferred_state(device);
+ if (result)
+ return_VALUE(result);
+ }
+
+ *state = device->power.state;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n",
+ device->pnp.bus_id, device->power.state));
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_bus_get_power);
+
+
+int
+acpi_bus_set_power (
+ acpi_handle handle,
+ int state)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_device *device = NULL;
+ char object_name[5] = {'_','P','S','0'+state,'\0'};
+
+ ACPI_FUNCTION_TRACE("acpi_bus_set_power");
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return_VALUE(result);
+
+ if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
+ return_VALUE(-EINVAL);
+
+ /* Make sure this is a valid target state */
+
+ if (!device->flags.power_manageable) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n"));
+ return_VALUE(-ENODEV);
+ }
+ if (state == device->power.state) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state));
+ return_VALUE(0);
+ }
+ if (!device->power.states[state].flags.valid) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device does not support D%d\n", state));
+ return_VALUE(-ENODEV);
+ }
+ if (device->parent && (state < device->parent->power.state)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Cannot set device to a higher-powered state than parent\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ /*
+ * Transition Power
+ * ----------------
+ * On transitions to a high-powered state we first apply power (via
+ * power resources) then evalute _PSx. Conversly for transitions to
+ * a lower-powered state.
+ */
+ if (state < device->power.state) {
+ if (device->power.flags.power_resources) {
+ result = acpi_power_transition(device, state);
+ if (result)
+ goto end;
+ }
+ if (device->power.states[state].flags.explicit_set) {
+ status = acpi_evaluate_object(device->handle,
+ object_name, NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ result = -ENODEV;
+ goto end;
+ }
+ }
+ }
+ else {
+ if (device->power.states[state].flags.explicit_set) {
+ status = acpi_evaluate_object(device->handle,
+ object_name, NULL, NULL);
+ if (ACPI_FAILURE(status)) {
+ result = -ENODEV;
+ goto end;
+ }
+ }
+ if (device->power.flags.power_resources) {
+ result = acpi_power_transition(device, state);
+ if (result)
+ goto end;
+ }
+ }
+
+end:
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error transitioning device [%s] to D%d\n",
+ device->pnp.bus_id, state));
+ else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] transitioned to D%d\n",
+ device->pnp.bus_id, state));
+
+ return_VALUE(result);
+}
+EXPORT_SYMBOL(acpi_bus_set_power);
+
+
+
+/* --------------------------------------------------------------------------
+ Event Management
+ -------------------------------------------------------------------------- */
+
+static DEFINE_SPINLOCK(acpi_bus_event_lock);
+
+LIST_HEAD(acpi_bus_event_list);
+DECLARE_WAIT_QUEUE_HEAD(acpi_bus_event_queue);
+
+extern int event_is_open;
+
+int
+acpi_bus_generate_event (
+ struct acpi_device *device,
+ u8 type,
+ int data)
+{
+ struct acpi_bus_event *event = NULL;
+ unsigned long flags = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_generate_event");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ /* drop event on the floor if no one's listening */
+ if (!event_is_open)
+ return_VALUE(0);
+
+ event = kmalloc(sizeof(struct acpi_bus_event), GFP_ATOMIC);
+ if (!event)
+ return_VALUE(-ENOMEM);
+
+ strcpy(event->device_class, device->pnp.device_class);
+ strcpy(event->bus_id, device->pnp.bus_id);
+ event->type = type;
+ event->data = data;
+
+ spin_lock_irqsave(&acpi_bus_event_lock, flags);
+ list_add_tail(&event->node, &acpi_bus_event_list);
+ spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
+
+ wake_up_interruptible(&acpi_bus_event_queue);
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_bus_generate_event);
+
+int
+acpi_bus_receive_event (
+ struct acpi_bus_event *event)
+{
+ unsigned long flags = 0;
+ struct acpi_bus_event *entry = NULL;
+
+ DECLARE_WAITQUEUE(wait, current);
+
+ ACPI_FUNCTION_TRACE("acpi_bus_receive_event");
+
+ if (!event)
+ return_VALUE(-EINVAL);
+
+ if (list_empty(&acpi_bus_event_list)) {
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&acpi_bus_event_queue, &wait);
+
+ if (list_empty(&acpi_bus_event_list))
+ schedule();
+
+ remove_wait_queue(&acpi_bus_event_queue, &wait);
+ set_current_state(TASK_RUNNING);
+
+ if (signal_pending(current))
+ return_VALUE(-ERESTARTSYS);
+ }
+
+ spin_lock_irqsave(&acpi_bus_event_lock, flags);
+ entry = list_entry(acpi_bus_event_list.next, struct acpi_bus_event, node);
+ if (entry)
+ list_del(&entry->node);
+ spin_unlock_irqrestore(&acpi_bus_event_lock, flags);
+
+ if (!entry)
+ return_VALUE(-ENODEV);
+
+ memcpy(event, entry, sizeof(struct acpi_bus_event));
+
+ kfree(entry);
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_bus_receive_event);
+
+
+/* --------------------------------------------------------------------------
+ Notification Handling
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_bus_check_device (
+ struct acpi_device *device,
+ int *status_changed)
+{
+ acpi_status status = 0;
+ struct acpi_device_status old_status;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_check_device");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ if (status_changed)
+ *status_changed = 0;
+
+ old_status = device->status;
+
+ /*
+ * Make sure this device's parent is present before we go about
+ * messing with the device.
+ */
+ if (device->parent && !device->parent->status.present) {
+ device->status = device->parent->status;
+ if (STRUCT_TO_INT(old_status) != STRUCT_TO_INT(device->status)) {
+ if (status_changed)
+ *status_changed = 1;
+ }
+ return_VALUE(0);
+ }
+
+ status = acpi_bus_get_status(device);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ if (STRUCT_TO_INT(old_status) == STRUCT_TO_INT(device->status))
+ return_VALUE(0);
+
+ if (status_changed)
+ *status_changed = 1;
+
+ /*
+ * Device Insertion/Removal
+ */
+ if ((device->status.present) && !(old_status.present)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device insertion detected\n"));
+ /* TBD: Handle device insertion */
+ }
+ else if (!(device->status.present) && (old_status.present)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device removal detected\n"));
+ /* TBD: Handle device removal */
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_bus_check_scope (
+ struct acpi_device *device)
+{
+ int result = 0;
+ int status_changed = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_check_scope");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ /* Status Change? */
+ result = acpi_bus_check_device(device, &status_changed);
+ if (result)
+ return_VALUE(result);
+
+ if (!status_changed)
+ return_VALUE(0);
+
+ /*
+ * TBD: Enumerate child devices within this device's scope and
+ * run acpi_bus_check_device()'s on them.
+ */
+
+ return_VALUE(0);
+}
+
+
+/**
+ * acpi_bus_notify
+ * ---------------
+ * Callback for all 'system-level' device notifications (values 0x00-0x7F).
+ */
+static void
+acpi_bus_notify (
+ acpi_handle handle,
+ u32 type,
+ void *data)
+{
+ int result = 0;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_notify");
+
+ if (acpi_bus_get_device(handle, &device))
+ return_VOID;
+
+ switch (type) {
+
+ case ACPI_NOTIFY_BUS_CHECK:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received BUS CHECK notification for device [%s]\n",
+ device->pnp.bus_id));
+ result = acpi_bus_check_scope(device);
+ /*
+ * TBD: We'll need to outsource certain events to non-ACPI
+ * drivers via the device manager (device.c).
+ */
+ break;
+
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received DEVICE CHECK notification for device [%s]\n",
+ device->pnp.bus_id));
+ result = acpi_bus_check_device(device, NULL);
+ /*
+ * TBD: We'll need to outsource certain events to non-ACPI
+ * drivers via the device manager (device.c).
+ */
+ break;
+
+ case ACPI_NOTIFY_DEVICE_WAKE:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received DEVICE WAKE notification for device [%s]\n",
+ device->pnp.bus_id));
+ /* TBD */
+ break;
+
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received EJECT REQUEST notification for device [%s]\n",
+ device->pnp.bus_id));
+ /* TBD */
+ break;
+
+ case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received DEVICE CHECK LIGHT notification for device [%s]\n",
+ device->pnp.bus_id));
+ /* TBD: Exactly what does 'light' mean? */
+ break;
+
+ case ACPI_NOTIFY_FREQUENCY_MISMATCH:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received FREQUENCY MISMATCH notification for device [%s]\n",
+ device->pnp.bus_id));
+ /* TBD */
+ break;
+
+ case ACPI_NOTIFY_BUS_MODE_MISMATCH:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received BUS MODE MISMATCH notification for device [%s]\n",
+ device->pnp.bus_id));
+ /* TBD */
+ break;
+
+ case ACPI_NOTIFY_POWER_FAULT:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received POWER FAULT notification for device [%s]\n",
+ device->pnp.bus_id));
+ /* TBD */
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Received unknown/unsupported notification [%08x]\n",
+ type));
+ break;
+ }
+
+ return_VOID;
+}
+
+/* --------------------------------------------------------------------------
+ Initialization/Cleanup
+ -------------------------------------------------------------------------- */
+
+static int __init
+acpi_bus_init_irq (void)
+{
+ acpi_status status = AE_OK;
+ union acpi_object arg = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list arg_list = {1, &arg};
+ char *message = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_init_irq");
+
+ /*
+ * Let the system know what interrupt model we are using by
+ * evaluating the \_PIC object, if exists.
+ */
+
+ switch (acpi_irq_model) {
+ case ACPI_IRQ_MODEL_PIC:
+ message = "PIC";
+ break;
+ case ACPI_IRQ_MODEL_IOAPIC:
+ message = "IOAPIC";
+ break;
+ case ACPI_IRQ_MODEL_IOSAPIC:
+ message = "IOSAPIC";
+ break;
+ default:
+ printk(KERN_WARNING PREFIX "Unknown interrupt routing model\n");
+ return_VALUE(-ENODEV);
+ }
+
+ printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
+
+ arg.integer.value = acpi_irq_model;
+
+ status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
+ if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+
+void __init
+acpi_early_init (void)
+{
+ acpi_status status = AE_OK;
+ struct acpi_buffer buffer = {sizeof(acpi_fadt), &acpi_fadt};
+
+ ACPI_FUNCTION_TRACE("acpi_early_init");
+
+ if (acpi_disabled)
+ return_VOID;
+
+ /* enable workarounds, unless strict ACPI spec. compliance */
+ if (!acpi_strict)
+ acpi_gbl_enable_interpreter_slack = TRUE;
+
+ status = acpi_initialize_subsystem();
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to initialize the ACPI Interpreter\n");
+ goto error0;
+ }
+
+ status = acpi_load_tables();
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to load the System Description Tables\n");
+ goto error0;
+ }
+
+ /*
+ * Get a separate copy of the FADT for use by other drivers.
+ */
+ status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to get the FADT\n");
+ goto error0;
+ }
+
+#ifdef CONFIG_X86
+ if (!acpi_ioapic) {
+ extern acpi_interrupt_flags acpi_sci_flags;
+
+ /* compatible (0) means level (3) */
+ if (acpi_sci_flags.trigger == 0)
+ acpi_sci_flags.trigger = 3;
+
+ /* Set PIC-mode SCI trigger type */
+ acpi_pic_sci_set_trigger(acpi_fadt.sci_int, acpi_sci_flags.trigger);
+ } else {
+ extern int acpi_sci_override_gsi;
+ /*
+ * now that acpi_fadt is initialized,
+ * update it with result from INT_SRC_OVR parsing
+ */
+ acpi_fadt.sci_int = acpi_sci_override_gsi;
+ }
+#endif
+
+ status = acpi_enable_subsystem(~(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE));
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
+ goto error0;
+ }
+
+ return_VOID;
+
+error0:
+ disable_acpi();
+ return_VOID;
+}
+
+static int __init
+acpi_bus_init (void)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ extern acpi_status acpi_os_initialize1(void);
+
+ ACPI_FUNCTION_TRACE("acpi_bus_init");
+
+ status = acpi_os_initialize1();
+
+ status = acpi_enable_subsystem(ACPI_NO_HARDWARE_INIT | ACPI_NO_ACPI_ENABLE);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to start the ACPI Interpreter\n");
+ goto error1;
+ }
+
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to initialize ACPI OS objects\n");
+ goto error1;
+ }
+#ifdef CONFIG_ACPI_EC
+ /*
+ * ACPI 2.0 requires the EC driver to be loaded and work before
+ * the EC device is found in the namespace (i.e. before acpi_initialize_objects()
+ * is called).
+ *
+ * This is accomplished by looking for the ECDT table, and getting
+ * the EC parameters out of that.
+ */
+ status = acpi_ec_ecdt_probe();
+ /* Ignore result. Not having an ECDT is not fatal. */
+#endif
+
+ status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
+ goto error1;
+ }
+
+ printk(KERN_INFO PREFIX "Interpreter enabled\n");
+
+ /*
+ * Get the system interrupt model and evaluate \_PIC.
+ */
+ result = acpi_bus_init_irq();
+ if (result)
+ goto error1;
+
+ /*
+ * Register the for all standard device notifications.
+ */
+ status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL);
+ if (ACPI_FAILURE(status)) {
+ printk(KERN_ERR PREFIX "Unable to register for device notifications\n");
+ goto error1;
+ }
+
+ /*
+ * Create the top ACPI proc directory
+ */
+ acpi_root_dir = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
+
+ return_VALUE(0);
+
+ /* Mimic structured exception handling */
+error1:
+ acpi_terminate();
+ return_VALUE(-ENODEV);
+}
+
+decl_subsys(acpi,NULL,NULL);
+
+static int __init acpi_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_init");
+
+ printk(KERN_INFO PREFIX "Subsystem revision %08x\n",
+ ACPI_CA_VERSION);
+
+ if (acpi_disabled) {
+ printk(KERN_INFO PREFIX "Interpreter disabled.\n");
+ return_VALUE(-ENODEV);
+ }
+
+ firmware_register(&acpi_subsys);
+
+ result = acpi_bus_init();
+
+ if (!result) {
+#ifdef CONFIG_PM
+ if (!PM_IS_ACTIVE())
+ pm_active = 1;
+ else {
+ printk(KERN_INFO PREFIX "APM is already active, exiting\n");
+ disable_acpi();
+ result = -ENODEV;
+ }
+#endif
+ } else
+ disable_acpi();
+
+ return_VALUE(result);
+}
+
+subsys_initcall(acpi_init);
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
new file mode 100644
index 000000000000..ec4430e3053f
--- /dev/null
+++ b/drivers/acpi/button.c
@@ -0,0 +1,558 @@
+/*
+ * acpi_button.c - ACPI Button Driver ($Revision: 30 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/proc_fs.h>
+#include <linux/seq_file.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define ACPI_BUTTON_COMPONENT 0x00080000
+#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver"
+#define ACPI_BUTTON_CLASS "button"
+#define ACPI_BUTTON_FILE_INFO "info"
+#define ACPI_BUTTON_FILE_STATE "state"
+#define ACPI_BUTTON_TYPE_UNKNOWN 0x00
+#define ACPI_BUTTON_NOTIFY_STATUS 0x80
+
+#define ACPI_BUTTON_SUBCLASS_POWER "power"
+#define ACPI_BUTTON_HID_POWER "PNP0C0C"
+#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)"
+#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)"
+#define ACPI_BUTTON_TYPE_POWER 0x01
+#define ACPI_BUTTON_TYPE_POWERF 0x02
+
+#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep"
+#define ACPI_BUTTON_HID_SLEEP "PNP0C0E"
+#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)"
+#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)"
+#define ACPI_BUTTON_TYPE_SLEEP 0x03
+#define ACPI_BUTTON_TYPE_SLEEPF 0x04
+
+#define ACPI_BUTTON_SUBCLASS_LID "lid"
+#define ACPI_BUTTON_HID_LID "PNP0C0D"
+#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
+#define ACPI_BUTTON_TYPE_LID 0x05
+
+#define _COMPONENT ACPI_BUTTON_COMPONENT
+ACPI_MODULE_NAME ("acpi_button")
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION(ACPI_BUTTON_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+
+static int acpi_button_add (struct acpi_device *device);
+static int acpi_button_remove (struct acpi_device *device, int type);
+static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
+static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
+
+static struct acpi_driver acpi_button_driver = {
+ .name = ACPI_BUTTON_DRIVER_NAME,
+ .class = ACPI_BUTTON_CLASS,
+ .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
+ .ops = {
+ .add = acpi_button_add,
+ .remove = acpi_button_remove,
+ },
+};
+
+struct acpi_button {
+ acpi_handle handle;
+ struct acpi_device *device; /* Fixed button kludge */
+ u8 type;
+ unsigned long pushed;
+};
+
+static struct file_operations acpi_button_info_fops = {
+ .open = acpi_button_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct file_operations acpi_button_state_fops = {
+ .open = acpi_button_state_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_button_dir;
+
+static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_button *button = (struct acpi_button *) seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_button_info_seq_show");
+
+ if (!button || !button->device)
+ return_VALUE(0);
+
+ seq_printf(seq, "type: %s\n",
+ acpi_device_name(button->device));
+
+ return_VALUE(0);
+}
+
+static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_button_info_seq_show, PDE(inode)->data);
+}
+
+static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_button *button = (struct acpi_button *) seq->private;
+ acpi_status status;
+ unsigned long state;
+
+ ACPI_FUNCTION_TRACE("acpi_button_state_seq_show");
+
+ if (!button || !button->device)
+ return_VALUE(0);
+
+ status = acpi_evaluate_integer(button->handle,"_LID",NULL,&state);
+ if (ACPI_FAILURE(status)) {
+ seq_printf(seq, "state: unsupported\n");
+ }
+ else{
+ seq_printf(seq, "state: %s\n", (state ? "open" : "closed"));
+ }
+
+ return_VALUE(0);
+}
+
+static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_button_state_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_button_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+ struct acpi_button *button = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_button_add_fs");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ button = acpi_driver_data(device);
+
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWER:
+ case ACPI_BUTTON_TYPE_POWERF:
+ entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
+ acpi_button_dir);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEP:
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
+ acpi_button_dir);
+ break;
+ case ACPI_BUTTON_TYPE_LID:
+ entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
+ acpi_button_dir);
+ break;
+ }
+
+ if (!entry)
+ return_VALUE(-ENODEV);
+ entry->owner = THIS_MODULE;
+
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ acpi_device_dir(device)->owner = THIS_MODULE;
+
+ /* 'info' [R] */
+ entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_BUTTON_FILE_INFO));
+ else {
+ entry->proc_fops = &acpi_button_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* show lid state [R] */
+ if (button->type == ACPI_BUTTON_TYPE_LID) {
+ entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_BUTTON_FILE_INFO));
+ else {
+ entry->proc_fops = &acpi_button_state_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_button_remove_fs (
+ struct acpi_device *device)
+{
+ struct acpi_button *button = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
+
+ button = acpi_driver_data(device);
+ if (acpi_device_dir(device)) {
+ if (button->type == ACPI_BUTTON_TYPE_LID)
+ remove_proc_entry(ACPI_BUTTON_FILE_STATE,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_BUTTON_FILE_INFO,
+ acpi_device_dir(device));
+
+ remove_proc_entry(acpi_device_bid(device),
+ acpi_device_dir(device)->parent);
+
+
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWER:
+ case ACPI_BUTTON_TYPE_POWERF:
+ remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER,
+ acpi_button_dir);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEP:
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP,
+ acpi_button_dir);
+ break;
+ case ACPI_BUTTON_TYPE_LID:
+ remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID,
+ acpi_button_dir);
+ break;
+ }
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static void
+acpi_button_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_button *button = (struct acpi_button *) data;
+
+ ACPI_FUNCTION_TRACE("acpi_button_notify");
+
+ if (!button || !button->device)
+ return_VOID;
+
+ switch (event) {
+ case ACPI_BUTTON_NOTIFY_STATUS:
+ acpi_bus_generate_event(button->device, event, ++button->pushed);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+
+static acpi_status
+acpi_button_notify_fixed (
+ void *data)
+{
+ struct acpi_button *button = (struct acpi_button *) data;
+
+ ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
+
+ if (!button)
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+ acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+
+static int
+acpi_button_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_button *button = NULL;
+
+ static struct acpi_device *power_button;
+ static struct acpi_device *sleep_button;
+ static struct acpi_device *lid_button;
+
+ ACPI_FUNCTION_TRACE("acpi_button_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ button = kmalloc(sizeof(struct acpi_button), GFP_KERNEL);
+ if (!button)
+ return_VALUE(-ENOMEM);
+ memset(button, 0, sizeof(struct acpi_button));
+
+ button->device = device;
+ button->handle = device->handle;
+ acpi_driver_data(device) = button;
+
+ /*
+ * Determine the button type (via hid), as fixed-feature buttons
+ * need to be handled a bit differently than generic-space.
+ */
+ if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
+ button->type = ACPI_BUTTON_TYPE_POWER;
+ strcpy(acpi_device_name(device),
+ ACPI_BUTTON_DEVICE_NAME_POWER);
+ sprintf(acpi_device_class(device), "%s/%s",
+ ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
+ }
+ else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
+ button->type = ACPI_BUTTON_TYPE_POWERF;
+ strcpy(acpi_device_name(device),
+ ACPI_BUTTON_DEVICE_NAME_POWERF);
+ sprintf(acpi_device_class(device), "%s/%s",
+ ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
+ }
+ else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
+ button->type = ACPI_BUTTON_TYPE_SLEEP;
+ strcpy(acpi_device_name(device),
+ ACPI_BUTTON_DEVICE_NAME_SLEEP);
+ sprintf(acpi_device_class(device), "%s/%s",
+ ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
+ }
+ else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
+ button->type = ACPI_BUTTON_TYPE_SLEEPF;
+ strcpy(acpi_device_name(device),
+ ACPI_BUTTON_DEVICE_NAME_SLEEPF);
+ sprintf(acpi_device_class(device), "%s/%s",
+ ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
+ }
+ else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
+ button->type = ACPI_BUTTON_TYPE_LID;
+ strcpy(acpi_device_name(device),
+ ACPI_BUTTON_DEVICE_NAME_LID);
+ sprintf(acpi_device_class(device), "%s/%s",
+ ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
+ }
+ else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
+ acpi_device_hid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+
+ /*
+ * Ensure only one button of each type is used.
+ */
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWER:
+ case ACPI_BUTTON_TYPE_POWERF:
+ if (!power_button)
+ power_button = device;
+ else {
+ kfree(button);
+ return_VALUE(-ENODEV);
+ }
+ break;
+ case ACPI_BUTTON_TYPE_SLEEP:
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ if (!sleep_button)
+ sleep_button = device;
+ else {
+ kfree(button);
+ return_VALUE(-ENODEV);
+ }
+ break;
+ case ACPI_BUTTON_TYPE_LID:
+ if (!lid_button)
+ lid_button = device;
+ else {
+ kfree(button);
+ return_VALUE(-ENODEV);
+ }
+ break;
+ }
+
+ result = acpi_button_add_fs(device);
+ if (result)
+ goto end;
+
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWERF:
+ status = acpi_install_fixed_event_handler (
+ ACPI_EVENT_POWER_BUTTON,
+ acpi_button_notify_fixed,
+ button);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ status = acpi_install_fixed_event_handler (
+ ACPI_EVENT_SLEEP_BUTTON,
+ acpi_button_notify_fixed,
+ button);
+ break;
+ default:
+ status = acpi_install_notify_handler (
+ button->handle,
+ ACPI_DEVICE_NOTIFY,
+ acpi_button_notify,
+ button);
+ break;
+ }
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ if (device->wakeup.flags.valid) {
+ /* Button's GPE is run-wake GPE */
+ acpi_set_gpe_type(device->wakeup.gpe_device,
+ device->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN);
+ acpi_enable_gpe(device->wakeup.gpe_device,
+ device->wakeup.gpe_number, ACPI_NOT_ISR);
+ device->wakeup.state.enabled = 1;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s]\n",
+ acpi_device_name(device), acpi_device_bid(device));
+
+end:
+ if (result) {
+ acpi_button_remove_fs(device);
+ kfree(button);
+ }
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_button_remove (struct acpi_device *device, int type)
+{
+ acpi_status status = 0;
+ struct acpi_button *button = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_button_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ button = acpi_driver_data(device);
+
+ /* Unregister for device notifications. */
+ switch (button->type) {
+ case ACPI_BUTTON_TYPE_POWERF:
+ status = acpi_remove_fixed_event_handler(
+ ACPI_EVENT_POWER_BUTTON, acpi_button_notify_fixed);
+ break;
+ case ACPI_BUTTON_TYPE_SLEEPF:
+ status = acpi_remove_fixed_event_handler(
+ ACPI_EVENT_SLEEP_BUTTON, acpi_button_notify_fixed);
+ break;
+ default:
+ status = acpi_remove_notify_handler(button->handle,
+ ACPI_DEVICE_NOTIFY, acpi_button_notify);
+ break;
+ }
+
+ if (ACPI_FAILURE(status))
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+
+ acpi_button_remove_fs(device);
+
+ kfree(button);
+
+ return_VALUE(0);
+}
+
+
+static int __init
+acpi_button_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_button_init");
+
+ acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
+ if (!acpi_button_dir)
+ return_VALUE(-ENODEV);
+ acpi_button_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&acpi_button_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+
+static void __exit
+acpi_button_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_button_exit");
+
+ acpi_bus_unregister_driver(&acpi_button_driver);
+
+ remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+
+
+module_init(acpi_button_init);
+module_exit(acpi_button_exit);
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
new file mode 100644
index 000000000000..5a0adbf8bc04
--- /dev/null
+++ b/drivers/acpi/container.c
@@ -0,0 +1,303 @@
+/*
+ * acpi_container.c - ACPI Generic Container Driver
+ * ($Revision: )
+ *
+ * Copyright (C) 2004 Anil S Keshavamurthy (anil.s.keshavamurthy@intel.com)
+ * Copyright (C) 2004 Keiichiro Tokunaga (tokunaga.keiich@jp.fujitsu.com)
+ * Copyright (C) 2004 Motoyuki Ito (motoyuki@soft.fujitsu.com)
+ * Copyright (C) 2004 Intel Corp.
+ * Copyright (C) 2004 FUJITSU LIMITED
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/container.h>
+
+#define ACPI_CONTAINER_DRIVER_NAME "ACPI container driver"
+#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
+#define ACPI_CONTAINER_CLASS "container"
+
+#define INSTALL_NOTIFY_HANDLER 1
+#define UNINSTALL_NOTIFY_HANDLER 2
+
+#define ACPI_CONTAINER_COMPONENT 0x01000000
+#define _COMPONENT ACPI_CONTAINER_COMPONENT
+ACPI_MODULE_NAME ("acpi_container")
+
+MODULE_AUTHOR("Anil S Keshavamurthy");
+MODULE_DESCRIPTION(ACPI_CONTAINER_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+#define ACPI_STA_PRESENT (0x00000001)
+
+static int acpi_container_add(struct acpi_device *device);
+static int acpi_container_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_container_driver = {
+ .name = ACPI_CONTAINER_DRIVER_NAME,
+ .class = ACPI_CONTAINER_CLASS,
+ .ids = "ACPI0004,PNP0A05,PNP0A06",
+ .ops = {
+ .add = acpi_container_add,
+ .remove = acpi_container_remove,
+ },
+};
+
+
+/*******************************************************************/
+
+static int
+is_device_present(acpi_handle handle)
+{
+ acpi_handle temp;
+ acpi_status status;
+ unsigned long sta;
+
+ ACPI_FUNCTION_TRACE("is_device_present");
+
+ status = acpi_get_handle(handle, "_STA", &temp);
+ if (ACPI_FAILURE(status))
+ return_VALUE(1); /* _STA not found, assmue device present */
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status))
+ return_VALUE(0); /* Firmware error */
+
+ return_VALUE((sta & ACPI_STA_PRESENT) == ACPI_STA_PRESENT);
+}
+
+/*******************************************************************/
+static int
+acpi_container_add(struct acpi_device *device)
+{
+ struct acpi_container *container;
+
+ ACPI_FUNCTION_TRACE("acpi_container_add");
+
+ if (!device) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "device is NULL\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ container = kmalloc(sizeof(struct acpi_container), GFP_KERNEL);
+ if(!container)
+ return_VALUE(-ENOMEM);
+
+ memset(container, 0, sizeof(struct acpi_container));
+ container->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
+ acpi_driver_data(device) = container;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n", \
+ acpi_device_name(device), acpi_device_bid(device)));
+
+
+ return_VALUE(0);
+}
+
+static int
+acpi_container_remove(struct acpi_device *device, int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_container *pc = NULL;
+ pc = (struct acpi_container*) acpi_driver_data(device);
+
+ if (pc)
+ kfree(pc);
+
+ return status;
+}
+
+
+static int
+container_device_add(struct acpi_device **device, acpi_handle handle)
+{
+ acpi_handle phandle;
+ struct acpi_device *pdev;
+ int result;
+
+ ACPI_FUNCTION_TRACE("container_device_add");
+
+ if (acpi_get_parent(handle, &phandle)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_get_device(phandle, &pdev)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_DEVICE)) {
+ return_VALUE(-ENODEV);
+ }
+
+ result = acpi_bus_scan(*device);
+
+ return_VALUE(result);
+}
+
+static void
+container_notify_cb(acpi_handle handle, u32 type, void *context)
+{
+ struct acpi_device *device = NULL;
+ int result;
+ int present;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("container_notify_cb");
+
+ present = is_device_present(handle);
+
+ switch (type) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ /* Fall through */
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ printk("Container driver received %s event\n",
+ (type == ACPI_NOTIFY_BUS_CHECK)?
+ "ACPI_NOTIFY_BUS_CHECK":"ACPI_NOTIFY_DEVICE_CHECK");
+ status = acpi_bus_get_device(handle, &device);
+ if (present) {
+ if (ACPI_FAILURE(status) || !device) {
+ result = container_device_add(&device, handle);
+ if (!result)
+ kobject_hotplug(&device->kobj,
+ KOBJ_ONLINE);
+ else
+ printk("Failed to add container\n");
+ }
+ } else {
+ if (ACPI_SUCCESS(status)) {
+ /* device exist and this is a remove request */
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ }
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ if (!acpi_bus_get_device(handle, &device) && device) {
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ }
+ break;
+ default:
+ break;
+ }
+ return_VOID;
+}
+
+static acpi_status
+container_walk_namespace_cb(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ char *hid = NULL;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_device_info *info;
+ acpi_status status;
+ int *action = context;
+
+ ACPI_FUNCTION_TRACE("container_walk_namespace_cb");
+
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_FAILURE(status) || !buffer.pointer) {
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ info = buffer.pointer;
+ if (info->valid & ACPI_VALID_HID)
+ hid = info->hardware_id.value;
+
+ if (hid == NULL) {
+ goto end;
+ }
+
+ if (strcmp(hid, "ACPI0004") && strcmp(hid, "PNP0A05") &&
+ strcmp(hid, "PNP0A06")) {
+ goto end;
+ }
+
+ switch(*action) {
+ case INSTALL_NOTIFY_HANDLER:
+ acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ container_notify_cb,
+ NULL);
+ break;
+ case UNINSTALL_NOTIFY_HANDLER:
+ acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ container_notify_cb);
+ break;
+ default:
+ break;
+ }
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ return_ACPI_STATUS(AE_OK);
+}
+
+
+static int __init
+acpi_container_init(void)
+{
+ int result = 0;
+ int action = INSTALL_NOTIFY_HANDLER;
+
+ result = acpi_bus_register_driver(&acpi_container_driver);
+ if (result < 0) {
+ return(result);
+ }
+
+ /* register notify handler to every container device */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ container_walk_namespace_cb,
+ &action, NULL);
+
+ return(0);
+}
+
+static void __exit
+acpi_container_exit(void)
+{
+ int action = UNINSTALL_NOTIFY_HANDLER;
+
+ ACPI_FUNCTION_TRACE("acpi_container_exit");
+
+ acpi_walk_namespace(ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ container_walk_namespace_cb,
+ &action, NULL);
+
+ acpi_bus_unregister_driver(&acpi_container_driver);
+
+ return_VOID;
+}
+
+module_init(acpi_container_init);
+module_exit(acpi_container_exit);
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c
new file mode 100644
index 000000000000..2c0dac559f16
--- /dev/null
+++ b/drivers/acpi/debug.c
@@ -0,0 +1,233 @@
+/*
+ * debug.c - ACPI debug interface to userspace.
+ */
+
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <asm/uaccess.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acglobal.h>
+
+#define _COMPONENT ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME ("debug")
+
+#define ACPI_SYSTEM_FILE_DEBUG_LAYER "debug_layer"
+#define ACPI_SYSTEM_FILE_DEBUG_LEVEL "debug_level"
+
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+
+#define MODULE_PARAM_PREFIX
+module_param(acpi_dbg_layer, uint, 0400);
+module_param(acpi_dbg_level, uint, 0400);
+
+struct acpi_dlayer {
+ const char *name;
+ unsigned long value;
+};
+struct acpi_dlevel {
+ const char *name;
+ unsigned long value;
+};
+#define ACPI_DEBUG_INIT(v) { .name = #v, .value = v }
+
+static const struct acpi_dlayer acpi_debug_layers[] =
+{
+ ACPI_DEBUG_INIT(ACPI_UTILITIES),
+ ACPI_DEBUG_INIT(ACPI_HARDWARE),
+ ACPI_DEBUG_INIT(ACPI_EVENTS),
+ ACPI_DEBUG_INIT(ACPI_TABLES),
+ ACPI_DEBUG_INIT(ACPI_NAMESPACE),
+ ACPI_DEBUG_INIT(ACPI_PARSER),
+ ACPI_DEBUG_INIT(ACPI_DISPATCHER),
+ ACPI_DEBUG_INIT(ACPI_EXECUTER),
+ ACPI_DEBUG_INIT(ACPI_RESOURCES),
+ ACPI_DEBUG_INIT(ACPI_CA_DEBUGGER),
+ ACPI_DEBUG_INIT(ACPI_OS_SERVICES),
+ ACPI_DEBUG_INIT(ACPI_CA_DISASSEMBLER),
+ ACPI_DEBUG_INIT(ACPI_COMPILER),
+ ACPI_DEBUG_INIT(ACPI_TOOLS),
+};
+
+static const struct acpi_dlevel acpi_debug_levels[] =
+{
+ ACPI_DEBUG_INIT(ACPI_LV_ERROR),
+ ACPI_DEBUG_INIT(ACPI_LV_WARN),
+ ACPI_DEBUG_INIT(ACPI_LV_INIT),
+ ACPI_DEBUG_INIT(ACPI_LV_DEBUG_OBJECT),
+ ACPI_DEBUG_INIT(ACPI_LV_INFO),
+
+ ACPI_DEBUG_INIT(ACPI_LV_INIT_NAMES),
+ ACPI_DEBUG_INIT(ACPI_LV_PARSE),
+ ACPI_DEBUG_INIT(ACPI_LV_LOAD),
+ ACPI_DEBUG_INIT(ACPI_LV_DISPATCH),
+ ACPI_DEBUG_INIT(ACPI_LV_EXEC),
+ ACPI_DEBUG_INIT(ACPI_LV_NAMES),
+ ACPI_DEBUG_INIT(ACPI_LV_OPREGION),
+ ACPI_DEBUG_INIT(ACPI_LV_BFIELD),
+ ACPI_DEBUG_INIT(ACPI_LV_TABLES),
+ ACPI_DEBUG_INIT(ACPI_LV_VALUES),
+ ACPI_DEBUG_INIT(ACPI_LV_OBJECTS),
+ ACPI_DEBUG_INIT(ACPI_LV_RESOURCES),
+ ACPI_DEBUG_INIT(ACPI_LV_USER_REQUESTS),
+ ACPI_DEBUG_INIT(ACPI_LV_PACKAGE),
+
+ ACPI_DEBUG_INIT(ACPI_LV_ALLOCATIONS),
+ ACPI_DEBUG_INIT(ACPI_LV_FUNCTIONS),
+ ACPI_DEBUG_INIT(ACPI_LV_OPTIMIZATIONS),
+
+ ACPI_DEBUG_INIT(ACPI_LV_MUTEX),
+ ACPI_DEBUG_INIT(ACPI_LV_THREADS),
+ ACPI_DEBUG_INIT(ACPI_LV_IO),
+ ACPI_DEBUG_INIT(ACPI_LV_INTERRUPTS),
+
+ ACPI_DEBUG_INIT(ACPI_LV_AML_DISASSEMBLE),
+ ACPI_DEBUG_INIT(ACPI_LV_VERBOSE_INFO),
+ ACPI_DEBUG_INIT(ACPI_LV_FULL_TABLES),
+ ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
+};
+
+static int
+acpi_system_read_debug (
+ char *page,
+ char **start,
+ off_t off,
+ int count,
+ int *eof,
+ void *data)
+{
+ char *p = page;
+ int size = 0;
+ unsigned int i;
+
+ if (off != 0)
+ goto end;
+
+ p += sprintf(p, "%-25s\tHex SET\n", "Description");
+
+ switch ((unsigned long) data) {
+ case 0:
+ for (i = 0; i < ARRAY_SIZE(acpi_debug_layers); i++) {
+ p += sprintf(p, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_layers[i].name,
+ acpi_debug_layers[i].value,
+ (acpi_dbg_layer & acpi_debug_layers[i].value) ?
+ '*' : ' ');
+ }
+ p += sprintf(p, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+ ACPI_ALL_DRIVERS,
+ (acpi_dbg_layer & ACPI_ALL_DRIVERS) == ACPI_ALL_DRIVERS?
+ '*' : (acpi_dbg_layer & ACPI_ALL_DRIVERS) == 0 ?
+ ' ' : '-');
+ p += sprintf(p,
+ "--\ndebug_layer = 0x%08X (* = enabled, - = partial)\n",
+ acpi_dbg_layer);
+ break;
+ case 1:
+ for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
+ p += sprintf(p, "%-25s\t0x%08lX [%c]\n",
+ acpi_debug_levels[i].name,
+ acpi_debug_levels[i].value,
+ (acpi_dbg_level & acpi_debug_levels[i].value) ?
+ '*' : ' ');
+ }
+ p += sprintf(p, "--\ndebug_level = 0x%08X (* = enabled)\n",
+ acpi_dbg_level);
+ break;
+ default:
+ p += sprintf(p, "Invalid debug option\n");
+ break;
+ }
+
+end:
+ size = (p - page);
+ if (size <= off+count) *eof = 1;
+ *start = page + off;
+ size -= off;
+ if (size>count) size = count;
+ if (size<0) size = 0;
+
+ return size;
+}
+
+
+static int
+acpi_system_write_debug (
+ struct file *file,
+ const char __user *buffer,
+ unsigned long count,
+ void *data)
+{
+ char debug_string[12] = {'\0'};
+
+ ACPI_FUNCTION_TRACE("acpi_system_write_debug");
+
+ if (count > sizeof(debug_string) - 1)
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(debug_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ debug_string[count] = '\0';
+
+ switch ((unsigned long) data) {
+ case 0:
+ acpi_dbg_layer = simple_strtoul(debug_string, NULL, 0);
+ break;
+ case 1:
+ acpi_dbg_level = simple_strtoul(debug_string, NULL, 0);
+ break;
+ default:
+ return_VALUE(-EINVAL);
+ }
+
+ return_VALUE(count);
+}
+
+static int __init acpi_debug_init(void)
+{
+ struct proc_dir_entry *entry;
+ int error = 0;
+ char * name;
+
+ ACPI_FUNCTION_TRACE("acpi_debug_init");
+
+ if (acpi_disabled)
+ return_VALUE(0);
+
+ /* 'debug_layer' [R/W] */
+ name = ACPI_SYSTEM_FILE_DEBUG_LAYER;
+ entry = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir,
+ acpi_system_read_debug,(void *)0);
+ if (entry)
+ entry->write_proc = acpi_system_write_debug;
+ else
+ goto Error;
+
+ /* 'debug_level' [R/W] */
+ name = ACPI_SYSTEM_FILE_DEBUG_LEVEL;
+ entry = create_proc_read_entry(name, S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir,
+ acpi_system_read_debug, (void *)1);
+ if (entry)
+ entry->write_proc = acpi_system_write_debug;
+ else
+ goto Error;
+
+ Done:
+ return_VALUE(error);
+
+ Error:
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' proc fs entry\n", name));
+
+ remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LEVEL, acpi_root_dir);
+ remove_proc_entry(ACPI_SYSTEM_FILE_DEBUG_LAYER, acpi_root_dir);
+ error = -EFAULT;
+ goto Done;
+}
+
+subsys_initcall(acpi_debug_init);
diff --git a/drivers/acpi/dispatcher/Makefile b/drivers/acpi/dispatcher/Makefile
new file mode 100644
index 000000000000..eb7e602a83cd
--- /dev/null
+++ b/drivers/acpi/dispatcher/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := dsfield.o dsmthdat.o dsopcode.o dswexec.o dswscope.o \
+ dsmethod.o dsobject.o dsutils.o dswload.o dswstate.o \
+ dsinit.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
new file mode 100644
index 000000000000..2779211be756
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -0,0 +1,601 @@
+/******************************************************************************
+ *
+ * Module Name: dsfield - Dispatcher field routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dsfield")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_buffer_field
+ *
+ * PARAMETERS: Opcode - The opcode to be executed
+ * Operands - List of operands for the opcode
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute the create_field operators:
+ * create_bit_field_op,
+ * create_byte_field_op,
+ * create_word_field_op,
+ * create_dword_field_op,
+ * create_qword_field_op,
+ * create_field_op (all of which define fields in buffers)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_buffer_field (
+ union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *arg;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *second_desc = NULL;
+ u32 flags;
+
+
+ ACPI_FUNCTION_TRACE ("ds_create_buffer_field");
+
+
+ /* Get the name_string argument */
+
+ if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+ arg = acpi_ps_get_arg (op, 3);
+ }
+ else {
+ /* Create Bit/Byte/Word/Dword field */
+
+ arg = acpi_ps_get_arg (op, 2);
+ }
+
+ if (!arg) {
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ if (walk_state->deferred_node) {
+ node = walk_state->deferred_node;
+ status = AE_OK;
+ }
+ else {
+ /*
+ * During the load phase, we want to enter the name of the field into
+ * the namespace. During the execute phase (when we evaluate the size
+ * operand), we want to lookup the name
+ */
+ if (walk_state->parse_flags & ACPI_PARSE_EXECUTE) {
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
+ }
+ else {
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND;
+ }
+
+ /*
+ * Enter the name_string into the namespace
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS1,
+ flags, walk_state, &(node));
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (arg->common.value.string, status);
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* We could put the returned object (Node) on the object stack for later, but
+ * for now, we will put it in the "op" object that the parser uses, so we
+ * can get it again at the end of this scope
+ */
+ op->common.node = node;
+
+ /*
+ * If there is no object attached to the node, this node was just created and
+ * we need to create the field object. Otherwise, this was a lookup of an
+ * existing node and we don't want to create the field object again.
+ */
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (obj_desc) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * The Field definition is not fully parsed at this time.
+ * (We must save the address of the AML for the buffer and index operands)
+ */
+
+ /* Create the buffer field object */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER_FIELD);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Remember location in AML stream of the field unit
+ * opcode and operands -- since the buffer and index
+ * operands must be evaluated.
+ */
+ second_desc = obj_desc->common.next_object;
+ second_desc->extra.aml_start = op->named.data;
+ second_desc->extra.aml_length = op->named.length;
+ obj_desc->buffer_field.node = node;
+
+ /* Attach constructed field descriptors to parent node */
+
+ status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_BUFFER_FIELD);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+
+cleanup:
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_field_names
+ *
+ * PARAMETERS: Info - create_field info structure
+ * ` walk_state - Current method state
+ * Arg - First parser arg for the field name list
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Process all named fields in a field declaration. Names are
+ * entered into the namespace.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_get_field_names (
+ struct acpi_create_field_info *info,
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *arg)
+{
+ acpi_status status;
+ acpi_integer position;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_get_field_names", info);
+
+
+ /* First field starts at bit zero */
+
+ info->field_bit_position = 0;
+
+ /* Process all elements in the field list (of parse nodes) */
+
+ while (arg) {
+ /*
+ * Three types of field elements are handled:
+ * 1) Offset - specifies a bit offset
+ * 2) access_as - changes the access mode
+ * 3) Name - Enters a new named field into the namespace
+ */
+ switch (arg->common.aml_opcode) {
+ case AML_INT_RESERVEDFIELD_OP:
+
+ position = (acpi_integer) info->field_bit_position
+ + (acpi_integer) arg->common.value.size;
+
+ if (position > ACPI_UINT32_MAX) {
+ ACPI_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n"));
+ return_ACPI_STATUS (AE_SUPPORT);
+ }
+
+ info->field_bit_position = (u32) position;
+ break;
+
+
+ case AML_INT_ACCESSFIELD_OP:
+
+ /*
+ * Get a new access_type and access_attribute -- to be used for all
+ * field units that follow, until field end or another access_as keyword.
+ *
+ * In field_flags, preserve the flag bits other than the ACCESS_TYPE bits
+ */
+ info->field_flags = (u8) ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |
+ ((u8) ((u32) arg->common.value.integer >> 8)));
+
+ info->attribute = (u8) (arg->common.value.integer);
+ break;
+
+
+ case AML_INT_NAMEDFIELD_OP:
+
+ /* Lookup the name */
+
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (char *) &arg->named.name,
+ info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE,
+ walk_state, &info->field_node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR ((char *) &arg->named.name, status);
+ if (status != AE_ALREADY_EXISTS) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Already exists, ignore error */
+ }
+ else {
+ arg->common.node = info->field_node;
+ info->field_bit_length = arg->common.value.size;
+
+ /* Create and initialize an object for the new Field Node */
+
+ status = acpi_ex_prep_field_value (info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Keep track of bit position for the next field */
+
+ position = (acpi_integer) info->field_bit_position
+ + (acpi_integer) arg->common.value.size;
+
+ if (position > ACPI_UINT32_MAX) {
+ ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n",
+ (char *) &info->field_node->name));
+ return_ACPI_STATUS (AE_SUPPORT);
+ }
+
+ info->field_bit_position += info->field_bit_length;
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n",
+ arg->common.aml_opcode));
+ return_ACPI_STATUS (AE_AML_BAD_OPCODE);
+ }
+
+ arg = arg->common.next;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * region_node - Object for the containing Operation Region
+ * ` walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new field in the specified operation region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_field (
+ union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg;
+ struct acpi_create_field_info info;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_create_field", op);
+
+
+ /* First arg is the name of the parent op_region (must already exist) */
+
+ arg = op->common.value.arg;
+ if (!region_node) {
+ status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name,
+ ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state, &region_node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (arg->common.value.name, status);
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Second arg is the field flags */
+
+ arg = arg->common.next;
+ info.field_flags = (u8) arg->common.value.integer;
+ info.attribute = 0;
+
+ /* Each remaining arg is a Named Field */
+
+ info.field_type = ACPI_TYPE_LOCAL_REGION_FIELD;
+ info.region_node = region_node;
+
+ status = acpi_ds_get_field_names (&info, walk_state, arg->common.next);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_field_objects
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * ` walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: For each "Field Unit" name in the argument list that is
+ * part of the field declaration, enter the name into the
+ * namespace.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_init_field_objects (
+ union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg = NULL;
+ struct acpi_namespace_node *node;
+ u8 type = 0;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_init_field_objects", op);
+
+
+ switch (walk_state->opcode) {
+ case AML_FIELD_OP:
+ arg = acpi_ps_get_arg (op, 2);
+ type = ACPI_TYPE_LOCAL_REGION_FIELD;
+ break;
+
+ case AML_BANK_FIELD_OP:
+ arg = acpi_ps_get_arg (op, 4);
+ type = ACPI_TYPE_LOCAL_BANK_FIELD;
+ break;
+
+ case AML_INDEX_FIELD_OP:
+ arg = acpi_ps_get_arg (op, 3);
+ type = ACPI_TYPE_LOCAL_INDEX_FIELD;
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Walk the list of entries in the field_list
+ */
+ while (arg) {
+ /* Ignore OFFSET and ACCESSAS terms here */
+
+ if (arg->common.aml_opcode == AML_INT_NAMEDFIELD_OP) {
+ status = acpi_ns_lookup (walk_state->scope_info,
+ (char *) &arg->named.name,
+ type, ACPI_IMODE_LOAD_PASS1,
+ ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
+ walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR ((char *) &arg->named.name, status);
+ if (status != AE_ALREADY_EXISTS) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Name already exists, just ignore this error */
+
+ status = AE_OK;
+ }
+
+ arg->common.node = node;
+ }
+
+ /* Move to next field in the list */
+
+ arg = arg->common.next;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_bank_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * region_node - Object for the containing Operation Region
+ * ` walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new bank field in the specified operation region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_bank_field (
+ union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg;
+ struct acpi_create_field_info info;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_create_bank_field", op);
+
+
+ /* First arg is the name of the parent op_region (must already exist) */
+
+ arg = op->common.value.arg;
+ if (!region_node) {
+ status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.name,
+ ACPI_TYPE_REGION, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state, &region_node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (arg->common.value.name, status);
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Second arg is the Bank Register (Field) (must already exist) */
+
+ arg = arg->common.next;
+ status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (arg->common.value.string, status);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Third arg is the bank_value */
+
+ arg = arg->common.next;
+ info.bank_value = (u32) arg->common.value.integer;
+
+ /* Fourth arg is the field flags */
+
+ arg = arg->common.next;
+ info.field_flags = (u8) arg->common.value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ info.field_type = ACPI_TYPE_LOCAL_BANK_FIELD;
+ info.region_node = region_node;
+
+ status = acpi_ds_get_field_names (&info, walk_state, arg->common.next);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_index_field
+ *
+ * PARAMETERS: Op - Op containing the Field definition and args
+ * region_node - Object for the containing Operation Region
+ * ` walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new index field in the specified operation region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_index_field (
+ union acpi_parse_object *op,
+ struct acpi_namespace_node *region_node,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_parse_object *arg;
+ struct acpi_create_field_info info;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_create_index_field", op);
+
+
+ /* First arg is the name of the Index register (must already exist) */
+
+ arg = op->common.value.arg;
+ status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state, &info.register_node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (arg->common.value.string, status);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Second arg is the data register (must already exist) */
+
+ arg = arg->common.next;
+ status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT, walk_state, &info.data_register_node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (arg->common.value.string, status);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Next arg is the field flags */
+
+ arg = arg->common.next;
+ info.field_flags = (u8) arg->common.value.integer;
+
+ /* Each remaining arg is a Named Field */
+
+ info.field_type = ACPI_TYPE_LOCAL_INDEX_FIELD;
+ info.region_node = region_node;
+
+ status = acpi_ds_get_field_names (&info, walk_state, arg->common.next);
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
new file mode 100644
index 000000000000..b4d264dbbf67
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -0,0 +1,235 @@
+/******************************************************************************
+ *
+ * Module Name: dsinit - Object initialization namespace walk
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dsinit")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_one_object
+ *
+ * PARAMETERS: obj_handle - Node
+ * Level - Current nesting level
+ * Context - Points to a init info struct
+ * return_value - Not used
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object
+ * within the namespace.
+ *
+ * Currently, the only objects that require initialization are:
+ * 1) Methods
+ * 2) Operation Regions
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_init_one_object (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ acpi_object_type type;
+ acpi_status status;
+ struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context;
+
+
+ ACPI_FUNCTION_NAME ("ds_init_one_object");
+
+
+ /*
+ * We are only interested in objects owned by the table that
+ * was just loaded
+ */
+ if (((struct acpi_namespace_node *) obj_handle)->owner_id !=
+ info->table_desc->table_id) {
+ return (AE_OK);
+ }
+
+ info->object_count++;
+
+ /* And even then, we are only interested in a few object types */
+
+ type = acpi_ns_get_type (obj_handle);
+
+ switch (type) {
+ case ACPI_TYPE_REGION:
+
+ status = acpi_ds_initialize_region (obj_handle);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n",
+ obj_handle, acpi_ut_get_node_name (obj_handle),
+ acpi_format_exception (status)));
+ }
+
+ info->op_region_count++;
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ info->method_count++;
+
+ /* Print a dot for each method unless we are going to print the entire pathname */
+
+ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
+ }
+
+ /*
+ * Set the execution data width (32 or 64) based upon the
+ * revision number of the parent ACPI table.
+ * TBD: This is really for possible future support of integer width
+ * on a per-table basis. Currently, we just use a global for the width.
+ */
+ if (info->table_desc->pointer->revision == 1) {
+ ((struct acpi_namespace_node *) obj_handle)->flags |= ANOBJ_DATA_WIDTH_32;
+ }
+
+ /*
+ * Always parse methods to detect errors, we will delete
+ * the parse tree below
+ */
+ status = acpi_ds_parse_method (obj_handle);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n",
+ obj_handle, acpi_ut_get_node_name (obj_handle),
+ acpi_format_exception (status)));
+
+ /* This parse failed, but we will continue parsing more methods */
+
+ break;
+ }
+
+ /*
+ * Delete the parse tree. We simply re-parse the method
+ * for every execution since there isn't much overhead
+ */
+ acpi_ns_delete_namespace_subtree (obj_handle);
+ acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id);
+ break;
+
+
+ case ACPI_TYPE_DEVICE:
+
+ info->device_count++;
+ break;
+
+
+ default:
+ break;
+ }
+
+ /*
+ * We ignore errors from above, and always return OK, since
+ * we don't want to abort the walk on a single error.
+ */
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_initialize_objects
+ *
+ * PARAMETERS: table_desc - Descriptor for parent ACPI table
+ * start_node - Root of subtree to be initialized.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk the namespace starting at "start_node" and perform any
+ * necessary initialization on the objects found therein
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_initialize_objects (
+ struct acpi_table_desc *table_desc,
+ struct acpi_namespace_node *start_node)
+{
+ acpi_status status;
+ struct acpi_init_walk_info info;
+
+
+ ACPI_FUNCTION_TRACE ("ds_initialize_objects");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "**** Starting initialization of namespace objects ****\n"));
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "Parsing all Control Methods:"));
+
+ info.method_count = 0;
+ info.op_region_count = 0;
+ info.object_count = 0;
+ info.device_count = 0;
+ info.table_desc = table_desc;
+
+ /* Walk entire namespace from the supplied root */
+
+ status = acpi_walk_namespace (ACPI_TYPE_ANY, start_node, ACPI_UINT32_MAX,
+ acpi_ds_init_one_object, &info, NULL);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed, %s\n",
+ acpi_format_exception (status)));
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+ "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
+ table_desc->pointer->signature, table_desc->table_id, info.object_count,
+ info.device_count, info.method_count, info.op_region_count));
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "%hd Methods, %hd Regions\n", info.method_count, info.op_region_count));
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
new file mode 100644
index 000000000000..9f0456cb9bb5
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -0,0 +1,597 @@
+/******************************************************************************
+ *
+ * Module Name: dsmethod - Parser/Interpreter interface - control method parsing
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dsmethod")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_parse_method
+ *
+ * PARAMETERS: obj_handle - Method node
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Call the parser and parse the AML that is associated with the
+ * method.
+ *
+ * MUTEX: Assumes parser is locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_parse_method (
+ acpi_handle obj_handle)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_parse_object *op;
+ struct acpi_namespace_node *node;
+ acpi_owner_id owner_id;
+ struct acpi_walk_state *walk_state;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_parse_method", obj_handle);
+
+
+ /* Parameter Validation */
+
+ if (!obj_handle) {
+ return_ACPI_STATUS (AE_NULL_ENTRY);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "**** Parsing [%4.4s] **** named_obj=%p\n",
+ acpi_ut_get_node_name (obj_handle), obj_handle));
+
+ /* Extract the method object from the method Node */
+
+ node = (struct acpi_namespace_node *) obj_handle;
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NULL_OBJECT);
+ }
+
+ /* Create a mutex for the method if there is a concurrency limit */
+
+ if ((obj_desc->method.concurrency != ACPI_INFINITE_CONCURRENCY) &&
+ (!obj_desc->method.semaphore)) {
+ status = acpi_os_create_semaphore (obj_desc->method.concurrency,
+ obj_desc->method.concurrency,
+ &obj_desc->method.semaphore);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Allocate a new parser op to be the root of the parsed
+ * method tree
+ */
+ op = acpi_ps_alloc_op (AML_METHOD_OP);
+ if (!op) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Init new op with the method name and pointer back to the Node */
+
+ acpi_ps_set_name (op, node->name.integer);
+ op->common.node = node;
+
+ /*
+ * Get a new owner_id for objects created by this method. Namespace
+ * objects (such as Operation Regions) can be created during the
+ * first pass parse.
+ */
+ owner_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);
+ obj_desc->method.owning_id = owner_id;
+
+ /* Create and initialize a new walk state */
+
+ walk_state = acpi_ds_create_walk_state (owner_id, NULL, NULL, NULL);
+ if (!walk_state) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ status = acpi_ds_init_aml_walk (walk_state, op, node,
+ obj_desc->method.aml_start,
+ obj_desc->method.aml_length, NULL, 1);
+ if (ACPI_FAILURE (status)) {
+ acpi_ds_delete_walk_state (walk_state);
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Parse the method, first pass
+ *
+ * The first pass load is where newly declared named objects are
+ * added into the namespace. Actual evaluation of
+ * the named objects (what would be called a "second
+ * pass") happens during the actual execution of the
+ * method so that operands to the named objects can
+ * take on dynamic run-time values.
+ */
+ status = acpi_ps_parse_aml (walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "**** [%4.4s] Parsed **** named_obj=%p Op=%p\n",
+ acpi_ut_get_node_name (obj_handle), obj_handle, op));
+
+ acpi_ps_delete_parse_tree (op);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_begin_method_execution
+ *
+ * PARAMETERS: method_node - Node of the method
+ * obj_desc - The method object
+ * calling_method_node - Caller of this method (if non-null)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Prepare a method for execution. Parses the method if necessary,
+ * increments the thread count, and waits at the method semaphore
+ * for clearance to execute.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_begin_method_execution (
+ struct acpi_namespace_node *method_node,
+ union acpi_operand_object *obj_desc,
+ struct acpi_namespace_node *calling_method_node)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_begin_method_execution", method_node);
+
+
+ if (!method_node) {
+ return_ACPI_STATUS (AE_NULL_ENTRY);
+ }
+
+ /*
+ * If there is a concurrency limit on this method, we need to
+ * obtain a unit from the method semaphore.
+ */
+ if (obj_desc->method.semaphore) {
+ /*
+ * Allow recursive method calls, up to the reentrancy/concurrency
+ * limit imposed by the SERIALIZED rule and the sync_level method
+ * parameter.
+ *
+ * The point of this code is to avoid permanently blocking a
+ * thread that is making recursive method calls.
+ */
+ if (method_node == calling_method_node) {
+ if (obj_desc->method.thread_count >= obj_desc->method.concurrency) {
+ return_ACPI_STATUS (AE_AML_METHOD_LIMIT);
+ }
+ }
+
+ /*
+ * Get a unit from the method semaphore. This releases the
+ * interpreter if we block
+ */
+ status = acpi_ex_system_wait_semaphore (obj_desc->method.semaphore,
+ ACPI_WAIT_FOREVER);
+ }
+
+ /*
+ * Increment the method parse tree thread count since it has been
+ * reentered one more time (even if it is the same thread)
+ */
+ obj_desc->method.thread_count++;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_call_control_method
+ *
+ * PARAMETERS: Thread - Info for this thread
+ * this_walk_state - Current walk state
+ * Op - Current Op to be walked
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transfer execution to a called control method
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_call_control_method (
+ struct acpi_thread_state *thread,
+ struct acpi_walk_state *this_walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ struct acpi_namespace_node *method_node;
+ struct acpi_walk_state *next_walk_state;
+ union acpi_operand_object *obj_desc;
+ struct acpi_parameter_info info;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_call_control_method", this_walk_state);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Execute method %p, currentstate=%p\n",
+ this_walk_state->prev_op, this_walk_state));
+
+ /*
+ * Get the namespace entry for the control method we are about to call
+ */
+ method_node = this_walk_state->method_call_node;
+ if (!method_node) {
+ return_ACPI_STATUS (AE_NULL_ENTRY);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (method_node);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NULL_OBJECT);
+ }
+
+ obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);
+
+ /* Init for new method, wait on concurrency semaphore */
+
+ status = acpi_ds_begin_method_execution (method_node, obj_desc,
+ this_walk_state->method_node);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
+ /* 1) Parse: Create a new walk state for the preempting walk */
+
+ next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
+ op, obj_desc, NULL);
+ if (!next_walk_state) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Create and init a Root Node */
+
+ op = acpi_ps_create_scope_op ();
+ if (!op) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ status = acpi_ds_init_aml_walk (next_walk_state, op, method_node,
+ obj_desc->method.aml_start, obj_desc->method.aml_length,
+ NULL, 1);
+ if (ACPI_FAILURE (status)) {
+ acpi_ds_delete_walk_state (next_walk_state);
+ goto cleanup;
+ }
+
+ /* Begin AML parse */
+
+ status = acpi_ps_parse_aml (next_walk_state);
+ acpi_ps_delete_parse_tree (op);
+ }
+
+ /* 2) Execute: Create a new state for the preempting walk */
+
+ next_walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
+ NULL, obj_desc, thread);
+ if (!next_walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+ /*
+ * The resolved arguments were put on the previous walk state's operand
+ * stack. Operands on the previous walk state stack always
+ * start at index 0.
+ * Null terminate the list of arguments
+ */
+ this_walk_state->operands [this_walk_state->num_operands] = NULL;
+
+ info.parameters = &this_walk_state->operands[0];
+ info.parameter_type = ACPI_PARAM_ARGS;
+
+ status = acpi_ds_init_aml_walk (next_walk_state, NULL, method_node,
+ obj_desc->method.aml_start, obj_desc->method.aml_length,
+ &info, 3);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * Delete the operands on the previous walkstate operand stack
+ * (they were copied to new objects)
+ */
+ for (i = 0; i < obj_desc->method.param_count; i++) {
+ acpi_ut_remove_reference (this_walk_state->operands [i]);
+ this_walk_state->operands [i] = NULL;
+ }
+
+ /* Clear the operand stack */
+
+ this_walk_state->num_operands = 0;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Starting nested execution, newstate=%p\n", next_walk_state));
+
+ if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
+ status = obj_desc->method.implementation (next_walk_state);
+ return_ACPI_STATUS (status);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+
+
+ /* On error, we must delete the new walk state */
+
+cleanup:
+ if (next_walk_state && (next_walk_state->method_desc)) {
+ /* Decrement the thread count on the method parse tree */
+
+ next_walk_state->method_desc->method.thread_count--;
+ }
+ (void) acpi_ds_terminate_control_method (next_walk_state);
+ acpi_ds_delete_walk_state (next_walk_state);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_restart_control_method
+ *
+ * PARAMETERS: walk_state - State for preempted method (caller)
+ * return_desc - Return value from the called method
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Restart a method that was preempted by another (nested) method
+ * invocation. Handle the return value (if any) from the callee.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_restart_control_method (
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object *return_desc)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_restart_control_method", walk_state);
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "****Restart [%4.4s] Op %p return_value_from_callee %p\n",
+ (char *) &walk_state->method_node->name, walk_state->method_call_op,
+ return_desc));
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ " return_from_this_method_used?=%X res_stack %p Walk %p\n",
+ walk_state->return_used,
+ walk_state->results, walk_state));
+
+ /* Did the called method return a value? */
+
+ if (return_desc) {
+ /* Are we actually going to use the return value? */
+
+ if (walk_state->return_used) {
+ /* Save the return value from the previous method */
+
+ status = acpi_ds_result_push (return_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Save as THIS method's return value in case it is returned
+ * immediately to yet another method
+ */
+ walk_state->return_desc = return_desc;
+ }
+
+ /*
+ * The following code is the
+ * optional support for a so-called "implicit return". Some AML code
+ * assumes that the last value of the method is "implicitly" returned
+ * to the caller. Just save the last result as the return value.
+ * NOTE: this is optional because the ASL language does not actually
+ * support this behavior.
+ */
+ else if (!acpi_ds_do_implicit_return (return_desc, walk_state, FALSE)) {
+ /*
+ * Delete the return value if it will not be used by the
+ * calling method
+ */
+ acpi_ut_remove_reference (return_desc);
+ }
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_terminate_control_method
+ *
+ * PARAMETERS: walk_state - State of the method
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Terminate a control method. Delete everything that the method
+ * created, delete all locals and arguments, and delete the parse
+ * tree if requested.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_terminate_control_method (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *method_node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_terminate_control_method", walk_state);
+
+
+ if (!walk_state) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* The current method object was saved in the walk state */
+
+ obj_desc = walk_state->method_desc;
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Delete all arguments and locals */
+
+ acpi_ds_method_data_delete_all (walk_state);
+
+ /*
+ * Lock the parser while we terminate this method.
+ * If this is the last thread executing the method,
+ * we have additional cleanup to perform
+ */
+ status = acpi_ut_acquire_mutex (ACPI_MTX_PARSER);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Signal completion of the execution of this method if necessary */
+
+ if (walk_state->method_desc->method.semaphore) {
+ status = acpi_os_signal_semaphore (
+ walk_state->method_desc->method.semaphore, 1);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not signal method semaphore\n"));
+ status = AE_OK;
+
+ /* Ignore error and continue cleanup */
+ }
+ }
+
+ if (walk_state->method_desc->method.thread_count) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "*** Not deleting method namespace, there are still %d threads\n",
+ walk_state->method_desc->method.thread_count));
+ }
+
+ if (!walk_state->method_desc->method.thread_count) {
+ /*
+ * Support to dynamically change a method from not_serialized to
+ * Serialized if it appears that the method is written foolishly and
+ * does not support multiple thread execution. The best example of this
+ * is if such a method creates namespace objects and blocks. A second
+ * thread will fail with an AE_ALREADY_EXISTS exception
+ *
+ * This code is here because we must wait until the last thread exits
+ * before creating the synchronization semaphore.
+ */
+ if ((walk_state->method_desc->method.concurrency == 1) &&
+ (!walk_state->method_desc->method.semaphore)) {
+ status = acpi_os_create_semaphore (1,
+ 1,
+ &walk_state->method_desc->method.semaphore);
+ }
+
+ /*
+ * There are no more threads executing this method. Perform
+ * additional cleanup.
+ *
+ * The method Node is stored in the walk state
+ */
+ method_node = walk_state->method_node;
+
+ /*
+ * Delete any namespace entries created immediately underneath
+ * the method
+ */
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (method_node->child) {
+ acpi_ns_delete_namespace_subtree (method_node);
+ }
+
+ /*
+ * Delete any namespace entries created anywhere else within
+ * the namespace
+ */
+ acpi_ns_delete_namespace_by_owner (walk_state->method_desc->method.owning_id);
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ status = acpi_ut_release_mutex (ACPI_MTX_PARSER);
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
new file mode 100644
index 000000000000..f31d095f9833
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -0,0 +1,715 @@
+/*******************************************************************************
+ *
+ * Module Name: dsmthdat - control method arguments and local variables
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dsmthdat")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_init
+ *
+ * PARAMETERS: walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the data structures that hold the method's arguments
+ * and locals. The data struct is an array of NTEs for each.
+ * This allows ref_of and de_ref_of to work properly for these
+ * special data types.
+ *
+ * NOTES: walk_state fields are initialized to zero by the
+ * ACPI_MEM_CALLOCATE().
+ *
+ * A pseudo-Namespace Node is assigned to each argument and local
+ * so that ref_of() can return a pointer to the Node.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_method_data_init (
+ struct acpi_walk_state *walk_state)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ds_method_data_init");
+
+
+ /* Init the method arguments */
+
+ for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++) {
+ ACPI_MOVE_32_TO_32 (&walk_state->arguments[i].name,
+ NAMEOF_ARG_NTE);
+ walk_state->arguments[i].name.integer |= (i << 24);
+ walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED;
+ walk_state->arguments[i].type = ACPI_TYPE_ANY;
+ walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
+ }
+
+ /* Init the method locals */
+
+ for (i = 0; i < ACPI_METHOD_NUM_LOCALS; i++) {
+ ACPI_MOVE_32_TO_32 (&walk_state->local_variables[i].name,
+ NAMEOF_LOCAL_NTE);
+
+ walk_state->local_variables[i].name.integer |= (i << 24);
+ walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED;
+ walk_state->local_variables[i].type = ACPI_TYPE_ANY;
+ walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_delete_all
+ *
+ * PARAMETERS: walk_state - Current walk state object
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete method locals and arguments. Arguments are only
+ * deleted if this method was called from another method.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_method_data_delete_all (
+ struct acpi_walk_state *walk_state)
+{
+ u32 index;
+
+
+ ACPI_FUNCTION_TRACE ("ds_method_data_delete_all");
+
+
+ /* Detach the locals */
+
+ for (index = 0; index < ACPI_METHOD_NUM_LOCALS; index++) {
+ if (walk_state->local_variables[index].object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Local%d=%p\n",
+ index, walk_state->local_variables[index].object));
+
+ /* Detach object (if present) and remove a reference */
+
+ acpi_ns_detach_object (&walk_state->local_variables[index]);
+ }
+ }
+
+ /* Detach the arguments */
+
+ for (index = 0; index < ACPI_METHOD_NUM_ARGS; index++) {
+ if (walk_state->arguments[index].object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Deleting Arg%d=%p\n",
+ index, walk_state->arguments[index].object));
+
+ /* Detach object (if present) and remove a reference */
+
+ acpi_ns_detach_object (&walk_state->arguments[index]);
+ }
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_init_args
+ *
+ * PARAMETERS: *Params - Pointer to a parameter list for the method
+ * max_param_count - The arg count for this method
+ * walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize arguments for a method. The parameter list is a list
+ * of ACPI operand objects, either null terminated or whose length
+ * is defined by max_param_count.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_data_init_args (
+ union acpi_operand_object **params,
+ u32 max_param_count,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ u32 index = 0;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_method_data_init_args", params);
+
+
+ if (!params) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "No param list passed to method\n"));
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Copy passed parameters into the new method stack frame */
+
+ while ((index < ACPI_METHOD_NUM_ARGS) && (index < max_param_count) && params[index]) {
+ /*
+ * A valid parameter.
+ * Store the argument in the method/walk descriptor.
+ * Do not copy the arg in order to implement call by reference
+ */
+ status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ index++;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%d args passed to method\n", index));
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_get_node
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - which local_var or argument whose type
+ * to get
+ * walk_state - Current walk state object
+ *
+ * RETURN: Get the Node associated with a local or arg.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_data_get_node (
+ u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node **node)
+{
+ ACPI_FUNCTION_TRACE ("ds_method_data_get_node");
+
+
+ /*
+ * Method Locals and Arguments are supported
+ */
+ switch (opcode) {
+ case AML_LOCAL_OP:
+
+ if (index > ACPI_METHOD_MAX_LOCAL) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n",
+ index, ACPI_METHOD_MAX_LOCAL));
+ return_ACPI_STATUS (AE_AML_INVALID_INDEX);
+ }
+
+ /* Return a pointer to the pseudo-node */
+
+ *node = &walk_state->local_variables[index];
+ break;
+
+ case AML_ARG_OP:
+
+ if (index > ACPI_METHOD_MAX_ARG) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n",
+ index, ACPI_METHOD_MAX_ARG));
+ return_ACPI_STATUS (AE_AML_INVALID_INDEX);
+ }
+
+ /* Return a pointer to the pseudo-node */
+
+ *node = &walk_state->arguments[index];
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Opcode %d is invalid\n", opcode));
+ return_ACPI_STATUS (AE_AML_BAD_OPCODE);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_set_value
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - which local_var or argument to get
+ * Object - Object to be inserted into the stack entry
+ * walk_state - Current walk state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Insert an object onto the method stack at entry Opcode:Index.
+ * Note: There is no "implicit conversion" for locals.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_data_set_value (
+ u16 opcode,
+ u32 index,
+ union acpi_operand_object *object,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+
+
+ ACPI_FUNCTION_TRACE ("ds_method_data_set_value");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "new_obj %p Opcode %X, Refs=%d [%s]\n", object,
+ opcode, object->common.reference_count,
+ acpi_ut_get_type_name (object->common.type)));
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Increment ref count so object can't be deleted while installed.
+ * NOTE: We do not copy the object in order to preserve the call by
+ * reference semantics of ACPI Control Method invocation.
+ * (See ACPI specification 2.0_c)
+ */
+ acpi_ut_add_reference (object);
+
+ /* Install the object */
+
+ node->object = object;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_get_type
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - which local_var or argument whose type
+ * to get
+ * walk_state - Current walk state object
+ *
+ * RETURN: Data type of current value of the selected Arg or Local
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_object_type
+acpi_ds_method_data_get_type (
+ u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *object;
+
+
+ ACPI_FUNCTION_TRACE ("ds_method_data_get_type");
+
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ return_VALUE ((ACPI_TYPE_NOT_FOUND));
+ }
+
+ /* Get the object */
+
+ object = acpi_ns_get_attached_object (node);
+ if (!object) {
+ /* Uninitialized local/arg, return TYPE_ANY */
+
+ return_VALUE (ACPI_TYPE_ANY);
+ }
+
+ /* Get the object type */
+
+ return_VALUE (ACPI_GET_OBJECT_TYPE (object));
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_get_value
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - which local_var or argument to get
+ * walk_state - Current walk state object
+ * *dest_desc - Ptr to Descriptor into which selected Arg
+ * or Local value should be copied
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame
+ * at the current top of the method stack.
+ * Used only in acpi_ex_resolve_to_value().
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_method_data_get_value (
+ u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object **dest_desc)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *object;
+
+
+ ACPI_FUNCTION_TRACE ("ds_method_data_get_value");
+
+
+ /* Validate the object descriptor */
+
+ if (!dest_desc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null object descriptor pointer\n"));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the object from the node */
+
+ object = node->object;
+
+ /* Examine the returned object, it must be valid. */
+
+ if (!object) {
+ /*
+ * Index points to uninitialized object.
+ * This means that either 1) The expected argument was
+ * not passed to the method, or 2) A local variable
+ * was referenced by the method (via the ASL)
+ * before it was initialized. Either case is an error.
+ */
+
+ /* If slack enabled, init the local_x/arg_x to an Integer of value zero */
+
+ if (acpi_gbl_enable_interpreter_slack) {
+ object = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!object) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ object->integer.value = 0;
+ node->object = object;
+ }
+
+ /* Otherwise, return the error */
+
+ else switch (opcode) {
+ case AML_ARG_OP:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n",
+ index, node));
+
+ return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG);
+
+ case AML_LOCAL_OP:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n",
+ index, node));
+
+ return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL);
+
+ default:
+ ACPI_REPORT_ERROR (("Not Arg/Local opcode: %X\n", opcode));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+ }
+
+ /*
+ * The Index points to an initialized and valid object.
+ * Return an additional reference to the object
+ */
+ *dest_desc = object;
+ acpi_ut_add_reference (object);
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_delete_value
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - which local_var or argument to delete
+ * walk_state - Current walk state object
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts
+ * a null into the stack slot after the object is deleted.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_method_data_delete_value (
+ u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *object;
+
+
+ ACPI_FUNCTION_TRACE ("ds_method_data_delete_value");
+
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ return_VOID;
+ }
+
+ /* Get the associated object */
+
+ object = acpi_ns_get_attached_object (node);
+
+ /*
+ * Undefine the Arg or Local by setting its descriptor
+ * pointer to NULL. Locals/Args can contain both
+ * ACPI_OPERAND_OBJECTS and ACPI_NAMESPACE_NODEs
+ */
+ node->object = NULL;
+
+ if ((object) &&
+ (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_OPERAND)) {
+ /*
+ * There is a valid object.
+ * Decrement the reference count by one to balance the
+ * increment when the object was stored.
+ */
+ acpi_ut_remove_reference (object);
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_store_object_to_local
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - which local_var or argument to set
+ * obj_desc - Value to be stored
+ * walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store a value in an Arg or Local. The obj_desc is installed
+ * as the new value for the Arg or Local and the reference count
+ * for obj_desc is incremented.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_store_object_to_local (
+ u16 opcode,
+ u32 index,
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *current_obj_desc;
+ union acpi_operand_object *new_obj_desc;
+
+
+ ACPI_FUNCTION_TRACE ("ds_store_object_to_local");
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode=%X Index=%d Obj=%p\n",
+ opcode, index, obj_desc));
+
+ /* Parameter validation */
+
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ current_obj_desc = acpi_ns_get_attached_object (node);
+ if (current_obj_desc == obj_desc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p already installed!\n",
+ obj_desc));
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * If the reference count on the object is more than one, we must
+ * take a copy of the object before we store. A reference count
+ * of exactly 1 means that the object was just created during the
+ * evaluation of an expression, and we can safely use it since it
+ * is not used anywhere else.
+ */
+ new_obj_desc = obj_desc;
+ if (obj_desc->common.reference_count > 1) {
+ status = acpi_ut_copy_iobject_to_iobject (obj_desc, &new_obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * If there is an object already in this slot, we either
+ * have to delete it, or if this is an argument and there
+ * is an object reference stored there, we have to do
+ * an indirect store!
+ */
+ if (current_obj_desc) {
+ /*
+ * Check for an indirect store if an argument
+ * contains an object reference (stored as an Node).
+ * We don't allow this automatic dereferencing for
+ * locals, since a store to a local should overwrite
+ * anything there, including an object reference.
+ *
+ * If both Arg0 and Local0 contain ref_of (Local4):
+ *
+ * Store (1, Arg0) - Causes indirect store to local4
+ * Store (1, Local0) - Stores 1 in local0, overwriting
+ * the reference to local4
+ * Store (1, de_refof (Local0)) - Causes indirect store to local4
+ *
+ * Weird, but true.
+ */
+ if (opcode == AML_ARG_OP) {
+ /*
+ * Make sure that the object is the correct type. This may be overkill, but
+ * it is here because references were NS nodes in the past. Now they are
+ * operand objects of type Reference.
+ */
+ if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+ ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n",
+ acpi_ut_get_descriptor_name (current_obj_desc)));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /*
+ * If we have a valid reference object that came from ref_of(), do the
+ * indirect store
+ */
+ if ((current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) &&
+ (current_obj_desc->reference.opcode == AML_REF_OF_OP)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Arg (%p) is an obj_ref(Node), storing in node %p\n",
+ new_obj_desc, current_obj_desc));
+
+ /*
+ * Store this object to the Node (perform the indirect store)
+ * NOTE: No implicit conversion is performed, as per the ACPI
+ * specification rules on storing to Locals/Args.
+ */
+ status = acpi_ex_store_object_to_node (new_obj_desc,
+ current_obj_desc->reference.object, walk_state,
+ ACPI_NO_IMPLICIT_CONVERSION);
+
+ /* Remove local reference if we copied the object above */
+
+ if (new_obj_desc != obj_desc) {
+ acpi_ut_remove_reference (new_obj_desc);
+ }
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Delete the existing object
+ * before storing the new one
+ */
+ acpi_ds_method_data_delete_value (opcode, index, walk_state);
+ }
+
+ /*
+ * Install the Obj descriptor (*new_obj_desc) into
+ * the descriptor for the Arg or Local.
+ * (increments the object reference count by one)
+ */
+ status = acpi_ds_method_data_set_value (opcode, index, new_obj_desc, walk_state);
+
+ /* Remove local reference if we copied the object above */
+
+ if (new_obj_desc != obj_desc) {
+ acpi_ut_remove_reference (new_obj_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
new file mode 100644
index 000000000000..eb8af4785bcb
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -0,0 +1,618 @@
+/******************************************************************************
+ *
+ * Module Name: dsobject - Dispatcher object management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dsobject")
+
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_build_internal_object
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser object to be translated
+ * obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op object to the equivalent namespace object
+ * Simple objects are any objects other than a package object!
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_build_internal_object (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ union acpi_operand_object **obj_desc_ptr)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ds_build_internal_object");
+
+
+ *obj_desc_ptr = NULL;
+ if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ /*
+ * This is an named object reference. If this name was
+ * previously looked up in the namespace, it was stored in this op.
+ * Otherwise, go ahead and look it up now
+ */
+ if (!op->common.node) {
+ status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL,
+ (struct acpi_namespace_node **) &(op->common.node));
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (op->common.value.string, status);
+ return_ACPI_STATUS (status);
+ }
+ }
+ }
+
+ /* Create and init the internal ACPI object */
+
+ obj_desc = acpi_ut_create_internal_object ((acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+ }
+
+ *obj_desc_ptr = obj_desc;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_build_internal_buffer_obj
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser object to be translated
+ * buffer_length - Length of the buffer
+ * obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op package object to the equivalent
+ * namespace object
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_build_internal_buffer_obj (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u32 buffer_length,
+ union acpi_operand_object **obj_desc_ptr)
+{
+ union acpi_parse_object *arg;
+ union acpi_operand_object *obj_desc;
+ union acpi_parse_object *byte_list;
+ u32 byte_list_length = 0;
+
+
+ ACPI_FUNCTION_TRACE ("ds_build_internal_buffer_obj");
+
+
+ obj_desc = *obj_desc_ptr;
+ if (obj_desc) {
+ /*
+ * We are evaluating a Named buffer object "Name (xxxx, Buffer)".
+ * The buffer object already exists (from the NS node)
+ */
+ }
+ else {
+ /* Create a new buffer object */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
+ *obj_desc_ptr = obj_desc;
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+ }
+
+ /*
+ * Second arg is the buffer data (optional) byte_list can be either
+ * individual bytes or a string initializer. In either case, a
+ * byte_list appears in the AML.
+ */
+ arg = op->common.value.arg; /* skip first arg */
+
+ byte_list = arg->named.next;
+ if (byte_list) {
+ if (byte_list->common.aml_opcode != AML_INT_BYTELIST_OP) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Expecting bytelist, got AML opcode %X in op %p\n",
+ byte_list->common.aml_opcode, byte_list));
+
+ acpi_ut_remove_reference (obj_desc);
+ return (AE_TYPE);
+ }
+
+ byte_list_length = (u32) byte_list->common.value.integer;
+ }
+
+ /*
+ * The buffer length (number of bytes) will be the larger of:
+ * 1) The specified buffer length and
+ * 2) The length of the initializer byte list
+ */
+ obj_desc->buffer.length = buffer_length;
+ if (byte_list_length > buffer_length) {
+ obj_desc->buffer.length = byte_list_length;
+ }
+
+ /* Allocate the buffer */
+
+ if (obj_desc->buffer.length == 0) {
+ obj_desc->buffer.pointer = NULL;
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Buffer defined with zero length in AML, creating\n"));
+ }
+ else {
+ obj_desc->buffer.pointer = ACPI_MEM_CALLOCATE (
+ obj_desc->buffer.length);
+ if (!obj_desc->buffer.pointer) {
+ acpi_ut_delete_object_desc (obj_desc);
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Initialize buffer from the byte_list (if present) */
+
+ if (byte_list) {
+ ACPI_MEMCPY (obj_desc->buffer.pointer, byte_list->named.data,
+ byte_list_length);
+ }
+ }
+
+ obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
+ op->common.node = (struct acpi_namespace_node *) obj_desc;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_build_internal_package_obj
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser object to be translated
+ * package_length - Number of elements in the package
+ * obj_desc_ptr - Where the ACPI internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parser Op package object to the equivalent
+ * namespace object
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_build_internal_package_obj (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u32 package_length,
+ union acpi_operand_object **obj_desc_ptr)
+{
+ union acpi_parse_object *arg;
+ union acpi_parse_object *parent;
+ union acpi_operand_object *obj_desc = NULL;
+ u32 package_list_length;
+ acpi_status status = AE_OK;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ds_build_internal_package_obj");
+
+
+ /* Find the parent of a possibly nested package */
+
+ parent = op->common.parent;
+ while ((parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
+ parent = parent->common.parent;
+ }
+
+ obj_desc = *obj_desc_ptr;
+ if (obj_desc) {
+ /*
+ * We are evaluating a Named package object "Name (xxxx, Package)".
+ * Get the existing package object from the NS node
+ */
+ }
+ else {
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE);
+ *obj_desc_ptr = obj_desc;
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ obj_desc->package.node = parent->common.node;
+ }
+
+ obj_desc->package.count = package_length;
+
+ /* Count the number of items in the package list */
+
+ package_list_length = 0;
+ arg = op->common.value.arg;
+ arg = arg->common.next;
+ while (arg) {
+ package_list_length++;
+ arg = arg->common.next;
+ }
+
+ /*
+ * The package length (number of elements) will be the greater
+ * of the specified length and the length of the initializer list
+ */
+ if (package_list_length > package_length) {
+ obj_desc->package.count = package_list_length;
+ }
+
+ /*
+ * Allocate the pointer array (array of pointers to the
+ * individual objects). Add an extra pointer slot so
+ * that the list is always null terminated.
+ */
+ obj_desc->package.elements = ACPI_MEM_CALLOCATE (
+ ((acpi_size) obj_desc->package.count + 1) * sizeof (void *));
+
+ if (!obj_desc->package.elements) {
+ acpi_ut_delete_object_desc (obj_desc);
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Now init the elements of the package
+ */
+ i = 0;
+ arg = op->common.value.arg;
+ arg = arg->common.next;
+ while (arg) {
+ if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+ /* Object (package or buffer) is already built */
+
+ obj_desc->package.elements[i] = ACPI_CAST_PTR (union acpi_operand_object, arg->common.node);
+ }
+ else {
+ status = acpi_ds_build_internal_object (walk_state, arg,
+ &obj_desc->package.elements[i]);
+ }
+
+ i++;
+ arg = arg->common.next;
+ }
+
+ obj_desc->package.flags |= AOPOBJ_DATA_VALID;
+ op->common.node = (struct acpi_namespace_node *) obj_desc;
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_node
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Node - NS Node to be initialized
+ * Op - Parser object to be translated
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create the object to be associated with a namespace node
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_create_node (
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node *node,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_create_node", op);
+
+
+ /*
+ * Because of the execution pass through the non-control-method
+ * parts of the table, we can arrive here twice. Only init
+ * the named object node the first time through
+ */
+ if (acpi_ns_get_attached_object (node)) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ if (!op->common.value.arg) {
+ /* No arguments, there is nothing to do */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Build an internal object for the argument(s) */
+
+ status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Re-type the object according to its argument */
+
+ node->type = ACPI_GET_OBJECT_TYPE (obj_desc);
+
+ /* Attach obj to node */
+
+ status = acpi_ns_attach_object (node, obj_desc, node->type);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+#endif /* ACPI_NO_METHOD_EXECUTION */
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_object_from_op
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Op - Parser op used to init the internal object
+ * Opcode - AML opcode associated with the object
+ * ret_obj_desc - Namespace object to be initialized
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize a namespace object from a parser Op and its
+ * associated arguments. The namespace object is a more compact
+ * representation of the Op and its arguments.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_init_object_from_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ u16 opcode,
+ union acpi_operand_object **ret_obj_desc)
+{
+ const struct acpi_opcode_info *op_info;
+ union acpi_operand_object *obj_desc;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ds_init_object_from_op");
+
+
+ obj_desc = *ret_obj_desc;
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (op_info->class == AML_CLASS_UNKNOWN) {
+ /* Unknown opcode */
+
+ return_ACPI_STATUS (AE_TYPE);
+ }
+
+ /* Perform per-object initialization */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * Defer evaluation of Buffer term_arg operand
+ */
+ obj_desc->buffer.node = (struct acpi_namespace_node *) walk_state->operands[0];
+ obj_desc->buffer.aml_start = op->named.data;
+ obj_desc->buffer.aml_length = op->named.length;
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * Defer evaluation of Package term_arg operand
+ */
+ obj_desc->package.node = (struct acpi_namespace_node *) walk_state->operands[0];
+ obj_desc->package.aml_start = op->named.data;
+ obj_desc->package.aml_length = op->named.length;
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+
+ switch (op_info->type) {
+ case AML_TYPE_CONSTANT:
+ /*
+ * Resolve AML Constants here - AND ONLY HERE!
+ * All constants are integers.
+ * We mark the integer with a flag that indicates that it started life
+ * as a constant -- so that stores to constants will perform as expected (noop).
+ * (zero_op is used as a placeholder for optional target operands.)
+ */
+ obj_desc->common.flags = AOPOBJ_AML_CONSTANT;
+
+ switch (opcode) {
+ case AML_ZERO_OP:
+
+ obj_desc->integer.value = 0;
+ break;
+
+ case AML_ONE_OP:
+
+ obj_desc->integer.value = 1;
+ break;
+
+ case AML_ONES_OP:
+
+ obj_desc->integer.value = ACPI_INTEGER_MAX;
+
+ /* Truncate value if we are executing from a 32-bit ACPI table */
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ acpi_ex_truncate_for32bit_table (obj_desc);
+#endif
+ break;
+
+ case AML_REVISION_OP:
+
+ obj_desc->integer.value = ACPI_CA_VERSION;
+ break;
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode));
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+ break;
+
+
+ case AML_TYPE_LITERAL:
+
+ obj_desc->integer.value = op->common.value.integer;
+ break;
+
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type));
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ obj_desc->string.pointer = op->common.value.string;
+ obj_desc->string.length = (u32) ACPI_STRLEN (op->common.value.string);
+
+ /*
+ * The string is contained in the ACPI table, don't ever try
+ * to delete it
+ */
+ obj_desc->common.flags |= AOPOBJ_STATIC_POINTER;
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ switch (op_info->type) {
+ case AML_TYPE_LOCAL_VARIABLE:
+
+ /* Split the opcode into a base opcode + offset */
+
+ obj_desc->reference.opcode = AML_LOCAL_OP;
+ obj_desc->reference.offset = opcode - AML_LOCAL_OP;
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset,
+ walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object);
+#endif
+ break;
+
+
+ case AML_TYPE_METHOD_ARGUMENT:
+
+ /* Split the opcode into a base opcode + offset */
+
+ obj_desc->reference.opcode = AML_ARG_OP;
+ obj_desc->reference.offset = opcode - AML_ARG_OP;
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset,
+ walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object);
+#endif
+ break;
+
+ default: /* Other literals, etc.. */
+
+ if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ /* Node was saved in Op */
+
+ obj_desc->reference.node = op->common.node;
+ }
+
+ obj_desc->reference.opcode = opcode;
+ break;
+ }
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unimplemented data type: %X\n",
+ ACPI_GET_OBJECT_TYPE (obj_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
new file mode 100644
index 000000000000..5c987a0e7b75
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -0,0 +1,1151 @@
+/******************************************************************************
+ *
+ * Module Name: dsopcode - Dispatcher Op Region support and handling of
+ * "control" opcodes
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dsopcode")
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_execute_arguments
+ *
+ * PARAMETERS: Node - Parent NS node
+ * aml_length - Length of executable AML
+ * aml_start - Pointer to the AML
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Late (deferred) execution of region or field arguments
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_execute_arguments (
+ struct acpi_namespace_node *node,
+ struct acpi_namespace_node *scope_node,
+ u32 aml_length,
+ u8 *aml_start)
+{
+ acpi_status status;
+ union acpi_parse_object *op;
+ struct acpi_walk_state *walk_state;
+
+
+ ACPI_FUNCTION_TRACE ("ds_execute_arguments");
+
+
+ /*
+ * Allocate a new parser op to be the root of the parsed tree
+ */
+ op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP);
+ if (!op) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Save the Node for use in acpi_ps_parse_aml */
+
+ op->common.node = scope_node;
+
+ /* Create and initialize a new parser state */
+
+ walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL);
+ if (!walk_state) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start,
+ aml_length, NULL, 1);
+ if (ACPI_FAILURE (status)) {
+ acpi_ds_delete_walk_state (walk_state);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Mark this parse as a deferred opcode */
+
+ walk_state->parse_flags = ACPI_PARSE_DEFERRED_OP;
+ walk_state->deferred_node = node;
+
+ /* Pass1: Parse the entire declaration */
+
+ status = acpi_ps_parse_aml (walk_state);
+ if (ACPI_FAILURE (status)) {
+ acpi_ps_delete_parse_tree (op);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get and init the Op created above */
+
+ op->common.node = node;
+ acpi_ps_delete_parse_tree (op);
+
+ /* Evaluate the deferred arguments */
+
+ op = acpi_ps_alloc_op (AML_INT_EVAL_SUBTREE_OP);
+ if (!op) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ op->common.node = scope_node;
+
+ /* Create and initialize a new parser state */
+
+ walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL);
+ if (!walk_state) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Execute the opcode and arguments */
+
+ status = acpi_ds_init_aml_walk (walk_state, op, NULL, aml_start,
+ aml_length, NULL, 3);
+ if (ACPI_FAILURE (status)) {
+ acpi_ds_delete_walk_state (walk_state);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Mark this execution as a deferred opcode */
+
+ walk_state->deferred_node = node;
+ status = acpi_ps_parse_aml (walk_state);
+ acpi_ps_delete_parse_tree (op);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_buffer_field_arguments
+ *
+ * PARAMETERS: obj_desc - A valid buffer_field object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get buffer_field Buffer and Index. This implements the late
+ * evaluation of these field attributes.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_buffer_field_arguments (
+ union acpi_operand_object *obj_desc)
+{
+ union acpi_operand_object *extra_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_get_buffer_field_arguments", obj_desc);
+
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Get the AML pointer (method object) and buffer_field node */
+
+ extra_desc = acpi_ns_get_secondary_object (obj_desc);
+ node = obj_desc->buffer_field.node;
+
+ ACPI_DEBUG_EXEC(acpi_ut_display_init_pathname (ACPI_TYPE_BUFFER_FIELD, node, NULL));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] buffer_field Arg Init\n",
+ acpi_ut_get_node_name (node)));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node),
+ extra_desc->extra.aml_length, extra_desc->extra.aml_start);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_buffer_arguments
+ *
+ * PARAMETERS: obj_desc - A valid Buffer object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get Buffer length and initializer byte list. This implements
+ * the late evaluation of these attributes.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_buffer_arguments (
+ union acpi_operand_object *obj_desc)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_get_buffer_arguments", obj_desc);
+
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Get the Buffer node */
+
+ node = obj_desc->buffer.node;
+ if (!node) {
+ ACPI_REPORT_ERROR ((
+ "No pointer back to NS node in buffer obj %p\n", obj_desc));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Buffer Arg Init\n"));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments (node, node,
+ obj_desc->buffer.aml_length, obj_desc->buffer.aml_start);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_package_arguments
+ *
+ * PARAMETERS: obj_desc - A valid Package object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get Package length and initializer byte list. This implements
+ * the late evaluation of these attributes.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_package_arguments (
+ union acpi_operand_object *obj_desc)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_get_package_arguments", obj_desc);
+
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Get the Package node */
+
+ node = obj_desc->package.node;
+ if (!node) {
+ ACPI_REPORT_ERROR ((
+ "No pointer back to NS node in package %p\n", obj_desc));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Package Arg Init\n"));
+
+ /* Execute the AML code for the term_arg arguments */
+
+ status = acpi_ds_execute_arguments (node, node,
+ obj_desc->package.aml_length, obj_desc->package.aml_start);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_region_arguments
+ *
+ * PARAMETERS: obj_desc - A valid region object
+ *
+ * RETURN: Status.
+ *
+ * DESCRIPTION: Get region address and length. This implements the late
+ * evaluation of these region attributes.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_region_arguments (
+ union acpi_operand_object *obj_desc)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ union acpi_operand_object *extra_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_get_region_arguments", obj_desc);
+
+
+ if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ extra_desc = acpi_ns_get_secondary_object (obj_desc);
+ if (!extra_desc) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /* Get the Region node */
+
+ node = obj_desc->region.node;
+
+ ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_REGION, node, NULL));
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s] op_region Arg Init at AML %p\n",
+ acpi_ut_get_node_name (node), extra_desc->extra.aml_start));
+
+ /* Execute the argument AML */
+
+ status = acpi_ds_execute_arguments (node, acpi_ns_get_parent_node (node),
+ extra_desc->extra.aml_length, extra_desc->extra.aml_start);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_initialize_region
+ *
+ * PARAMETERS: Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Front end to ev_initialize_region
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_initialize_region (
+ acpi_handle obj_handle)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ obj_desc = acpi_ns_get_attached_object (obj_handle);
+
+ /* Namespace is NOT locked */
+
+ status = acpi_ev_initialize_region (obj_desc, FALSE);
+ return (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_buffer_field
+ *
+ * PARAMETERS: aml_opcode - create_xxx_field
+ * obj_desc - buffer_field object
+ * buffer_desc - Host Buffer
+ * offset_desc - Offset into buffer
+ * Length - Length of field (CREATE_FIELD_OP only)
+ * Result - Where to store the result
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform actual initialization of a buffer field
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_init_buffer_field (
+ u16 aml_opcode,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object *buffer_desc,
+ union acpi_operand_object *offset_desc,
+ union acpi_operand_object *length_desc,
+ union acpi_operand_object *result_desc)
+{
+ u32 offset;
+ u32 bit_offset;
+ u32 bit_count;
+ u8 field_flags;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_init_buffer_field", obj_desc);
+
+
+ /* Host object must be a Buffer */
+
+ if (ACPI_GET_OBJECT_TYPE (buffer_desc) != ACPI_TYPE_BUFFER) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Target of Create Field is not a Buffer object - %s\n",
+ acpi_ut_get_object_type_name (buffer_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * The last parameter to all of these opcodes (result_desc) started
+ * out as a name_string, and should therefore now be a NS node
+ * after resolution in acpi_ex_resolve_operands().
+ */
+ if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination not a NS Node [%s]\n",
+ acpi_ps_get_opcode_name (aml_opcode), acpi_ut_get_descriptor_name (result_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ offset = (u32) offset_desc->integer.value;
+
+ /*
+ * Setup the Bit offsets and counts, according to the opcode
+ */
+ switch (aml_opcode) {
+ case AML_CREATE_FIELD_OP:
+
+ /* Offset is in bits, count is in bits */
+
+ bit_offset = offset;
+ bit_count = (u32) length_desc->integer.value;
+ field_flags = AML_FIELD_ACCESS_BYTE;
+ break;
+
+ case AML_CREATE_BIT_FIELD_OP:
+
+ /* Offset is in bits, Field is one bit */
+
+ bit_offset = offset;
+ bit_count = 1;
+ field_flags = AML_FIELD_ACCESS_BYTE;
+ break;
+
+ case AML_CREATE_BYTE_FIELD_OP:
+
+ /* Offset is in bytes, field is one byte */
+
+ bit_offset = 8 * offset;
+ bit_count = 8;
+ field_flags = AML_FIELD_ACCESS_BYTE;
+ break;
+
+ case AML_CREATE_WORD_FIELD_OP:
+
+ /* Offset is in bytes, field is one word */
+
+ bit_offset = 8 * offset;
+ bit_count = 16;
+ field_flags = AML_FIELD_ACCESS_WORD;
+ break;
+
+ case AML_CREATE_DWORD_FIELD_OP:
+
+ /* Offset is in bytes, field is one dword */
+
+ bit_offset = 8 * offset;
+ bit_count = 32;
+ field_flags = AML_FIELD_ACCESS_DWORD;
+ break;
+
+ case AML_CREATE_QWORD_FIELD_OP:
+
+ /* Offset is in bytes, field is one qword */
+
+ bit_offset = 8 * offset;
+ bit_count = 64;
+ field_flags = AML_FIELD_ACCESS_QWORD;
+ break;
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown field creation opcode %02x\n",
+ aml_opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+ /* Entire field must fit within the current length of the buffer */
+
+ if ((bit_offset + bit_count) >
+ (8 * (u32) buffer_desc->buffer.length)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Field [%4.4s] size %d exceeds Buffer [%4.4s] size %d (bits)\n",
+ acpi_ut_get_node_name (result_desc),
+ bit_offset + bit_count,
+ acpi_ut_get_node_name (buffer_desc->buffer.node),
+ 8 * (u32) buffer_desc->buffer.length));
+ status = AE_AML_BUFFER_LIMIT;
+ goto cleanup;
+ }
+
+ /*
+ * Initialize areas of the field object that are common to all fields
+ * For field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE)
+ */
+ status = acpi_ex_prep_common_field_object (obj_desc, field_flags, 0,
+ bit_offset, bit_count);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ obj_desc->buffer_field.buffer_obj = buffer_desc;
+
+ /* Reference count for buffer_desc inherits obj_desc count */
+
+ buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count +
+ obj_desc->common.reference_count);
+
+
+cleanup:
+
+ /* Always delete the operands */
+
+ acpi_ut_remove_reference (offset_desc);
+ acpi_ut_remove_reference (buffer_desc);
+
+ if (aml_opcode == AML_CREATE_FIELD_OP) {
+ acpi_ut_remove_reference (length_desc);
+ }
+
+ /* On failure, delete the result descriptor */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (result_desc); /* Result descriptor */
+ }
+ else {
+ /* Now the address and length are valid for this buffer_field */
+
+ obj_desc->buffer_field.flags |= AOPOBJ_DATA_VALID;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_buffer_field_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid buffer_field Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get buffer_field Buffer and Index
+ * Called from acpi_ds_exec_end_op during buffer_field parse tree walk
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_eval_buffer_field_operands (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_eval_buffer_field_operands", op);
+
+
+ /*
+ * This is where we evaluate the address and length fields of the
+ * create_xxx_field declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to the op that holds the Buffer */
+
+ next_op = op->common.value.arg;
+
+ /* Evaluate/create the address and length operands */
+
+ status = acpi_ds_create_operands (walk_state, next_op);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /* Resolve the operands */
+
+ status = acpi_ex_resolve_operands (op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
+
+ ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name (op->common.aml_opcode),
+ walk_state->num_operands, "after acpi_ex_resolve_operands");
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) bad operand(s) (%X)\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode), status));
+
+ return_ACPI_STATUS (status);
+ }
+
+ /* Initialize the Buffer Field */
+
+ if (op->common.aml_opcode == AML_CREATE_FIELD_OP) {
+ /* NOTE: Slightly different operands for this opcode */
+
+ status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc,
+ walk_state->operands[0], walk_state->operands[1],
+ walk_state->operands[2], walk_state->operands[3]);
+ }
+ else {
+ /* All other, create_xxx_field opcodes */
+
+ status = acpi_ds_init_buffer_field (op->common.aml_opcode, obj_desc,
+ walk_state->operands[0], walk_state->operands[1],
+ NULL, walk_state->operands[2]);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_region_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid region Op object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get region address and length
+ * Called from acpi_ds_exec_end_op during op_region parse tree walk
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_eval_region_operands (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *operand_desc;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *next_op;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_eval_region_operands", op);
+
+
+ /*
+ * This is where we evaluate the address and length fields of the op_region declaration
+ */
+ node = op->common.node;
+
+ /* next_op points to the op that holds the space_iD */
+
+ next_op = op->common.value.arg;
+
+ /* next_op points to address op */
+
+ next_op = next_op->common.next;
+
+ /* Evaluate/create the address and length operands */
+
+ status = acpi_ds_create_operands (walk_state, next_op);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Resolve the length and address operands to numbers */
+
+ status = acpi_ex_resolve_operands (op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name (op->common.aml_opcode),
+ 1, "after acpi_ex_resolve_operands");
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /*
+ * Get the length operand and save it
+ * (at Top of stack)
+ */
+ operand_desc = walk_state->operands[walk_state->num_operands - 1];
+
+ obj_desc->region.length = (u32) operand_desc->integer.value;
+ acpi_ut_remove_reference (operand_desc);
+
+ /*
+ * Get the address and save it
+ * (at top of stack - 1)
+ */
+ operand_desc = walk_state->operands[walk_state->num_operands - 2];
+
+ obj_desc->region.address = (acpi_physical_address) operand_desc->integer.value;
+ acpi_ut_remove_reference (operand_desc);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n",
+ obj_desc,
+ ACPI_FORMAT_UINT64 (obj_desc->region.address),
+ obj_desc->region.length));
+
+ /* Now the address and length are valid for this opregion */
+
+ obj_desc->region.flags |= AOPOBJ_DATA_VALID;
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_eval_data_object_operands
+ *
+ * PARAMETERS: walk_state - Current walk
+ * Op - A valid data_object Op object
+ * obj_desc - data_object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the operands and complete the following data object types:
+ * Buffer, Package.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_eval_data_object_operands (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status;
+ union acpi_operand_object *arg_desc;
+ u32 length;
+
+
+ ACPI_FUNCTION_TRACE ("ds_eval_data_object_operands");
+
+
+ /* The first operand (for all of these data objects) is the length */
+
+ status = acpi_ds_create_operand (walk_state, op->common.value.arg, 1);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ex_resolve_operands (walk_state->opcode,
+ &(walk_state->operands [walk_state->num_operands -1]),
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Extract length operand */
+
+ arg_desc = walk_state->operands [walk_state->num_operands - 1];
+ length = (u32) arg_desc->integer.value;
+
+ /* Cleanup for length operand */
+
+ status = acpi_ds_obj_stack_pop (1, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ acpi_ut_remove_reference (arg_desc);
+
+ /*
+ * Create the actual data object
+ */
+ switch (op->common.aml_opcode) {
+ case AML_BUFFER_OP:
+
+ status = acpi_ds_build_internal_buffer_obj (walk_state, op, length, &obj_desc);
+ break;
+
+ case AML_PACKAGE_OP:
+ case AML_VAR_PACKAGE_OP:
+
+ status = acpi_ds_build_internal_package_obj (walk_state, op, length, &obj_desc);
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_AML_BAD_OPCODE);
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Return the object in the walk_state, unless the parent is a package --
+ * in this case, the return object will be stored in the parse tree
+ * for the package.
+ */
+ if ((!op->common.parent) ||
+ ((op->common.parent->common.aml_opcode != AML_PACKAGE_OP) &&
+ (op->common.parent->common.aml_opcode != AML_VAR_PACKAGE_OP) &&
+ (op->common.parent->common.aml_opcode != AML_NAME_OP))) {
+ walk_state->result_obj = obj_desc;
+ }
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_begin_control_op
+ *
+ * PARAMETERS: walk_list - The list that owns the walk stack
+ * Op - The control Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ * execution.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_exec_begin_control_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status = AE_OK;
+ union acpi_generic_state *control_state;
+
+
+ ACPI_FUNCTION_NAME ("ds_exec_begin_control_op");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p Opcode=%2.2X State=%p\n", op,
+ op->common.aml_opcode, walk_state));
+
+ switch (op->common.aml_opcode) {
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+
+ /*
+ * IF/WHILE: Create a new control state to manage these
+ * constructs. We need to manage these as a stack, in order
+ * to handle nesting.
+ */
+ control_state = acpi_ut_create_control_state ();
+ if (!control_state) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+ /*
+ * Save a pointer to the predicate for multiple executions
+ * of a loop
+ */
+ control_state->control.aml_predicate_start = walk_state->parser_state.aml - 1;
+ control_state->control.package_end = walk_state->parser_state.pkg_end;
+ control_state->control.opcode = op->common.aml_opcode;
+
+
+ /* Push the control state on this walk's control stack */
+
+ acpi_ut_push_generic_state (&walk_state->control_state, control_state);
+ break;
+
+ case AML_ELSE_OP:
+
+ /* Predicate is in the state object */
+ /* If predicate is true, the IF was executed, ignore ELSE part */
+
+ if (walk_state->last_predicate) {
+ status = AE_CTRL_TRUE;
+ }
+
+ break;
+
+ case AML_RETURN_OP:
+
+ break;
+
+ default:
+ break;
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_end_control_op
+ *
+ * PARAMETERS: walk_list - The list that owns the walk stack
+ * Op - The control Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handles all control ops encountered during control method
+ * execution.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_exec_end_control_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ acpi_status status = AE_OK;
+ union acpi_generic_state *control_state;
+
+
+ ACPI_FUNCTION_NAME ("ds_exec_end_control_op");
+
+
+ switch (op->common.aml_opcode) {
+ case AML_IF_OP:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[IF_OP] Op=%p\n", op));
+
+ /*
+ * Save the result of the predicate in case there is an
+ * ELSE to come
+ */
+ walk_state->last_predicate =
+ (u8) walk_state->control_state->common.value;
+
+ /*
+ * Pop the control state that was created at the start
+ * of the IF and free it
+ */
+ control_state = acpi_ut_pop_generic_state (&walk_state->control_state);
+ acpi_ut_delete_generic_state (control_state);
+ break;
+
+
+ case AML_ELSE_OP:
+
+ break;
+
+
+ case AML_WHILE_OP:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] Op=%p\n", op));
+
+ if (walk_state->control_state->common.value) {
+ /* Predicate was true, go back and evaluate it again! */
+
+ status = AE_CTRL_PENDING;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op));
+
+ /* Pop this control state and free it */
+
+ control_state = acpi_ut_pop_generic_state (&walk_state->control_state);
+
+ walk_state->aml_last_while = control_state->control.aml_predicate_start;
+ acpi_ut_delete_generic_state (control_state);
+ break;
+
+
+ case AML_RETURN_OP:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "[RETURN_OP] Op=%p Arg=%p\n",op, op->common.value.arg));
+
+ /*
+ * One optional operand -- the return value
+ * It can be either an immediate operand or a result that
+ * has been bubbled up the tree
+ */
+ if (op->common.value.arg) {
+ /* Since we have a real Return(), delete any implicit return */
+
+ acpi_ds_clear_implicit_return (walk_state);
+
+ /* Return statement has an immediate operand */
+
+ status = acpi_ds_create_operands (walk_state, op->common.value.arg);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * If value being returned is a Reference (such as
+ * an arg or local), resolve it now because it may
+ * cease to exist at the end of the method.
+ */
+ status = acpi_ex_resolve_to_value (&walk_state->operands [0], walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Get the return value and save as the last result
+ * value. This is the only place where walk_state->return_desc
+ * is set to anything other than zero!
+ */
+ walk_state->return_desc = walk_state->operands[0];
+ }
+ else if ((walk_state->results) &&
+ (walk_state->results->results.num_results > 0)) {
+ /* Since we have a real Return(), delete any implicit return */
+
+ acpi_ds_clear_implicit_return (walk_state);
+
+ /*
+ * The return value has come from a previous calculation.
+ *
+ * If value being returned is a Reference (such as
+ * an arg or local), resolve it now because it may
+ * cease to exist at the end of the method.
+ *
+ * Allow references created by the Index operator to return unchanged.
+ */
+ if ((ACPI_GET_DESCRIPTOR_TYPE (walk_state->results->results.obj_desc[0]) == ACPI_DESC_TYPE_OPERAND) &&
+ (ACPI_GET_OBJECT_TYPE (walk_state->results->results.obj_desc [0]) == ACPI_TYPE_LOCAL_REFERENCE) &&
+ ((walk_state->results->results.obj_desc [0])->reference.opcode != AML_INDEX_OP)) {
+ status = acpi_ex_resolve_to_value (&walk_state->results->results.obj_desc [0], walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ walk_state->return_desc = walk_state->results->results.obj_desc [0];
+ }
+ else {
+ /* No return operand */
+
+ if (walk_state->num_operands) {
+ acpi_ut_remove_reference (walk_state->operands [0]);
+ }
+
+ walk_state->operands [0] = NULL;
+ walk_state->num_operands = 0;
+ walk_state->return_desc = NULL;
+ }
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Completed RETURN_OP State=%p, ret_val=%p\n",
+ walk_state, walk_state->return_desc));
+
+ /* End the control method execution right now */
+
+ status = AE_CTRL_TERMINATE;
+ break;
+
+
+ case AML_NOOP_OP:
+
+ /* Just do nothing! */
+ break;
+
+
+ case AML_BREAK_POINT_OP:
+
+ /* Call up to the OS service layer to handle this */
+
+ status = acpi_os_signal (ACPI_SIGNAL_BREAKPOINT, "Executed AML Breakpoint opcode");
+
+ /* If and when it returns, all done. */
+
+ break;
+
+
+ case AML_BREAK_OP:
+ case AML_CONTINUE_OP: /* ACPI 2.0 */
+
+
+ /* Pop and delete control states until we find a while */
+
+ while (walk_state->control_state &&
+ (walk_state->control_state->control.opcode != AML_WHILE_OP)) {
+ control_state = acpi_ut_pop_generic_state (&walk_state->control_state);
+ acpi_ut_delete_generic_state (control_state);
+ }
+
+ /* No while found? */
+
+ if (!walk_state->control_state) {
+ return (AE_AML_NO_WHILE);
+ }
+
+ /* Was: walk_state->aml_last_while = walk_state->control_state->Control.aml_predicate_start; */
+
+ walk_state->aml_last_while = walk_state->control_state->control.package_end;
+
+ /* Return status depending on opcode */
+
+ if (op->common.aml_opcode == AML_BREAK_OP) {
+ status = AE_CTRL_BREAK;
+ }
+ else {
+ status = AE_CTRL_CONTINUE;
+ }
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown control opcode=%X Op=%p\n",
+ op->common.aml_opcode, op));
+
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+ return (status);
+}
+
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
new file mode 100644
index 000000000000..462c5d83e747
--- /dev/null
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -0,0 +1,744 @@
+/*******************************************************************************
+ *
+ * Module Name: dsutils - Dispatcher utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acdebug.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dsutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_clear_implicit_return
+ *
+ * PARAMETERS: walk_state - Current State
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Clear and remove a reference on an implicit return value. Used
+ * to delete "stale" return values (if enabled, the return value
+ * from every operator is saved at least momentarily, in case the
+ * parent method exits.)
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_clear_implicit_return (
+ struct acpi_walk_state *walk_state)
+{
+ ACPI_FUNCTION_NAME ("ds_clear_implicit_return");
+
+
+ /*
+ * Slack must be enabled for this feature
+ */
+ if (!acpi_gbl_enable_interpreter_slack) {
+ return;
+ }
+
+ if (walk_state->implicit_return_obj) {
+ /*
+ * Delete any "stale" implicit return. However, in
+ * complex statements, the implicit return value can be
+ * bubbled up several levels.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Removing reference on stale implicit return obj %p\n",
+ walk_state->implicit_return_obj));
+
+ acpi_ut_remove_reference (walk_state->implicit_return_obj);
+ walk_state->implicit_return_obj = NULL;
+ }
+}
+
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_do_implicit_return
+ *
+ * PARAMETERS: return_desc - The return value
+ * walk_state - Current State
+ * add_reference - True if a reference should be added to the
+ * return object
+ *
+ * RETURN: TRUE if implicit return enabled, FALSE otherwise
+ *
+ * DESCRIPTION: Implements the optional "implicit return". We save the result
+ * of every ASL operator and control method invocation in case the
+ * parent method exit. Before storing a new return value, we
+ * delete the previous return value.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ds_do_implicit_return (
+ union acpi_operand_object *return_desc,
+ struct acpi_walk_state *walk_state,
+ u8 add_reference)
+{
+ ACPI_FUNCTION_NAME ("ds_do_implicit_return");
+
+
+ /*
+ * Slack must be enabled for this feature, and we must
+ * have a valid return object
+ */
+ if ((!acpi_gbl_enable_interpreter_slack) ||
+ (!return_desc)) {
+ return (FALSE);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Result %p will be implicitly returned; Prev=%p\n",
+ return_desc,
+ walk_state->implicit_return_obj));
+
+ /*
+ * Delete any "stale" implicit return value first. However, in
+ * complex statements, the implicit return value can be
+ * bubbled up several levels, so we don't clear the value if it
+ * is the same as the return_desc.
+ */
+ if (walk_state->implicit_return_obj) {
+ if (walk_state->implicit_return_obj == return_desc) {
+ return (TRUE);
+ }
+ acpi_ds_clear_implicit_return (walk_state);
+ }
+
+ /* Save the implicit return value, add a reference if requested */
+
+ walk_state->implicit_return_obj = return_desc;
+ if (add_reference) {
+ acpi_ut_add_reference (return_desc);
+ }
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_is_result_used
+ *
+ * PARAMETERS: Op - Current Op
+ * walk_state - Current State
+ *
+ * RETURN: TRUE if result is used, FALSE otherwise
+ *
+ * DESCRIPTION: Check if a result object will be used by the parent
+ *
+ ******************************************************************************/
+
+u8
+acpi_ds_is_result_used (
+ union acpi_parse_object *op,
+ struct acpi_walk_state *walk_state)
+{
+ const struct acpi_opcode_info *parent_info;
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_is_result_used", op);
+
+
+ /* Must have both an Op and a Result Object */
+
+ if (!op) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n"));
+ return_VALUE (TRUE);
+ }
+
+ /*
+ * We know that this operator is not a
+ * Return() operator (would not come here.) The following code is the
+ * optional support for a so-called "implicit return". Some AML code
+ * assumes that the last value of the method is "implicitly" returned
+ * to the caller. Just save the last result as the return value.
+ * NOTE: this is optional because the ASL language does not actually
+ * support this behavior.
+ */
+ acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE);
+
+ /*
+ * Now determine if the parent will use the result
+ *
+ * If there is no parent, or the parent is a scope_op, we are executing
+ * at the method level. An executing method typically has no parent,
+ * since each method is parsed separately. A method invoked externally
+ * via execute_control_method has a scope_op as the parent.
+ */
+ if ((!op->common.parent) ||
+ (op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
+ /* No parent, the return value cannot possibly be used */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode)));
+ return_VALUE (FALSE);
+ }
+
+ /* Get info on the parent. The root_op is AML_SCOPE */
+
+ parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode);
+ if (parent_info->class == AML_CLASS_UNKNOWN) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown parent opcode. Op=%p\n", op));
+ return_VALUE (FALSE);
+ }
+
+ /*
+ * Decide what to do with the result based on the parent. If
+ * the parent opcode will not use the result, delete the object.
+ * Otherwise leave it as is, it will be deleted when it is used
+ * as an operand later.
+ */
+ switch (parent_info->class) {
+ case AML_CLASS_CONTROL:
+
+ switch (op->common.parent->common.aml_opcode) {
+ case AML_RETURN_OP:
+
+ /* Never delete the return value associated with a return opcode */
+
+ goto result_used;
+
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+
+ /*
+ * If we are executing the predicate AND this is the predicate op,
+ * we will use the return value
+ */
+ if ((walk_state->control_state->common.state == ACPI_CONTROL_PREDICATE_EXECUTING) &&
+ (walk_state->control_state->control.predicate_op == op)) {
+ goto result_used;
+ }
+ break;
+
+ default:
+ /* Ignore other control opcodes */
+ break;
+ }
+
+ /* The general control opcode returns no result */
+
+ goto result_not_used;
+
+
+ case AML_CLASS_CREATE:
+
+ /*
+ * These opcodes allow term_arg(s) as operands and therefore
+ * the operands can be method calls. The result is used.
+ */
+ goto result_used;
+
+
+ case AML_CLASS_NAMED_OBJECT:
+
+ if ((op->common.parent->common.aml_opcode == AML_REGION_OP) ||
+ (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) ||
+ (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_BUFFER_OP) ||
+ (op->common.parent->common.aml_opcode == AML_INT_EVAL_SUBTREE_OP)) {
+ /*
+ * These opcodes allow term_arg(s) as operands and therefore
+ * the operands can be method calls. The result is used.
+ */
+ goto result_used;
+ }
+
+ goto result_not_used;
+
+
+ default:
+
+ /*
+ * In all other cases. the parent will actually use the return
+ * object, so keep it.
+ */
+ goto result_used;
+ }
+
+
+result_used:
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode),
+ acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op));
+
+ return_VALUE (TRUE);
+
+
+result_not_used:
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode),
+ acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op));
+
+ return_VALUE (FALSE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_delete_result_if_not_used
+ *
+ * PARAMETERS: Op - Current parse Op
+ * result_obj - Result of the operation
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Used after interpretation of an opcode. If there is an internal
+ * result descriptor, check if the parent opcode will actually use
+ * this result. If not, delete the result now so that it will
+ * not become orphaned.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_delete_result_if_not_used (
+ union acpi_parse_object *op,
+ union acpi_operand_object *result_obj,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_delete_result_if_not_used", result_obj);
+
+
+ if (!op) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Op\n"));
+ return_VOID;
+ }
+
+ if (!result_obj) {
+ return_VOID;
+ }
+
+ if (!acpi_ds_is_result_used (op, walk_state)) {
+ /* Must pop the result stack (obj_desc should be equal to result_obj) */
+
+ status = acpi_ds_result_pop (&obj_desc, walk_state);
+ if (ACPI_SUCCESS (status)) {
+ acpi_ut_remove_reference (result_obj);
+ }
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_resolve_operands
+ *
+ * PARAMETERS: walk_state - Current walk state with operands on stack
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Resolve all operands to their values. Used to prepare
+ * arguments to a control method invocation (a call from one
+ * method to another.)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_resolve_operands (
+ struct acpi_walk_state *walk_state)
+{
+ u32 i;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_resolve_operands", walk_state);
+
+
+ /*
+ * Attempt to resolve each of the valid operands
+ * Method arguments are passed by reference, not by value. This means
+ * that the actual objects are passed, not copies of the objects.
+ */
+ for (i = 0; i < walk_state->num_operands; i++) {
+ status = acpi_ex_resolve_to_value (&walk_state->operands[i], walk_state);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_clear_operands
+ *
+ * PARAMETERS: walk_state - Current walk state with operands on stack
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Clear all operands on the current walk state operand stack.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_clear_operands (
+ struct acpi_walk_state *walk_state)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_clear_operands", walk_state);
+
+
+ /* Remove a reference on each operand on the stack */
+
+ for (i = 0; i < walk_state->num_operands; i++) {
+ /*
+ * Remove a reference to all operands, including both
+ * "Arguments" and "Targets".
+ */
+ acpi_ut_remove_reference (walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+
+ walk_state->num_operands = 0;
+ return_VOID;
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_operand
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * Arg - Parse object for the argument
+ * arg_index - Which argument (zero based)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a parse tree object that is an argument to an AML
+ * opcode to the equivalent interpreter object. This may include
+ * looking up a name or entering a new name into the internal
+ * namespace.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_operand (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *arg,
+ u32 arg_index)
+{
+ acpi_status status = AE_OK;
+ char *name_string;
+ u32 name_length;
+ union acpi_operand_object *obj_desc;
+ union acpi_parse_object *parent_op;
+ u16 opcode;
+ acpi_interpreter_mode interpreter_mode;
+ const struct acpi_opcode_info *op_info;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_create_operand", arg);
+
+
+ /* A valid name must be looked up in the namespace */
+
+ if ((arg->common.aml_opcode == AML_INT_NAMEPATH_OP) &&
+ (arg->common.value.string)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Getting a name: Arg=%p\n", arg));
+
+ /* Get the entire name string from the AML stream */
+
+ status = acpi_ex_get_name_string (ACPI_TYPE_ANY, arg->common.value.buffer,
+ &name_string, &name_length);
+
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* All prefixes have been handled, and the name is in name_string */
+
+ /*
+ * Special handling for buffer_field declarations. This is a deferred
+ * opcode that unfortunately defines the field name as the last
+ * parameter instead of the first. We get here when we are performing
+ * the deferred execution, so the actual name of the field is already
+ * in the namespace. We don't want to attempt to look it up again
+ * because we may be executing in a different scope than where the
+ * actual opcode exists.
+ */
+ if ((walk_state->deferred_node) &&
+ (walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) &&
+ (arg_index != 0)) {
+ obj_desc = ACPI_CAST_PTR (union acpi_operand_object, walk_state->deferred_node);
+ status = AE_OK;
+ }
+ else /* All other opcodes */ {
+ /*
+ * Differentiate between a namespace "create" operation
+ * versus a "lookup" operation (IMODE_LOAD_PASS2 vs.
+ * IMODE_EXECUTE) in order to support the creation of
+ * namespace objects during the execution of control methods.
+ */
+ parent_op = arg->common.parent;
+ op_info = acpi_ps_get_opcode_info (parent_op->common.aml_opcode);
+ if ((op_info->flags & AML_NSNODE) &&
+ (parent_op->common.aml_opcode != AML_INT_METHODCALL_OP) &&
+ (parent_op->common.aml_opcode != AML_REGION_OP) &&
+ (parent_op->common.aml_opcode != AML_INT_NAMEPATH_OP)) {
+ /* Enter name into namespace if not found */
+
+ interpreter_mode = ACPI_IMODE_LOAD_PASS2;
+ }
+ else {
+ /* Return a failure if name not found */
+
+ interpreter_mode = ACPI_IMODE_EXECUTE;
+ }
+
+ status = acpi_ns_lookup (walk_state->scope_info, name_string,
+ ACPI_TYPE_ANY, interpreter_mode,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ walk_state,
+ ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &obj_desc));
+ /*
+ * The only case where we pass through (ignore) a NOT_FOUND
+ * error is for the cond_ref_of opcode.
+ */
+ if (status == AE_NOT_FOUND) {
+ if (parent_op->common.aml_opcode == AML_COND_REF_OF_OP) {
+ /*
+ * For the Conditional Reference op, it's OK if
+ * the name is not found; We just need a way to
+ * indicate this to the interpreter, set the
+ * object to the root
+ */
+ obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node);
+ status = AE_OK;
+ }
+ else {
+ /*
+ * We just plain didn't find it -- which is a
+ * very serious error at this point
+ */
+ status = AE_AML_NAME_NOT_FOUND;
+ }
+ }
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (name_string, status);
+ }
+ }
+
+ /* Free the namestring created above */
+
+ ACPI_MEM_FREE (name_string);
+
+ /* Check status from the lookup */
+
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Put the resulting object onto the current object stack */
+
+ status = acpi_ds_obj_stack_push (obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state));
+ }
+ else {
+ /* Check for null name case */
+
+ if (arg->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ /*
+ * If the name is null, this means that this is an
+ * optional result parameter that was not specified
+ * in the original ASL. Create a Zero Constant for a
+ * placeholder. (Store to a constant is a Noop.)
+ */
+ opcode = AML_ZERO_OP; /* Has no arguments! */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg));
+ }
+ else {
+ opcode = arg->common.aml_opcode;
+ }
+
+ /* Get the object type of the argument */
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (op_info->object_type == ACPI_TYPE_INVALID) {
+ return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
+ }
+
+ if (op_info->flags & AML_HAS_RETVAL) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Argument previously created, already stacked \n"));
+
+ ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (
+ walk_state->operands [walk_state->num_operands - 1], walk_state));
+
+ /*
+ * Use value that was already previously returned
+ * by the evaluation of this argument
+ */
+ status = acpi_ds_result_pop_from_bottom (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ /*
+ * Only error is underflow, and this indicates
+ * a missing or null operand!
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Missing or null operand, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+ }
+ else {
+ /* Create an ACPI_INTERNAL_OBJECT for the argument */
+
+ obj_desc = acpi_ut_create_internal_object (op_info->object_type);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Initialize the new object */
+
+ status = acpi_ds_init_object_from_op (walk_state, arg,
+ opcode, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_delete_object_desc (obj_desc);
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Put the operand object on the object stack */
+
+ status = acpi_ds_obj_stack_push (obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUGGER_EXEC (acpi_db_display_argument_object (obj_desc, walk_state));
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_operands
+ *
+ * PARAMETERS: walk_state - Current state
+ * first_arg - First argument of a parser argument tree
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an operator's arguments from a parse tree format to
+ * namespace objects and place those argument object on the object
+ * stack in preparation for evaluation by the interpreter.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_create_operands (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *first_arg)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *arg;
+ u32 arg_count = 0;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_create_operands", first_arg);
+
+
+ /* For all arguments in the list... */
+
+ arg = first_arg;
+ while (arg) {
+ status = acpi_ds_create_operand (walk_state, arg, arg_count);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Arg #%d (%p) done, Arg1=%p\n",
+ arg_count, arg, first_arg));
+
+ /* Move on to next argument, if any */
+
+ arg = arg->common.next;
+ arg_count++;
+ }
+
+ return_ACPI_STATUS (status);
+
+
+cleanup:
+ /*
+ * We must undo everything done above; meaning that we must
+ * pop everything off of the operand stack and delete those
+ * objects
+ */
+ (void) acpi_ds_obj_stack_pop_and_delete (arg_count, walk_state);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "While creating Arg %d - %s\n",
+ (arg_count + 1), acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
new file mode 100644
index 000000000000..2071a0d2bbbb
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -0,0 +1,751 @@
+/******************************************************************************
+ *
+ * Module Name: dswexec - Dispatcher method execution callbacks;
+ * dispatch to interpreter.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acdebug.h>
+#include <acpi/acdisasm.h>
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dswexec")
+
+/*
+ * Dispatch table for opcode classes
+ */
+static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = {
+ acpi_ex_opcode_0A_0T_1R,
+ acpi_ex_opcode_1A_0T_0R,
+ acpi_ex_opcode_1A_0T_1R,
+ acpi_ex_opcode_1A_1T_0R,
+ acpi_ex_opcode_1A_1T_1R,
+ acpi_ex_opcode_2A_0T_0R,
+ acpi_ex_opcode_2A_0T_1R,
+ acpi_ex_opcode_2A_1T_1R,
+ acpi_ex_opcode_2A_2T_1R,
+ acpi_ex_opcode_3A_0T_0R,
+ acpi_ex_opcode_3A_1T_1R,
+ acpi_ex_opcode_6A_0T_1R};
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_predicate_value
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the result of a predicate evaluation
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_get_predicate_value (
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object *result_obj) {
+ acpi_status status = AE_OK;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *local_obj_desc = NULL;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_get_predicate_value", walk_state);
+
+
+ walk_state->control_state->common.state = 0;
+
+ if (result_obj) {
+ status = acpi_ds_result_pop (&obj_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not get result from predicate evaluation, %s\n",
+ acpi_format_exception (status)));
+
+ return_ACPI_STATUS (status);
+ }
+ }
+ else {
+ status = acpi_ds_create_operand (walk_state, walk_state->op, 0);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ex_resolve_to_value (&walk_state->operands [0], walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ obj_desc = walk_state->operands [0];
+ }
+
+ if (!obj_desc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No predicate obj_desc=%p State=%p\n",
+ obj_desc, walk_state));
+
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ /*
+ * Result of predicate evaluation must be an Integer
+ * object. Implicitly convert the argument if necessary.
+ */
+ status = acpi_ex_convert_to_integer (obj_desc, &local_obj_desc, 16);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (local_obj_desc) != ACPI_TYPE_INTEGER) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Bad predicate (not an integer) obj_desc=%p State=%p Type=%X\n",
+ obj_desc, walk_state, ACPI_GET_OBJECT_TYPE (obj_desc)));
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /* Truncate the predicate to 32-bits if necessary */
+
+ acpi_ex_truncate_for32bit_table (local_obj_desc);
+
+ /*
+ * Save the result of the predicate evaluation on
+ * the control stack
+ */
+ if (local_obj_desc->integer.value) {
+ walk_state->control_state->common.value = TRUE;
+ }
+ else {
+ /*
+ * Predicate is FALSE, we will just toss the
+ * rest of the package
+ */
+ walk_state->control_state->common.value = FALSE;
+ status = AE_CTRL_FALSE;
+ }
+
+
+cleanup:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Completed a predicate eval=%X Op=%p\n",
+ walk_state->control_state->common.value, walk_state->op));
+
+ /* Break to debugger to display result */
+
+ ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (local_obj_desc, walk_state));
+
+ /*
+ * Delete the predicate result object (we know that
+ * we don't need it anymore)
+ */
+ if (local_obj_desc != obj_desc) {
+ acpi_ut_remove_reference (local_obj_desc);
+ }
+ acpi_ut_remove_reference (obj_desc);
+
+ walk_state->control_state->common.state = ACPI_CONTROL_NORMAL;
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_begin_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * out_op - Return op if a new one is created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the execution of control
+ * methods. This is where most operators and operands are
+ * dispatched to the interpreter.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_exec_begin_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op)
+{
+ union acpi_parse_object *op;
+ acpi_status status = AE_OK;
+ u32 opcode_class;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_exec_begin_op", walk_state);
+
+
+ op = walk_state->op;
+ if (!op) {
+ status = acpi_ds_load2_begin_op (walk_state, out_op);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ op = *out_op;
+ walk_state->op = op;
+ walk_state->opcode = op->common.aml_opcode;
+ walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+
+ if (acpi_ns_opens_scope (walk_state->op_info->object_type)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n",
+ acpi_ut_get_type_name (walk_state->op_info->object_type), op));
+
+ status = acpi_ds_scope_stack_pop (walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ }
+
+ if (op == walk_state->origin) {
+ if (out_op) {
+ *out_op = op;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * If the previous opcode was a conditional, this opcode
+ * must be the beginning of the associated predicate.
+ * Save this knowledge in the current scope descriptor
+ */
+ if ((walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ ACPI_CONTROL_CONDITIONAL_EXECUTING)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Exec predicate Op=%p State=%p\n",
+ op, walk_state));
+
+ walk_state->control_state->common.state = ACPI_CONTROL_PREDICATE_EXECUTING;
+
+ /* Save start of predicate */
+
+ walk_state->control_state->control.predicate_op = op;
+ }
+
+
+ opcode_class = walk_state->op_info->class;
+
+ /* We want to send namepaths to the load code */
+
+ if (op->common.aml_opcode == AML_INT_NAMEPATH_OP) {
+ opcode_class = AML_CLASS_NAMED_OBJECT;
+ }
+
+ /*
+ * Handle the opcode based upon the opcode type
+ */
+ switch (opcode_class) {
+ case AML_CLASS_CONTROL:
+
+ status = acpi_ds_result_stack_push (walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ds_exec_begin_control_op (walk_state, op);
+ break;
+
+
+ case AML_CLASS_NAMED_OBJECT:
+
+ if (walk_state->walk_type == ACPI_WALK_METHOD) {
+ /*
+ * Found a named object declaration during method
+ * execution; we must enter this object into the
+ * namespace. The created object is temporary and
+ * will be deleted upon completion of the execution
+ * of this method.
+ */
+ status = acpi_ds_load2_begin_op (walk_state, NULL);
+ }
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ status = acpi_ds_result_stack_push (walk_state);
+ }
+ break;
+
+
+ case AML_CLASS_EXECUTE:
+ case AML_CLASS_CREATE:
+
+ /*
+ * Most operators with arguments.
+ * Start a new result/operand state
+ */
+ status = acpi_ds_result_stack_push (walk_state);
+ break;
+
+
+ default:
+ break;
+ }
+
+ /* Nothing to do here during method execution */
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ds_exec_end_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the execution of control
+ * methods. The only thing we really need to do here is to
+ * notice the beginning of IF, ELSE, and WHILE blocks.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ds_exec_end_op (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *op;
+ acpi_status status = AE_OK;
+ u32 op_type;
+ u32 op_class;
+ union acpi_parse_object *next_op;
+ union acpi_parse_object *first_arg;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_exec_end_op", walk_state);
+
+
+ op = walk_state->op;
+ op_type = walk_state->op_info->type;
+ op_class = walk_state->op_info->class;
+
+ if (op_class == AML_CLASS_UNKNOWN) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown opcode %X\n", op->common.aml_opcode));
+ return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
+ }
+
+ first_arg = op->common.value.arg;
+
+ /* Init the walk state */
+
+ walk_state->num_operands = 0;
+ walk_state->return_desc = NULL;
+ walk_state->result_obj = NULL;
+
+ /* Call debugger for single step support (DEBUG build only) */
+
+ ACPI_DEBUGGER_EXEC (status = acpi_db_single_step (walk_state, op, op_class));
+ ACPI_DEBUGGER_EXEC (if (ACPI_FAILURE (status)) {return_ACPI_STATUS (status);});
+
+ /* Decode the Opcode Class */
+
+ switch (op_class) {
+ case AML_CLASS_ARGUMENT: /* constants, literals, etc. -- do nothing */
+ break;
+
+
+ case AML_CLASS_EXECUTE: /* most operators with arguments */
+
+ /* Build resolved operand stack */
+
+ status = acpi_ds_create_operands (walk_state, first_arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Done with this result state (Now that operand stack is built) */
+
+ status = acpi_ds_result_stack_pop (walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * All opcodes require operand resolution, with the only exceptions
+ * being the object_type and size_of operators.
+ */
+ if (!(walk_state->op_info->flags & AML_NO_OPERAND_RESOLVE)) {
+ /* Resolve all operands */
+
+ status = acpi_ex_resolve_operands (walk_state->opcode,
+ &(walk_state->operands [walk_state->num_operands -1]),
+ walk_state);
+ if (ACPI_SUCCESS (status)) {
+ ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
+ acpi_ps_get_opcode_name (walk_state->opcode),
+ walk_state->num_operands, "after ex_resolve_operands");
+ }
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Dispatch the request to the appropriate interpreter handler
+ * routine. There is one routine per opcode "type" based upon the
+ * number of opcode arguments and return type.
+ */
+ status = acpi_gbl_op_type_dispatch[op_type] (walk_state);
+ }
+ else {
+ /*
+ * Treat constructs of the form "Store(local_x,local_x)" as noops when the
+ * Local is uninitialized.
+ */
+ if ((status == AE_AML_UNINITIALIZED_LOCAL) &&
+ (walk_state->opcode == AML_STORE_OP) &&
+ (walk_state->operands[0]->common.type == ACPI_TYPE_LOCAL_REFERENCE) &&
+ (walk_state->operands[1]->common.type == ACPI_TYPE_LOCAL_REFERENCE) &&
+ (walk_state->operands[0]->reference.opcode ==
+ walk_state->operands[1]->reference.opcode) &&
+ (walk_state->operands[0]->reference.offset ==
+ walk_state->operands[1]->reference.offset)) {
+ status = AE_OK;
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "[%s]: Could not resolve operands, %s\n",
+ acpi_ps_get_opcode_name (walk_state->opcode),
+ acpi_format_exception (status)));
+ }
+ }
+
+ /* Always delete the argument objects and clear the operand stack */
+
+ acpi_ds_clear_operands (walk_state);
+
+ /*
+ * If a result object was returned from above, push it on the
+ * current result stack
+ */
+ if (ACPI_SUCCESS (status) &&
+ walk_state->result_obj) {
+ status = acpi_ds_result_push (walk_state->result_obj, walk_state);
+ }
+
+ break;
+
+
+ default:
+
+ switch (op_type) {
+ case AML_TYPE_CONTROL: /* Type 1 opcode, IF/ELSE/WHILE/NOOP */
+
+ /* 1 Operand, 0 external_result, 0 internal_result */
+
+ status = acpi_ds_exec_end_control_op (walk_state, op);
+
+ /* Make sure to properly pop the result stack */
+
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ds_result_stack_pop (walk_state);
+ }
+ else if (status == AE_CTRL_PENDING) {
+ status = acpi_ds_result_stack_pop (walk_state);
+ if (ACPI_SUCCESS (status)) {
+ status = AE_CTRL_PENDING;
+ }
+ }
+ break;
+
+
+ case AML_TYPE_METHOD_CALL:
+
+ /*
+ * If the method is referenced from within a package
+ * declaration, it is not a invocation of the method, just
+ * a reference to it.
+ */
+ if ((op->asl.parent) &&
+ ((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) ||
+ (op->asl.parent->asl.aml_opcode == AML_VAR_PACKAGE_OP))) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op));
+ op->common.node = (struct acpi_namespace_node *) op->asl.value.arg->asl.node->object;
+ acpi_ut_add_reference (op->asl.value.arg->asl.node->object);
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method invocation, Op=%p\n", op));
+
+ /*
+ * (AML_METHODCALL) Op->Asl.Value.Arg->Asl.Node contains
+ * the method Node pointer
+ */
+ /* next_op points to the op that holds the method name */
+
+ next_op = first_arg;
+
+ /* next_op points to first argument op */
+
+ next_op = next_op->common.next;
+
+ /*
+ * Get the method's arguments and put them on the operand stack
+ */
+ status = acpi_ds_create_operands (walk_state, next_op);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ /*
+ * Since the operands will be passed to another control method,
+ * we must resolve all local references here (Local variables,
+ * arguments to *this* method, etc.)
+ */
+ status = acpi_ds_resolve_operands (walk_state);
+ if (ACPI_FAILURE (status)) {
+ /* On error, clear all resolved operands */
+
+ acpi_ds_clear_operands (walk_state);
+ break;
+ }
+
+ /*
+ * Tell the walk loop to preempt this running method and
+ * execute the new method
+ */
+ status = AE_CTRL_TRANSFER;
+
+ /*
+ * Return now; we don't want to disturb anything,
+ * especially the operand count!
+ */
+ return_ACPI_STATUS (status);
+
+
+ case AML_TYPE_CREATE_FIELD:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Executing create_field Buffer/Index Op=%p\n", op));
+
+ status = acpi_ds_load2_end_op (walk_state);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ status = acpi_ds_eval_buffer_field_operands (walk_state, op);
+ break;
+
+
+ case AML_TYPE_CREATE_OBJECT:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Executing create_object (Buffer/Package) Op=%p\n", op));
+
+ switch (op->common.parent->common.aml_opcode) {
+ case AML_NAME_OP:
+
+ /*
+ * Put the Node on the object stack (Contains the ACPI Name of
+ * this object)
+ */
+ walk_state->operands[0] = (void *) op->common.parent->common.node;
+ walk_state->num_operands = 1;
+
+ status = acpi_ds_create_node (walk_state, op->common.parent->common.node, op->common.parent);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ /* Fall through */
+ /*lint -fallthrough */
+
+ case AML_INT_EVAL_SUBTREE_OP:
+
+ status = acpi_ds_eval_data_object_operands (walk_state, op,
+ acpi_ns_get_attached_object (op->common.parent->common.node));
+ break;
+
+ default:
+
+ status = acpi_ds_eval_data_object_operands (walk_state, op, NULL);
+ break;
+ }
+
+ /* Done with this result state (Now that operand stack is built) */
+
+ status = acpi_ds_result_stack_pop (walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * If a result object was returned from above, push it on the
+ * current result stack
+ */
+ if (ACPI_SUCCESS (status) &&
+ walk_state->result_obj) {
+ status = acpi_ds_result_push (walk_state->result_obj, walk_state);
+ }
+ break;
+
+
+ case AML_TYPE_NAMED_FIELD:
+ case AML_TYPE_NAMED_COMPLEX:
+ case AML_TYPE_NAMED_SIMPLE:
+ case AML_TYPE_NAMED_NO_OBJ:
+
+ status = acpi_ds_load2_end_op (walk_state);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Executing op_region Address/Length Op=%p\n", op));
+
+ status = acpi_ds_eval_region_operands (walk_state, op);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ status = acpi_ds_result_stack_pop (walk_state);
+ }
+
+ break;
+
+
+ case AML_TYPE_UNDEFINED:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", op));
+ return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
+
+
+ case AML_TYPE_BOGUS:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Internal opcode=%X type Op=%p\n",
+ walk_state->opcode, op));
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unimplemented opcode, class=%X type=%X Opcode=%X Op=%p\n",
+ op_class, op_type, op->common.aml_opcode, op));
+
+ status = AE_NOT_IMPLEMENTED;
+ break;
+ }
+ }
+
+ /*
+ * ACPI 2.0 support for 64-bit integers: Truncate numeric
+ * result value if we are executing from a 32-bit ACPI table
+ */
+ acpi_ex_truncate_for32bit_table (walk_state->result_obj);
+
+ /*
+ * Check if we just completed the evaluation of a
+ * conditional predicate
+ */
+
+ if ((ACPI_SUCCESS (status)) &&
+ (walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ ACPI_CONTROL_PREDICATE_EXECUTING) &&
+ (walk_state->control_state->control.predicate_op == op)) {
+ status = acpi_ds_get_predicate_value (walk_state, walk_state->result_obj);
+ walk_state->result_obj = NULL;
+ }
+
+
+cleanup:
+
+ /* Invoke exception handler on error */
+
+ if (ACPI_FAILURE (status) &&
+ acpi_gbl_exception_handler &&
+ !(status & AE_CODE_CONTROL)) {
+ acpi_ex_exit_interpreter ();
+ status = acpi_gbl_exception_handler (status,
+ walk_state->method_node->name.integer, walk_state->opcode,
+ walk_state->aml_offset, NULL);
+ acpi_ex_enter_interpreter ();
+ }
+
+ if (walk_state->result_obj) {
+ /* Break to debugger to display result */
+
+ ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state));
+
+ /*
+ * Delete the result op if and only if:
+ * Parent will not use the result -- such as any
+ * non-nested type2 op in a method (parent will be method)
+ */
+ acpi_ds_delete_result_if_not_used (op, walk_state->result_obj, walk_state);
+ }
+
+#ifdef _UNDER_DEVELOPMENT
+
+ if (walk_state->parser_state.aml == walk_state->parser_state.aml_end) {
+ acpi_db_method_end (walk_state);
+ }
+#endif
+
+ /* Always clear the object stack */
+
+ walk_state->num_operands = 0;
+
+#ifdef ACPI_DISASSEMBLER
+
+ /* On error, display method locals/args */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_dm_dump_method_info (status, walk_state, op);
+ }
+#endif
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
new file mode 100644
index 000000000000..06d758679588
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -0,0 +1,976 @@
+/******************************************************************************
+ *
+ * Module Name: dswload - Dispatcher namespace load callbacks
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+
+#ifdef _ACPI_ASL_COMPILER
+#include <acpi/acdisasm.h>
+#endif
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dswload")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_callbacks
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * pass_number - 1, 2, or 3
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Init walk state callbacks
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_init_callbacks (
+ struct acpi_walk_state *walk_state,
+ u32 pass_number)
+{
+
+ switch (pass_number) {
+ case 1:
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE;
+ walk_state->descending_callback = acpi_ds_load1_begin_op;
+ walk_state->ascending_callback = acpi_ds_load1_end_op;
+ break;
+
+ case 2:
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE;
+ walk_state->descending_callback = acpi_ds_load2_begin_op;
+ walk_state->ascending_callback = acpi_ds_load2_end_op;
+ break;
+
+ case 3:
+#ifndef ACPI_NO_METHOD_EXECUTION
+ walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE;
+ walk_state->descending_callback = acpi_ds_exec_begin_op;
+ walk_state->ascending_callback = acpi_ds_exec_end_op;
+#endif
+ break;
+
+ default:
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load1_begin_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_load1_begin_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op)
+{
+ union acpi_parse_object *op;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ acpi_object_type object_type;
+ char *path;
+ u32 flags;
+
+
+ ACPI_FUNCTION_NAME ("ds_load1_begin_op");
+
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state));
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (op) {
+ if (!(walk_state->op_info->flags & AML_NAMED)) {
+#if 0
+ if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
+ (walk_state->op_info->class == AML_CLASS_CONTROL)) {
+ acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name);
+ *out_op = op;
+ return (AE_CTRL_SKIP);
+ }
+#endif
+ *out_op = op;
+ return (AE_OK);
+ }
+
+ /* Check if this object has already been installed in the namespace */
+
+ if (op->common.node) {
+ *out_op = op;
+ return (AE_OK);
+ }
+ }
+
+ path = acpi_ps_get_next_namestring (&walk_state->parser_state);
+
+ /* Map the raw opcode into an internal object type */
+
+ object_type = walk_state->op_info->object_type;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "State=%p Op=%p [%s]\n", walk_state, op, acpi_ut_get_type_name (object_type)));
+
+ switch (walk_state->opcode) {
+ case AML_SCOPE_OP:
+
+ /*
+ * The target name of the Scope() operator must exist at this point so
+ * that we can actually open the scope to enter new names underneath it.
+ * Allow search-to-root for single namesegs.
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+#ifdef _ACPI_ASL_COMPILER
+ if (status == AE_NOT_FOUND) {
+ /*
+ * Table disassembly:
+ * Target of Scope() not found. Generate an External for it, and
+ * insert the name into the namespace.
+ */
+ acpi_dm_add_to_external_list (path);
+ status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
+ ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ }
+#endif
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (path, status);
+ return (status);
+ }
+
+ /*
+ * Check to make sure that the target is
+ * one of the opcodes that actually opens a scope
+ */
+ switch (node->type) {
+ case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+
+ /* These are acceptable types */
+ break;
+
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * These types we will allow, but we will change the type. This
+ * enables some existing code of the form:
+ *
+ * Name (DEB, 0)
+ * Scope (DEB) { ... }
+ *
+ * Note: silently change the type here. On the second pass, we will report a warning
+ */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
+ path, acpi_ut_get_type_name (node->type)));
+
+ node->type = ACPI_TYPE_ANY;
+ walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+ break;
+
+ default:
+
+ /* All other types are an error */
+
+ ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n",
+ acpi_ut_get_type_name (node->type), path));
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+ break;
+
+
+ default:
+
+ /*
+ * For all other named opcodes, we will enter the name into the namespace.
+ *
+ * Setup the search flags.
+ * Since we are entering a name into the namespace, we do not want to
+ * enable the search-to-root upsearch.
+ *
+ * There are only two conditions where it is acceptable that the name
+ * already exists:
+ * 1) the Scope() operator can reopen a scoping object that was
+ * previously defined (Scope, Method, Device, etc.)
+ * 2) Whenever we are parsing a deferred opcode (op_region, Buffer,
+ * buffer_field, or Package), the name of the object is already
+ * in the namespace.
+ */
+ if (walk_state->deferred_node) {
+ /* This name is already in the namespace, get the node */
+
+ node = walk_state->deferred_node;
+ status = AE_OK;
+ break;
+ }
+
+ flags = ACPI_NS_NO_UPSEARCH;
+ if ((walk_state->opcode != AML_SCOPE_OP) &&
+ (!(walk_state->parse_flags & ACPI_PARSE_DEFERRED_OP))) {
+ flags |= ACPI_NS_ERROR_IF_FOUND;
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Cannot already exist\n",
+ acpi_ut_get_type_name (object_type)));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n",
+ acpi_ut_get_type_name (object_type)));
+ }
+
+ /*
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that involve
+ * arguments to the opcode must be created as we go back up the parse tree later.
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
+ ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node));
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (path, status);
+ return (status);
+ }
+ break;
+ }
+
+
+ /* Common exit */
+
+ if (!op) {
+ /* Create a new op */
+
+ op = acpi_ps_alloc_op (walk_state->opcode);
+ if (!op) {
+ return (AE_NO_MEMORY);
+ }
+ }
+
+ /* Initialize */
+
+ op->named.name = node->name.integer;
+
+#if (defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY))
+ op->named.path = (u8 *) path;
+#endif
+
+
+ /*
+ * Put the Node in the "op" object that the parser uses, so we
+ * can get it again quickly when this scope is closed
+ */
+ op->common.node = node;
+ acpi_ps_append_arg (acpi_ps_get_parent_scope (&walk_state->parser_state), op);
+
+ *out_op = op;
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load1_end_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the loading of the namespace,
+ * both control methods and everything else.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_load1_end_op (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *op;
+ acpi_object_type object_type;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_NAME ("ds_load1_end_op");
+
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state));
+
+ /* We are only interested in opcodes that have an associated name */
+
+ if (!(walk_state->op_info->flags & (AML_NAMED | AML_FIELD))) {
+ return (AE_OK);
+ }
+
+ /* Get the object type to determine if we should pop the scope */
+
+ object_type = walk_state->op_info->object_type;
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+ if (walk_state->op_info->flags & AML_FIELD) {
+ if (walk_state->opcode == AML_FIELD_OP ||
+ walk_state->opcode == AML_BANK_FIELD_OP ||
+ walk_state->opcode == AML_INDEX_FIELD_OP) {
+ status = acpi_ds_init_field_objects (op, walk_state);
+ }
+ return (status);
+ }
+
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ status = acpi_ex_create_region (op->named.data, op->named.length,
+ (acpi_adr_space_type) ((op->common.value.arg)->common.value.integer), walk_state);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+#endif
+
+ if (op->common.aml_opcode == AML_NAME_OP) {
+ /* For Name opcode, get the object type from the argument */
+
+ if (op->common.value.arg) {
+ object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type;
+ op->common.node->type = (u8) object_type;
+ }
+ }
+
+ if (op->common.aml_opcode == AML_METHOD_OP) {
+ /*
+ * method_op pkg_length name_string method_flags term_list
+ *
+ * Note: We must create the method node/object pair as soon as we
+ * see the method declaration. This allows later pass1 parsing
+ * of invocations of the method (need to know the number of
+ * arguments.)
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "LOADING-Method: State=%p Op=%p named_obj=%p\n",
+ walk_state, op, op->named.node));
+
+ if (!acpi_ns_get_attached_object (op->named.node)) {
+ walk_state->operands[0] = (void *) op->named.node;
+ walk_state->num_operands = 1;
+
+ status = acpi_ds_create_operands (walk_state, op->common.value.arg);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ex_create_method (op->named.data,
+ op->named.length, walk_state);
+ }
+ walk_state->operands[0] = NULL;
+ walk_state->num_operands = 0;
+
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+ }
+
+ /* Pop the scope stack */
+
+ if (acpi_ns_opens_scope (object_type)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s): Popping scope for Op %p\n",
+ acpi_ut_get_type_name (object_type), op));
+
+ status = acpi_ds_scope_stack_pop (walk_state);
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load2_begin_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been reached in the
+ * walk; Arguments have not been evaluated yet.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Descending callback used during the loading of ACPI tables.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_load2_begin_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object **out_op)
+{
+ union acpi_parse_object *op;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ acpi_object_type object_type;
+ char *buffer_ptr;
+
+
+ ACPI_FUNCTION_TRACE ("ds_load2_begin_op");
+
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Op=%p State=%p\n", op, walk_state));
+
+ if (op) {
+ /* We only care about Namespace opcodes here */
+
+ if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
+ (!(walk_state->op_info->flags & AML_NAMED))) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Get the name we are going to enter or lookup in the namespace
+ */
+ if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
+ /* For Namepath op, get the path string */
+
+ buffer_ptr = op->common.value.string;
+ if (!buffer_ptr) {
+ /* No name, just exit */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+ else {
+ /* Get name from the op */
+
+ buffer_ptr = (char *) &op->named.name;
+ }
+ }
+ else {
+ /* Get the namestring from the raw AML */
+
+ buffer_ptr = acpi_ps_get_next_namestring (&walk_state->parser_state);
+ }
+
+ /* Map the opcode into an internal object type */
+
+ object_type = walk_state->op_info->object_type;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "State=%p Op=%p Type=%X\n", walk_state, op, object_type));
+
+
+ switch (walk_state->opcode) {
+ case AML_FIELD_OP:
+ case AML_BANK_FIELD_OP:
+ case AML_INDEX_FIELD_OP:
+
+ node = NULL;
+ status = AE_OK;
+ break;
+
+ case AML_INT_NAMEPATH_OP:
+
+ /*
+ * The name_path is an object reference to an existing object. Don't enter the
+ * name into the namespace, but look it up for use later
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ break;
+
+ case AML_SCOPE_OP:
+
+ /*
+ * The Path is an object reference to an existing object. Don't enter the
+ * name into the namespace, but look it up for use later
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ if (ACPI_FAILURE (status)) {
+#ifdef _ACPI_ASL_COMPILER
+ if (status == AE_NOT_FOUND) {
+ status = AE_OK;
+ }
+ else {
+ ACPI_REPORT_NSERROR (buffer_ptr, status);
+ }
+#else
+ ACPI_REPORT_NSERROR (buffer_ptr, status);
+#endif
+ return_ACPI_STATUS (status);
+ }
+ /*
+ * We must check to make sure that the target is
+ * one of the opcodes that actually opens a scope
+ */
+ switch (node->type) {
+ case ACPI_TYPE_LOCAL_SCOPE: /* Scope */
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+
+ /* These are acceptable types */
+ break;
+
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * These types we will allow, but we will change the type. This
+ * enables some existing code of the form:
+ *
+ * Name (DEB, 0)
+ * Scope (DEB) { ... }
+ */
+
+ ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
+ buffer_ptr, acpi_ut_get_type_name (node->type)));
+
+ node->type = ACPI_TYPE_ANY;
+ walk_state->scope_info->common.value = ACPI_TYPE_ANY;
+ break;
+
+ default:
+
+ /* All other types are an error */
+
+ ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n",
+ acpi_ut_get_type_name (node->type), buffer_ptr));
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+ break;
+
+ default:
+
+ /* All other opcodes */
+
+ if (op && op->common.node) {
+ /* This op/node was previously entered into the namespace */
+
+ node = op->common.node;
+
+ if (acpi_ns_opens_scope (object_type)) {
+ status = acpi_ds_scope_stack_push (node, object_type, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ }
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Enter the named type into the internal namespace. We enter the name
+ * as we go downward in the parse tree. Any necessary subobjects that involve
+ * arguments to the opcode must be created as we go back up the parse tree later.
+ *
+ * Note: Name may already exist if we are executing a deferred opcode.
+ */
+ if (walk_state->deferred_node) {
+ /* This name is already in the namespace, get the node */
+
+ node = walk_state->deferred_node;
+ status = AE_OK;
+ break;
+ }
+
+ status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
+ ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+ break;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_NSERROR (buffer_ptr, status);
+ return_ACPI_STATUS (status);
+ }
+
+
+ if (!op) {
+ /* Create a new op */
+
+ op = acpi_ps_alloc_op (walk_state->opcode);
+ if (!op) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Initialize the new op */
+
+ if (node) {
+ op->named.name = node->name.integer;
+ }
+ if (out_op) {
+ *out_op = op;
+ }
+ }
+
+ /*
+ * Put the Node in the "op" object that the parser uses, so we
+ * can get it again quickly when this scope is closed
+ */
+ op->common.node = node;
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_load2_end_op
+ *
+ * PARAMETERS: walk_state - Current state of the parse tree walk
+ * Op - Op that has been just been completed in the
+ * walk; Arguments have now been evaluated.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Ascending callback used during the loading of the namespace,
+ * both control methods and everything else.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_load2_end_op (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_parse_object *op;
+ acpi_status status = AE_OK;
+ acpi_object_type object_type;
+ struct acpi_namespace_node *node;
+ union acpi_parse_object *arg;
+ struct acpi_namespace_node *new_node;
+#ifndef ACPI_NO_METHOD_EXECUTION
+ u32 i;
+#endif
+
+
+ ACPI_FUNCTION_TRACE ("ds_load2_end_op");
+
+ op = walk_state->op;
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Opcode [%s] Op %p State %p\n",
+ walk_state->op_info->name, op, walk_state));
+
+ /* Only interested in opcodes that have namespace objects */
+
+ if (!(walk_state->op_info->flags & AML_NSOBJECT)) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ if (op->common.aml_opcode == AML_SCOPE_OP) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Ending scope Op=%p State=%p\n", op, walk_state));
+ }
+
+
+ object_type = walk_state->op_info->object_type;
+
+ /*
+ * Get the Node/name from the earlier lookup
+ * (It was saved in the *op structure)
+ */
+ node = op->common.node;
+
+ /*
+ * Put the Node on the object stack (Contains the ACPI Name of
+ * this object)
+ */
+ walk_state->operands[0] = (void *) node;
+ walk_state->num_operands = 1;
+
+ /* Pop the scope stack */
+
+ if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n",
+ acpi_ut_get_type_name (object_type), op));
+
+ status = acpi_ds_scope_stack_pop (walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ }
+
+ /*
+ * Named operations are as follows:
+ *
+ * AML_ALIAS
+ * AML_BANKFIELD
+ * AML_CREATEBITFIELD
+ * AML_CREATEBYTEFIELD
+ * AML_CREATEDWORDFIELD
+ * AML_CREATEFIELD
+ * AML_CREATEQWORDFIELD
+ * AML_CREATEWORDFIELD
+ * AML_DATA_REGION
+ * AML_DEVICE
+ * AML_EVENT
+ * AML_FIELD
+ * AML_INDEXFIELD
+ * AML_METHOD
+ * AML_METHODCALL
+ * AML_MUTEX
+ * AML_NAME
+ * AML_NAMEDFIELD
+ * AML_OPREGION
+ * AML_POWERRES
+ * AML_PROCESSOR
+ * AML_SCOPE
+ * AML_THERMALZONE
+ */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Create-Load [%s] State=%p Op=%p named_obj=%p\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode), walk_state, op, node));
+
+ /* Decode the opcode */
+
+ arg = op->common.value.arg;
+
+ switch (walk_state->op_info->type) {
+#ifndef ACPI_NO_METHOD_EXECUTION
+
+ case AML_TYPE_CREATE_FIELD:
+
+ /*
+ * Create the field object, but the field buffer and index must
+ * be evaluated later during the execution phase
+ */
+ status = acpi_ds_create_buffer_field (op, walk_state);
+ break;
+
+
+ case AML_TYPE_NAMED_FIELD:
+
+ switch (op->common.aml_opcode) {
+ case AML_INDEX_FIELD_OP:
+
+ status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node,
+ walk_state);
+ break;
+
+ case AML_BANK_FIELD_OP:
+
+ status = acpi_ds_create_bank_field (op, arg->common.node, walk_state);
+ break;
+
+ case AML_FIELD_OP:
+
+ status = acpi_ds_create_field (op, arg->common.node, walk_state);
+ break;
+
+ default:
+ /* All NAMED_FIELD opcodes must be handled above */
+ break;
+ }
+ break;
+
+
+ case AML_TYPE_NAMED_SIMPLE:
+
+ status = acpi_ds_create_operands (walk_state, arg);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ switch (op->common.aml_opcode) {
+ case AML_PROCESSOR_OP:
+
+ status = acpi_ex_create_processor (walk_state);
+ break;
+
+ case AML_POWER_RES_OP:
+
+ status = acpi_ex_create_power_resource (walk_state);
+ break;
+
+ case AML_MUTEX_OP:
+
+ status = acpi_ex_create_mutex (walk_state);
+ break;
+
+ case AML_EVENT_OP:
+
+ status = acpi_ex_create_event (walk_state);
+ break;
+
+ case AML_DATA_REGION_OP:
+
+ status = acpi_ex_create_table_region (walk_state);
+ break;
+
+ case AML_ALIAS_OP:
+
+ status = acpi_ex_create_alias (walk_state);
+ break;
+
+ default:
+ /* Unknown opcode */
+
+ status = AE_OK;
+ goto cleanup;
+ }
+
+ /* Delete operands */
+
+ for (i = 1; i < walk_state->num_operands; i++) {
+ acpi_ut_remove_reference (walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+
+ break;
+#endif /* ACPI_NO_METHOD_EXECUTION */
+
+ case AML_TYPE_NAMED_COMPLEX:
+
+ switch (op->common.aml_opcode) {
+#ifndef ACPI_NO_METHOD_EXECUTION
+ case AML_REGION_OP:
+ /*
+ * The op_region is not fully parsed at this time. Only valid argument is the space_id.
+ * (We must save the address of the AML of the address and length operands)
+ */
+ /*
+ * If we have a valid region, initialize it
+ * Namespace is NOT locked at this point.
+ */
+ status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE);
+ if (ACPI_FAILURE (status)) {
+ /*
+ * If AE_NOT_EXIST is returned, it is not fatal
+ * because many regions get created before a handler
+ * is installed for said region.
+ */
+ if (AE_NOT_EXIST == status) {
+ status = AE_OK;
+ }
+ }
+ break;
+
+
+ case AML_NAME_OP:
+
+ status = acpi_ds_create_node (walk_state, node, op);
+ break;
+#endif /* ACPI_NO_METHOD_EXECUTION */
+
+
+ default:
+ /* All NAMED_COMPLEX opcodes must be handled above */
+ /* Note: Method objects were already created in Pass 1 */
+ break;
+ }
+ break;
+
+
+ case AML_CLASS_INTERNAL:
+
+ /* case AML_INT_NAMEPATH_OP: */
+ break;
+
+
+ case AML_CLASS_METHOD_CALL:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "RESOLVING-method_call: State=%p Op=%p named_obj=%p\n",
+ walk_state, op, node));
+
+ /*
+ * Lookup the method name and save the Node
+ */
+ status = acpi_ns_lookup (walk_state->scope_info, arg->common.value.string,
+ ACPI_TYPE_ANY, ACPI_IMODE_LOAD_PASS2,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ walk_state, &(new_node));
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Make sure that what we found is indeed a method
+ * We didn't search for a method on purpose, to see if the name would resolve
+ */
+ if (new_node->type != ACPI_TYPE_METHOD) {
+ status = AE_AML_OPERAND_TYPE;
+ }
+
+ /* We could put the returned object (Node) on the object stack for later, but
+ * for now, we will put it in the "op" object that the parser uses, so we
+ * can get it again at the end of this scope
+ */
+ op->common.node = new_node;
+ }
+ else {
+ ACPI_REPORT_NSERROR (arg->common.value.string, status);
+ }
+ break;
+
+
+ default:
+ break;
+ }
+
+cleanup:
+
+ /* Remove the Node pushed at the very beginning */
+
+ walk_state->operands[0] = NULL;
+ walk_state->num_operands = 0;
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
new file mode 100644
index 000000000000..65f456151e25
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ * Module Name: dswscope - Scope stack manipulation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dswscope")
+
+
+#define STACK_POP(head) head
+
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ds_scope_stack_clear
+ *
+ * PARAMETERS: None
+ *
+ * DESCRIPTION: Pop (and free) everything on the scope stack except the
+ * root scope object (which remains at the stack top.)
+ *
+ ***************************************************************************/
+
+void
+acpi_ds_scope_stack_clear (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *scope_info;
+
+ ACPI_FUNCTION_NAME ("ds_scope_stack_clear");
+
+
+ while (walk_state->scope_info) {
+ /* Pop a scope off the stack */
+
+ scope_info = walk_state->scope_info;
+ walk_state->scope_info = scope_info->scope.next;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value)));
+ acpi_ut_delete_generic_state (scope_info);
+ }
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ds_scope_stack_push
+ *
+ * PARAMETERS: *Node, - Name to be made current
+ * Type, - Type of frame being pushed
+ *
+ * DESCRIPTION: Push the current scope on the scope stack, and make the
+ * passed Node current.
+ *
+ ***************************************************************************/
+
+acpi_status
+acpi_ds_scope_stack_push (
+ struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *scope_info;
+ union acpi_generic_state *old_scope_info;
+
+
+ ACPI_FUNCTION_TRACE ("ds_scope_stack_push");
+
+
+ if (!node) {
+ /* Invalid scope */
+
+ ACPI_REPORT_ERROR (("ds_scope_stack_push: null scope passed\n"));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Make sure object type is valid */
+
+ if (!acpi_ut_valid_object_type (type)) {
+ ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", type));
+ }
+
+ /* Allocate a new scope object */
+
+ scope_info = acpi_ut_create_generic_state ();
+ if (!scope_info) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Init new scope object */
+
+ scope_info->common.data_type = ACPI_DESC_TYPE_STATE_WSCOPE;
+ scope_info->scope.node = node;
+ scope_info->common.value = (u16) type;
+
+ walk_state->scope_depth++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[%.2d] Pushed scope ", (u32) walk_state->scope_depth));
+
+ old_scope_info = walk_state->scope_info;
+ if (old_scope_info) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+ "[%4.4s] (%s)",
+ acpi_ut_get_node_name (old_scope_info->scope.node),
+ acpi_ut_get_type_name (old_scope_info->common.value)));
+ }
+ else {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+ "[\\___] (%s)", "ROOT"));
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+ ", New scope -> [%4.4s] (%s)\n",
+ acpi_ut_get_node_name (scope_info->scope.node),
+ acpi_ut_get_type_name (scope_info->common.value)));
+
+ /* Push new scope object onto stack */
+
+ acpi_ut_push_generic_state (&walk_state->scope_info, scope_info);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ds_scope_stack_pop
+ *
+ * PARAMETERS: Type - The type of frame to be found
+ *
+ * DESCRIPTION: Pop the scope stack until a frame of the requested type
+ * is found.
+ *
+ * RETURN: Count of frames popped. If no frame of the requested type
+ * was found, the count is returned as a negative number and
+ * the scope stack is emptied (which sets the current scope
+ * to the root). If the scope stack was empty at entry, the
+ * function is a no-op and returns 0.
+ *
+ ***************************************************************************/
+
+acpi_status
+acpi_ds_scope_stack_pop (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *scope_info;
+ union acpi_generic_state *new_scope_info;
+
+
+ ACPI_FUNCTION_TRACE ("ds_scope_stack_pop");
+
+
+ /*
+ * Pop scope info object off the stack.
+ */
+ scope_info = acpi_ut_pop_generic_state (&walk_state->scope_info);
+ if (!scope_info) {
+ return_ACPI_STATUS (AE_STACK_UNDERFLOW);
+ }
+
+ walk_state->scope_depth--;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[%.2d] Popped scope [%4.4s] (%s), New scope -> ",
+ (u32) walk_state->scope_depth,
+ acpi_ut_get_node_name (scope_info->scope.node),
+ acpi_ut_get_type_name (scope_info->common.value)));
+
+ new_scope_info = walk_state->scope_info;
+ if (new_scope_info) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+ "[%4.4s] (%s)\n",
+ acpi_ut_get_node_name (new_scope_info->scope.node),
+ acpi_ut_get_type_name (new_scope_info->common.value)));
+ }
+ else {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC,
+ "[\\___] (ROOT)\n"));
+ }
+
+ acpi_ut_delete_generic_state (scope_info);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
new file mode 100644
index 000000000000..e555b3fbd5e5
--- /dev/null
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -0,0 +1,1100 @@
+/******************************************************************************
+ *
+ * Module Name: dswstate - Dispatcher parse tree walk management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/acdispat.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_DISPATCHER
+ ACPI_MODULE_NAME ("dswstate")
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_insert
+ *
+ * PARAMETERS: Object - Object to push
+ * Index - Where to insert the object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Insert an object onto this walk's result stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_insert (
+ void *object,
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_NAME ("ds_result_insert");
+
+
+ state = walk_state->results;
+ if (!state) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n",
+ walk_state));
+ return (AE_NOT_EXIST);
+ }
+
+ if (index >= ACPI_OBJ_NUM_OPERANDS) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Index out of range: %X Obj=%p State=%p Num=%X\n",
+ index, object, walk_state, state->results.num_results));
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (!object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null Object! Index=%X Obj=%p State=%p Num=%X\n",
+ index, object, walk_state, state->results.num_results));
+ return (AE_BAD_PARAMETER);
+ }
+
+ state->results.obj_desc [index] = object;
+ state->results.num_results++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
+ object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL",
+ walk_state, state->results.num_results, walk_state->current_result));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_remove
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * Index - Where to extract the object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
+ * other words, this is a FIFO.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_remove (
+ union acpi_operand_object **object,
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_NAME ("ds_result_remove");
+
+
+ state = walk_state->results;
+ if (!state) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n",
+ walk_state));
+ return (AE_NOT_EXIST);
+ }
+
+ if (index >= ACPI_OBJ_MAX_OPERAND) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Index out of range: %X State=%p Num=%X\n",
+ index, walk_state, state->results.num_results));
+ }
+
+ /* Check for a valid result object */
+
+ if (!state->results.obj_desc [index]) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null operand! State=%p #Ops=%X, Index=%X\n",
+ walk_state, state->results.num_results, index));
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ /* Remove the object */
+
+ state->results.num_results--;
+
+ *object = state->results.obj_desc [index];
+ state->results.obj_desc [index] = NULL;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Obj=%p [%s] Index=%X State=%p Num=%X\n",
+ *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL",
+ index, walk_state, state->results.num_results));
+
+ return (AE_OK);
+}
+
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_pop
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
+ * other words, this is a FIFO.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_pop (
+ union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_native_uint index;
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_NAME ("ds_result_pop");
+
+
+ state = walk_state->results;
+ if (!state) {
+ return (AE_OK);
+ }
+
+ if (!state->results.num_results) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Result stack is empty! State=%p\n",
+ walk_state));
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ /* Remove top element */
+
+ state->results.num_results--;
+
+ for (index = ACPI_OBJ_NUM_OPERANDS; index; index--) {
+ /* Check for a valid result object */
+
+ if (state->results.obj_desc [index -1]) {
+ *object = state->results.obj_desc [index -1];
+ state->results.obj_desc [index -1] = NULL;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] Index=%X State=%p Num=%X\n",
+ *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL",
+ (u32) index -1, walk_state, state->results.num_results));
+
+ return (AE_OK);
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state));
+ return (AE_AML_NO_RETURN_VALUE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_pop_from_bottom
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off the bottom of this walk's result stack. In
+ * other words, this is a FIFO.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_pop_from_bottom (
+ union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_native_uint index;
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_NAME ("ds_result_pop_from_bottom");
+
+
+ state = walk_state->results;
+ if (!state) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Warning: No result object pushed! State=%p\n", walk_state));
+ return (AE_NOT_EXIST);
+ }
+
+ if (!state->results.num_results) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state));
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ /* Remove Bottom element */
+
+ *object = state->results.obj_desc [0];
+
+ /* Push entire stack down one element */
+
+ for (index = 0; index < state->results.num_results; index++) {
+ state->results.obj_desc [index] = state->results.obj_desc [index + 1];
+ }
+
+ state->results.num_results--;
+
+ /* Check for a valid result object */
+
+ if (!*object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null operand! State=%p #Ops=%X, Index=%X\n",
+ walk_state, state->results.num_results, (u32) index));
+ return (AE_AML_NO_RETURN_VALUE);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s], Results=%p State=%p\n",
+ *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL",
+ state, walk_state));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_push
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto the current result stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_push (
+ union acpi_operand_object *object,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_NAME ("ds_result_push");
+
+
+ state = walk_state->results;
+ if (!state) {
+ ACPI_REPORT_ERROR (("No result stack frame during push\n"));
+ return (AE_AML_INTERNAL);
+ }
+
+ if (state->results.num_results == ACPI_OBJ_NUM_OPERANDS) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Result stack overflow: Obj=%p State=%p Num=%X\n",
+ object, walk_state, state->results.num_results));
+ return (AE_STACK_OVERFLOW);
+ }
+
+ if (!object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Object! Obj=%p State=%p Num=%X\n",
+ object, walk_state, state->results.num_results));
+ return (AE_BAD_PARAMETER);
+ }
+
+ state->results.obj_desc [state->results.num_results] = object;
+ state->results.num_results++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
+ object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL",
+ walk_state, state->results.num_results, walk_state->current_result));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_stack_push
+ *
+ * PARAMETERS: walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto the walk_state result stack.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_stack_push (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+ ACPI_FUNCTION_NAME ("ds_result_stack_push");
+
+
+ state = acpi_ut_create_generic_state ();
+ if (!state) {
+ return (AE_NO_MEMORY);
+ }
+
+ state->common.data_type = ACPI_DESC_TYPE_STATE_RESULT;
+ acpi_ut_push_generic_state (&walk_state->results, state);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Results=%p State=%p\n",
+ state, walk_state));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_stack_pop
+ *
+ * PARAMETERS: walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop an object off of the walk_state result stack.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_stack_pop (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+ ACPI_FUNCTION_NAME ("ds_result_stack_pop");
+
+
+ /* Check for stack underflow */
+
+ if (walk_state->results == NULL) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Underflow - State=%p\n",
+ walk_state));
+ return (AE_AML_NO_OPERAND);
+ }
+
+ state = acpi_ut_pop_generic_state (&walk_state->results);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Result=%p remaining_results=%X State=%p\n",
+ state, state->results.num_results, walk_state));
+
+ acpi_ut_delete_generic_state (state);
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_delete_all
+ *
+ * PARAMETERS: walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
+ * Should be used with great care, if at all!
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_ds_obj_stack_delete_all (
+ struct acpi_walk_state *walk_state)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state);
+
+
+ /* The stack size is configurable, but fixed */
+
+ for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) {
+ if (walk_state->operands[i]) {
+ acpi_ut_remove_reference (walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_push
+ *
+ * PARAMETERS: Object - Object to push
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push an object onto this walk's object/operand stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_push (
+ void *object,
+ struct acpi_walk_state *walk_state)
+{
+ ACPI_FUNCTION_NAME ("ds_obj_stack_push");
+
+
+ /* Check for stack overflow */
+
+ if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "overflow! Obj=%p State=%p #Ops=%X\n",
+ object, walk_state, walk_state->num_operands));
+ return (AE_STACK_OVERFLOW);
+ }
+
+ /* Put the object onto the stack */
+
+ walk_state->operands [walk_state->num_operands] = object;
+ walk_state->num_operands++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
+ object, acpi_ut_get_object_type_name ((union acpi_operand_object *) object),
+ walk_state, walk_state->num_operands));
+
+ return (AE_OK);
+}
+
+
+#if 0
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_pop_object
+ *
+ * PARAMETERS: pop_count - Number of objects/entries to pop
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
+ * deleted by this routine.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_pop_object (
+ union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
+{
+ ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object");
+
+
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Missing operand/stack empty! State=%p #Ops=%X\n",
+ walk_state, walk_state->num_operands));
+ *object = NULL;
+ return (AE_AML_NO_OPERAND);
+ }
+
+ /* Pop the stack */
+
+ walk_state->num_operands--;
+
+ /* Check for a valid operand */
+
+ if (!walk_state->operands [walk_state->num_operands]) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null operand! State=%p #Ops=%X\n",
+ walk_state, walk_state->num_operands));
+ *object = NULL;
+ return (AE_AML_NO_OPERAND);
+ }
+
+ /* Get operand and set stack entry to null */
+
+ *object = walk_state->operands [walk_state->num_operands];
+ walk_state->operands [walk_state->num_operands] = NULL;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
+ *object, acpi_ut_get_object_type_name (*object),
+ walk_state, walk_state->num_operands));
+
+ return (AE_OK);
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_pop
+ *
+ * PARAMETERS: pop_count - Number of objects/entries to pop
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
+ * deleted by this routine.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_pop (
+ u32 pop_count,
+ struct acpi_walk_state *walk_state)
+{
+ u32 i;
+
+ ACPI_FUNCTION_NAME ("ds_obj_stack_pop");
+
+
+ for (i = 0; i < pop_count; i++) {
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Underflow! Count=%X State=%p #Ops=%X\n",
+ pop_count, walk_state, walk_state->num_operands));
+ return (AE_STACK_UNDERFLOW);
+ }
+
+ /* Just set the stack entry to null */
+
+ walk_state->num_operands--;
+ walk_state->operands [walk_state->num_operands] = NULL;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
+ pop_count, walk_state, walk_state->num_operands));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_pop_and_delete
+ *
+ * PARAMETERS: pop_count - Number of objects/entries to pop
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack and delete each object that is
+ * popped off.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_pop_and_delete (
+ u32 pop_count,
+ struct acpi_walk_state *walk_state)
+{
+ u32 i;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_NAME ("ds_obj_stack_pop_and_delete");
+
+
+ for (i = 0; i < pop_count; i++) {
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Underflow! Count=%X State=%p #Ops=%X\n",
+ pop_count, walk_state, walk_state->num_operands));
+ return (AE_STACK_UNDERFLOW);
+ }
+
+ /* Pop the stack and delete an object if present in this stack entry */
+
+ walk_state->num_operands--;
+ obj_desc = walk_state->operands [walk_state->num_operands];
+ if (obj_desc) {
+ acpi_ut_remove_reference (walk_state->operands [walk_state->num_operands]);
+ walk_state->operands [walk_state->num_operands] = NULL;
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n",
+ pop_count, walk_state, walk_state->num_operands));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_get_value
+ *
+ * PARAMETERS: Index - Stack index whose value is desired. Based
+ * on the top of the stack (index=0 == top)
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve an object from this walk's object stack. Index must
+ * be within the range of the current stack pointer.
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+void *
+acpi_ds_obj_stack_get_value (
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state);
+
+
+ /* Can't do it if the stack is empty */
+
+ if (walk_state->num_operands == 0) {
+ return_PTR (NULL);
+ }
+
+ /* or if the index is past the top of the stack */
+
+ if (index > (walk_state->num_operands - (u32) 1)) {
+ return_PTR (NULL);
+ }
+
+ return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) -
+ index]);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_get_current_walk_state
+ *
+ * PARAMETERS: Thread - Get current active state for this Thread
+ *
+ * RETURN: Pointer to the current walk state
+ *
+ * DESCRIPTION: Get the walk state that is at the head of the list (the "current"
+ * walk state.)
+ *
+ ******************************************************************************/
+
+struct acpi_walk_state *
+acpi_ds_get_current_walk_state (
+ struct acpi_thread_state *thread)
+
+{
+ ACPI_FUNCTION_NAME ("ds_get_current_walk_state");
+
+
+ if (!thread) {
+ return (NULL);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Current walk_state %p\n",
+ thread->walk_state_list));
+
+ return (thread->walk_state_list);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_push_walk_state
+ *
+ * PARAMETERS: walk_state - State to push
+ * walk_list - The list that owns the walk stack
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Place the walk_state at the head of the state list.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_push_walk_state (
+ struct acpi_walk_state *walk_state,
+ struct acpi_thread_state *thread)
+{
+ ACPI_FUNCTION_TRACE ("ds_push_walk_state");
+
+
+ walk_state->next = thread->walk_state_list;
+ thread->walk_state_list = walk_state;
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_pop_walk_state
+ *
+ * PARAMETERS: walk_list - The list that owns the walk stack
+ *
+ * RETURN: A walk_state object popped from the stack
+ *
+ * DESCRIPTION: Remove and return the walkstate object that is at the head of
+ * the walk stack for the given walk list. NULL indicates that
+ * the list is empty.
+ *
+ ******************************************************************************/
+
+struct acpi_walk_state *
+acpi_ds_pop_walk_state (
+ struct acpi_thread_state *thread)
+{
+ struct acpi_walk_state *walk_state;
+
+
+ ACPI_FUNCTION_TRACE ("ds_pop_walk_state");
+
+
+ walk_state = thread->walk_state_list;
+
+ if (walk_state) {
+ /* Next walk state becomes the current walk state */
+
+ thread->walk_state_list = walk_state->next;
+
+ /*
+ * Don't clear the NEXT field, this serves as an indicator
+ * that there is a parent WALK STATE
+ * NO: walk_state->Next = NULL;
+ */
+ }
+
+ return_PTR (walk_state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_create_walk_state
+ *
+ * PARAMETERS: Origin - Starting point for this walk
+ * Thread - Current thread state
+ *
+ * RETURN: Pointer to the new walk state.
+ *
+ * DESCRIPTION: Allocate and initialize a new walk state. The current walk
+ * state is set to this new state.
+ *
+ ******************************************************************************/
+
+struct acpi_walk_state *
+acpi_ds_create_walk_state (
+ acpi_owner_id owner_id,
+ union acpi_parse_object *origin,
+ union acpi_operand_object *mth_desc,
+ struct acpi_thread_state *thread)
+{
+ struct acpi_walk_state *walk_state;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ds_create_walk_state");
+
+
+ walk_state = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_WALK);
+ if (!walk_state) {
+ return_PTR (NULL);
+ }
+
+ walk_state->data_type = ACPI_DESC_TYPE_WALK;
+ walk_state->owner_id = owner_id;
+ walk_state->origin = origin;
+ walk_state->method_desc = mth_desc;
+ walk_state->thread = thread;
+
+ walk_state->parser_state.start_op = origin;
+
+ /* Init the method args/local */
+
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+ acpi_ds_method_data_init (walk_state);
+#endif
+
+ /* Create an initial result stack entry */
+
+ status = acpi_ds_result_stack_push (walk_state);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_release_to_cache (ACPI_MEM_LIST_WALK, walk_state);
+ return_PTR (NULL);
+ }
+
+ /* Put the new state at the head of the walk list */
+
+ if (thread) {
+ acpi_ds_push_walk_state (walk_state, thread);
+ }
+
+ return_PTR (walk_state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_init_aml_walk
+ *
+ * PARAMETERS: walk_state - New state to be initialized
+ * Op - Current parse op
+ * method_node - Control method NS node, if any
+ * aml_start - Start of AML
+ * aml_length - Length of AML
+ * Params - Method args, if any
+ * return_obj_desc - Where to store a return object, if any
+ * pass_number - 1, 2, or 3
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_init_aml_walk (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ struct acpi_namespace_node *method_node,
+ u8 *aml_start,
+ u32 aml_length,
+ struct acpi_parameter_info *info,
+ u32 pass_number)
+{
+ acpi_status status;
+ struct acpi_parse_state *parser_state = &walk_state->parser_state;
+ union acpi_parse_object *extra_op;
+
+
+ ACPI_FUNCTION_TRACE ("ds_init_aml_walk");
+
+
+ walk_state->parser_state.aml =
+ walk_state->parser_state.aml_start = aml_start;
+ walk_state->parser_state.aml_end =
+ walk_state->parser_state.pkg_end = aml_start + aml_length;
+
+ /* The next_op of the next_walk will be the beginning of the method */
+
+ walk_state->next_op = NULL;
+
+ if (info) {
+ if (info->parameter_type == ACPI_PARAM_GPE) {
+ walk_state->gpe_event_info = ACPI_CAST_PTR (struct acpi_gpe_event_info,
+ info->parameters);
+ }
+ else {
+ walk_state->params = info->parameters;
+ walk_state->caller_return_desc = &info->return_object;
+ }
+ }
+
+ status = acpi_ps_init_scope (&walk_state->parser_state, op);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (method_node) {
+ walk_state->parser_state.start_node = method_node;
+ walk_state->walk_type = ACPI_WALK_METHOD;
+ walk_state->method_node = method_node;
+ walk_state->method_desc = acpi_ns_get_attached_object (method_node);
+
+ /* Push start scope on scope stack and make it current */
+
+ status = acpi_ds_scope_stack_push (method_node, ACPI_TYPE_METHOD, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Init the method arguments */
+
+ status = acpi_ds_method_data_init_args (walk_state->params, ACPI_METHOD_NUM_ARGS, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ else {
+ /*
+ * Setup the current scope.
+ * Find a Named Op that has a namespace node associated with it.
+ * search upwards from this Op. Current scope is the first
+ * Op with a namespace node.
+ */
+ extra_op = parser_state->start_op;
+ while (extra_op && !extra_op->common.node) {
+ extra_op = extra_op->common.parent;
+ }
+
+ if (!extra_op) {
+ parser_state->start_node = NULL;
+ }
+ else {
+ parser_state->start_node = extra_op->common.node;
+ }
+
+ if (parser_state->start_node) {
+ /* Push start scope on scope stack and make it current */
+
+ status = acpi_ds_scope_stack_push (parser_state->start_node,
+ parser_state->start_node->type, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ }
+
+ status = acpi_ds_init_callbacks (walk_state, pass_number);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_delete_walk_state
+ *
+ * PARAMETERS: walk_state - State to delete
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete a walk state including all internal data structures
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_delete_walk_state (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_delete_walk_state", walk_state);
+
+
+ if (!walk_state) {
+ return;
+ }
+
+ if (walk_state->data_type != ACPI_DESC_TYPE_WALK) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", walk_state));
+ return;
+ }
+
+ if (walk_state->parser_state.scope) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state));
+ }
+
+ /* Always must free any linked control states */
+
+ while (walk_state->control_state) {
+ state = walk_state->control_state;
+ walk_state->control_state = state->common.next;
+
+ acpi_ut_delete_generic_state (state);
+ }
+
+ /* Always must free any linked parse states */
+
+ while (walk_state->scope_info) {
+ state = walk_state->scope_info;
+ walk_state->scope_info = state->common.next;
+
+ acpi_ut_delete_generic_state (state);
+ }
+
+ /* Always must free any stacked result states */
+
+ while (walk_state->results) {
+ state = walk_state->results;
+ walk_state->results = state->common.next;
+
+ acpi_ut_delete_generic_state (state);
+ }
+
+ acpi_ut_release_to_cache (ACPI_MEM_LIST_WALK, walk_state);
+ return_VOID;
+}
+
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ds_delete_walk_state_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Purge the global state object cache. Used during subsystem
+ * termination.
+ *
+ ******************************************************************************/
+
+void
+acpi_ds_delete_walk_state_cache (
+ void)
+{
+ ACPI_FUNCTION_TRACE ("ds_delete_walk_state_cache");
+
+
+ acpi_ut_delete_generic_cache (ACPI_MEM_LIST_WALK);
+ return_VOID;
+}
+#endif
+
+
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
new file mode 100644
index 000000000000..fdf143b405be
--- /dev/null
+++ b/drivers/acpi/ec.c
@@ -0,0 +1,1024 @@
+/*
+ * acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 38 $)
+ *
+ * Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/io.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/actypes.h>
+
+#define _COMPONENT ACPI_EC_COMPONENT
+ACPI_MODULE_NAME ("acpi_ec")
+
+#define ACPI_EC_COMPONENT 0x00100000
+#define ACPI_EC_CLASS "embedded_controller"
+#define ACPI_EC_HID "PNP0C09"
+#define ACPI_EC_DRIVER_NAME "ACPI Embedded Controller Driver"
+#define ACPI_EC_DEVICE_NAME "Embedded Controller"
+#define ACPI_EC_FILE_INFO "info"
+
+
+#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
+#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
+#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
+
+#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */
+#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
+
+#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
+#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
+#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
+
+#define ACPI_EC_COMMAND_READ 0x80
+#define ACPI_EC_COMMAND_WRITE 0x81
+#define ACPI_EC_COMMAND_QUERY 0x84
+
+static int acpi_ec_add (struct acpi_device *device);
+static int acpi_ec_remove (struct acpi_device *device, int type);
+static int acpi_ec_start (struct acpi_device *device);
+static int acpi_ec_stop (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_ec_driver = {
+ .name = ACPI_EC_DRIVER_NAME,
+ .class = ACPI_EC_CLASS,
+ .ids = ACPI_EC_HID,
+ .ops = {
+ .add = acpi_ec_add,
+ .remove = acpi_ec_remove,
+ .start = acpi_ec_start,
+ .stop = acpi_ec_stop,
+ },
+};
+
+struct acpi_ec {
+ acpi_handle handle;
+ unsigned long uid;
+ unsigned long gpe_bit;
+ struct acpi_generic_address status_addr;
+ struct acpi_generic_address command_addr;
+ struct acpi_generic_address data_addr;
+ unsigned long global_lock;
+ spinlock_t lock;
+};
+
+/* If we find an EC via the ECDT, we need to keep a ptr to its context */
+static struct acpi_ec *ec_ecdt;
+
+/* External interfaces use first EC only, so remember */
+static struct acpi_device *first_ec;
+
+/* --------------------------------------------------------------------------
+ Transaction Management
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_ec_wait (
+ struct acpi_ec *ec,
+ u8 event)
+{
+ u32 acpi_ec_status = 0;
+ u32 i = ACPI_EC_UDELAY_COUNT;
+
+ if (!ec)
+ return -EINVAL;
+
+ /* Poll the EC status register waiting for the event to occur. */
+ switch (event) {
+ case ACPI_EC_EVENT_OBF:
+ do {
+ acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
+ if (acpi_ec_status & ACPI_EC_FLAG_OBF)
+ return 0;
+ udelay(ACPI_EC_UDELAY);
+ } while (--i>0);
+ break;
+ case ACPI_EC_EVENT_IBE:
+ do {
+ acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
+ if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
+ return 0;
+ udelay(ACPI_EC_UDELAY);
+ } while (--i>0);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return -ETIME;
+}
+
+
+static int
+acpi_ec_read (
+ struct acpi_ec *ec,
+ u8 address,
+ u32 *data)
+{
+ acpi_status status = AE_OK;
+ int result = 0;
+ unsigned long flags = 0;
+ u32 glk = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_read");
+
+ if (!ec || !data)
+ return_VALUE(-EINVAL);
+
+ *data = 0;
+
+ if (ec->global_lock) {
+ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+ }
+
+ spin_lock_irqsave(&ec->lock, flags);
+
+ acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ if (result)
+ goto end;
+
+ acpi_hw_low_level_write(8, address, &ec->data_addr);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+ if (result)
+ goto end;
+
+
+ acpi_hw_low_level_read(8, data, &ec->data_addr);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
+ *data, address));
+
+end:
+ spin_unlock_irqrestore(&ec->lock, flags);
+
+ if (ec->global_lock)
+ acpi_release_global_lock(glk);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_ec_write (
+ struct acpi_ec *ec,
+ u8 address,
+ u8 data)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ unsigned long flags = 0;
+ u32 glk = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_write");
+
+ if (!ec)
+ return_VALUE(-EINVAL);
+
+ if (ec->global_lock) {
+ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+ }
+
+ spin_lock_irqsave(&ec->lock, flags);
+
+ acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ if (result)
+ goto end;
+
+ acpi_hw_low_level_write(8, address, &ec->data_addr);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ if (result)
+ goto end;
+
+ acpi_hw_low_level_write(8, data, &ec->data_addr);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ if (result)
+ goto end;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
+ data, address));
+
+end:
+ spin_unlock_irqrestore(&ec->lock, flags);
+
+ if (ec->global_lock)
+ acpi_release_global_lock(glk);
+
+ return_VALUE(result);
+}
+
+/*
+ * Externally callable EC access functions. For now, assume 1 EC only
+ */
+int
+ec_read(u8 addr, u8 *val)
+{
+ struct acpi_ec *ec;
+ int err;
+ u32 temp_data;
+
+ if (!first_ec)
+ return -ENODEV;
+
+ ec = acpi_driver_data(first_ec);
+
+ err = acpi_ec_read(ec, addr, &temp_data);
+
+ if (!err) {
+ *val = temp_data;
+ return 0;
+ }
+ else
+ return err;
+}
+EXPORT_SYMBOL(ec_read);
+
+int
+ec_write(u8 addr, u8 val)
+{
+ struct acpi_ec *ec;
+ int err;
+
+ if (!first_ec)
+ return -ENODEV;
+
+ ec = acpi_driver_data(first_ec);
+
+ err = acpi_ec_write(ec, addr, val);
+
+ return err;
+}
+EXPORT_SYMBOL(ec_write);
+
+
+static int
+acpi_ec_query (
+ struct acpi_ec *ec,
+ u32 *data)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ unsigned long flags = 0;
+ u32 glk = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_query");
+
+ if (!ec || !data)
+ return_VALUE(-EINVAL);
+
+ *data = 0;
+
+ if (ec->global_lock) {
+ status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+ }
+
+ /*
+ * Query the EC to find out which _Qxx method we need to evaluate.
+ * Note that successful completion of the query causes the ACPI_EC_SCI
+ * bit to be cleared (and thus clearing the interrupt source).
+ */
+ spin_lock_irqsave(&ec->lock, flags);
+
+ acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr);
+ result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+ if (result)
+ goto end;
+
+ acpi_hw_low_level_read(8, data, &ec->data_addr);
+ if (!*data)
+ result = -ENODATA;
+
+end:
+ spin_unlock_irqrestore(&ec->lock, flags);
+
+ if (ec->global_lock)
+ acpi_release_global_lock(glk);
+
+ return_VALUE(result);
+}
+
+
+/* --------------------------------------------------------------------------
+ Event Management
+ -------------------------------------------------------------------------- */
+
+struct acpi_ec_query_data {
+ acpi_handle handle;
+ u8 data;
+};
+
+static void
+acpi_ec_gpe_query (
+ void *ec_cxt)
+{
+ struct acpi_ec *ec = (struct acpi_ec *) ec_cxt;
+ u32 value = 0;
+ unsigned long flags = 0;
+ static char object_name[5] = {'_','Q','0','0','\0'};
+ const char hex[] = {'0','1','2','3','4','5','6','7',
+ '8','9','A','B','C','D','E','F'};
+
+ ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
+
+ if (!ec_cxt)
+ goto end;
+
+ spin_lock_irqsave(&ec->lock, flags);
+ acpi_hw_low_level_read(8, &value, &ec->command_addr);
+ spin_unlock_irqrestore(&ec->lock, flags);
+
+ /* TBD: Implement asynch events!
+ * NOTE: All we care about are EC-SCI's. Other EC events are
+ * handled via polling (yuck!). This is because some systems
+ * treat EC-SCIs as level (versus EDGE!) triggered, preventing
+ * a purely interrupt-driven approach (grumble, grumble).
+ */
+ if (!(value & ACPI_EC_FLAG_SCI))
+ goto end;
+
+ if (acpi_ec_query(ec, &value))
+ goto end;
+
+ object_name[2] = hex[((value >> 4) & 0x0F)];
+ object_name[3] = hex[(value & 0x0F)];
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
+
+ acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
+
+end:
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+}
+
+static u32
+acpi_ec_gpe_handler (
+ void *data)
+{
+ acpi_status status = AE_OK;
+ struct acpi_ec *ec = (struct acpi_ec *) data;
+
+ if (!ec)
+ return ACPI_INTERRUPT_NOT_HANDLED;
+
+ acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+
+ status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+ acpi_ec_gpe_query, ec);
+
+ if (status == AE_OK)
+ return ACPI_INTERRUPT_HANDLED;
+ else
+ return ACPI_INTERRUPT_NOT_HANDLED;
+}
+
+/* --------------------------------------------------------------------------
+ Address Space Management
+ -------------------------------------------------------------------------- */
+
+static acpi_status
+acpi_ec_space_setup (
+ acpi_handle region_handle,
+ u32 function,
+ void *handler_context,
+ void **return_context)
+{
+ /*
+ * The EC object is in the handler context and is needed
+ * when calling the acpi_ec_space_handler.
+ */
+ if(function == ACPI_REGION_DEACTIVATE)
+ *return_context = NULL;
+ else
+ *return_context = handler_context;
+
+ return AE_OK;
+}
+
+
+static acpi_status
+acpi_ec_space_handler (
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ int result = 0;
+ struct acpi_ec *ec = NULL;
+ u32 temp = 0;
+ acpi_integer f_v = 0;
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_space_handler");
+
+ if ((address > 0xFF) || !value || !handler_context)
+ return_VALUE(AE_BAD_PARAMETER);
+
+ if(bit_width != 8) {
+ printk(KERN_WARNING PREFIX "acpi_ec_space_handler: bit_width should be 8\n");
+ if (acpi_strict)
+ return_VALUE(AE_BAD_PARAMETER);
+ }
+
+ ec = (struct acpi_ec *) handler_context;
+
+next_byte:
+ switch (function) {
+ case ACPI_READ:
+ result = acpi_ec_read(ec, (u8) address, &temp);
+ *value = (acpi_integer) temp;
+ break;
+ case ACPI_WRITE:
+ result = acpi_ec_write(ec, (u8) address, (u8) *value);
+ break;
+ default:
+ result = -EINVAL;
+ goto out;
+ break;
+ }
+
+ bit_width -= 8;
+ if(bit_width){
+
+ if(function == ACPI_READ)
+ f_v |= (acpi_integer) (*value) << 8*i;
+ if(function == ACPI_WRITE)
+ (*value) >>=8;
+ i++;
+ goto next_byte;
+ }
+
+
+ if(function == ACPI_READ){
+ f_v |= (acpi_integer) (*value) << 8*i;
+ *value = f_v;
+ }
+
+
+out:
+ switch (result) {
+ case -EINVAL:
+ return_VALUE(AE_BAD_PARAMETER);
+ break;
+ case -ENODEV:
+ return_VALUE(AE_NOT_FOUND);
+ break;
+ case -ETIME:
+ return_VALUE(AE_TIME);
+ break;
+ default:
+ return_VALUE(AE_OK);
+ }
+
+
+}
+
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_ec_dir;
+
+
+static int
+acpi_ec_read_info (struct seq_file *seq, void *offset)
+{
+ struct acpi_ec *ec = (struct acpi_ec *) seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_read_info");
+
+ if (!ec)
+ goto end;
+
+ seq_printf(seq, "gpe bit: 0x%02x\n",
+ (u32) ec->gpe_bit);
+ seq_printf(seq, "ports: 0x%02x, 0x%02x\n",
+ (u32) ec->status_addr.address, (u32) ec->data_addr.address);
+ seq_printf(seq, "use global lock: %s\n",
+ ec->global_lock?"yes":"no");
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_ec_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_ec_read_info, PDE(inode)->data);
+}
+
+static struct file_operations acpi_ec_info_ops = {
+ .open = acpi_ec_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int
+acpi_ec_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_add_fs");
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_ec_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ }
+
+ entry = create_proc_entry(ACPI_EC_FILE_INFO, S_IRUGO,
+ acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Unable to create '%s' fs entry\n",
+ ACPI_EC_FILE_INFO));
+ else {
+ entry->proc_fops = &acpi_ec_info_ops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_ec_remove_fs (
+ struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_ec_remove_fs");
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_EC_FILE_INFO, acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device), acpi_ec_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_ec_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_ec *ec = NULL;
+ unsigned long uid;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ ec = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec)
+ return_VALUE(-ENOMEM);
+ memset(ec, 0, sizeof(struct acpi_ec));
+
+ ec->handle = device->handle;
+ ec->uid = -1;
+ spin_lock_init(&ec->lock);
+ strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_EC_CLASS);
+ acpi_driver_data(device) = ec;
+
+ /* Use the global lock for all EC transactions? */
+ acpi_evaluate_integer(ec->handle, "_GLK", NULL, &ec->global_lock);
+
+ /* If our UID matches the UID for the ECDT-enumerated EC,
+ we now have the *real* EC info, so kill the makeshift one.*/
+ acpi_evaluate_integer(ec->handle, "_UID", NULL, &uid);
+ if (ec_ecdt && ec_ecdt->uid == uid) {
+ acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
+
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler);
+
+ kfree(ec_ecdt);
+ }
+
+ /* Get GPE bit assignment (EC events). */
+ /* TODO: Add support for _GPE returning a package */
+ status = acpi_evaluate_integer(ec->handle, "_GPE", NULL, &ec->gpe_bit);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error obtaining GPE bit assignment\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ result = acpi_ec_add_fs(device);
+ if (result)
+ goto end;
+
+ printk(KERN_INFO PREFIX "%s [%s] (gpe %d)\n",
+ acpi_device_name(device), acpi_device_bid(device),
+ (u32) ec->gpe_bit);
+
+ if (!first_ec)
+ first_ec = device;
+
+end:
+ if (result)
+ kfree(ec);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_ec_remove (
+ struct acpi_device *device,
+ int type)
+{
+ struct acpi_ec *ec = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_remove");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ ec = acpi_driver_data(device);
+
+ acpi_ec_remove_fs(device);
+
+ kfree(ec);
+
+ return_VALUE(0);
+}
+
+
+static acpi_status
+acpi_ec_io_ports (
+ struct acpi_resource *resource,
+ void *context)
+{
+ struct acpi_ec *ec = (struct acpi_ec *) context;
+ struct acpi_generic_address *addr;
+
+ if (resource->id != ACPI_RSTYPE_IO) {
+ return AE_OK;
+ }
+
+ /*
+ * The first address region returned is the data port, and
+ * the second address region returned is the status/command
+ * port.
+ */
+ if (ec->data_addr.register_bit_width == 0) {
+ addr = &ec->data_addr;
+ } else if (ec->command_addr.register_bit_width == 0) {
+ addr = &ec->command_addr;
+ } else {
+ return AE_CTRL_TERMINATE;
+ }
+
+ addr->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+ addr->register_bit_width = 8;
+ addr->register_bit_offset = 0;
+ addr->address = resource->data.io.min_base_address;
+
+ return AE_OK;
+}
+
+
+static int
+acpi_ec_start (
+ struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ struct acpi_ec *ec = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_start");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ ec = acpi_driver_data(device);
+
+ if (!ec)
+ return_VALUE(-EINVAL);
+
+ /*
+ * Get I/O port addresses. Convert to GAS format.
+ */
+ status = acpi_walk_resources(ec->handle, METHOD_NAME__CRS,
+ acpi_ec_io_ports, ec);
+ if (ACPI_FAILURE(status) || ec->command_addr.register_bit_width == 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error getting I/O port addresses"));
+ return_VALUE(-ENODEV);
+ }
+
+ ec->status_addr = ec->command_addr;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02x, ports=0x%2x,0x%2x\n",
+ (u32) ec->gpe_bit, (u32) ec->command_addr.address,
+ (u32) ec->data_addr.address));
+
+ /*
+ * Install GPE handler
+ */
+ status = acpi_install_gpe_handler(NULL, ec->gpe_bit,
+ ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler, ec);
+ if (ACPI_FAILURE(status)) {
+ return_VALUE(-ENODEV);
+ }
+ acpi_set_gpe_type (NULL, ec->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe (NULL, ec->gpe_bit, ACPI_NOT_ISR);
+
+ status = acpi_install_address_space_handler (ec->handle,
+ ACPI_ADR_SPACE_EC, &acpi_ec_space_handler,
+ &acpi_ec_space_setup, ec);
+ if (ACPI_FAILURE(status)) {
+ acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(AE_OK);
+}
+
+
+static int
+acpi_ec_stop (
+ struct acpi_device *device,
+ int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_ec *ec = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_stop");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ ec = acpi_driver_data(device);
+
+ status = acpi_remove_address_space_handler(ec->handle,
+ ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ status = acpi_remove_gpe_handler(NULL, ec->gpe_bit, &acpi_ec_gpe_handler);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ return_VALUE(0);
+}
+
+static acpi_status __init
+acpi_fake_ecdt_callback (
+ acpi_handle handle,
+ u32 Level,
+ void *context,
+ void **retval)
+{
+ acpi_status status;
+
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ acpi_ec_io_ports, ec_ecdt);
+ if (ACPI_FAILURE(status))
+ return status;
+ ec_ecdt->status_addr = ec_ecdt->command_addr;
+
+ ec_ecdt->uid = -1;
+ acpi_evaluate_integer(handle, "_UID", NULL, &ec_ecdt->uid);
+
+ status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit);
+ if (ACPI_FAILURE(status))
+ return status;
+ spin_lock_init(&ec_ecdt->lock);
+ ec_ecdt->global_lock = TRUE;
+ ec_ecdt->handle = handle;
+
+ printk(KERN_INFO PREFIX "GPE=0x%02x, ports=0x%2x, 0x%2x\n",
+ (u32) ec_ecdt->gpe_bit, (u32) ec_ecdt->command_addr.address,
+ (u32) ec_ecdt->data_addr.address);
+
+ return AE_CTRL_TERMINATE;
+}
+
+/*
+ * Some BIOS (such as some from Gateway laptops) access EC region very early
+ * such as in BAT0._INI or EC._INI before an EC device is found and
+ * do not provide an ECDT. According to ACPI spec, ECDT isn't mandatorily
+ * required, but if EC regison is accessed early, it is required.
+ * The routine tries to workaround the BIOS bug by pre-scan EC device
+ * It assumes that _CRS, _HID, _GPE, _UID methods of EC don't touch any
+ * op region (since _REG isn't invoked yet). The assumption is true for
+ * all systems found.
+ */
+static int __init
+acpi_ec_fake_ecdt(void)
+{
+ acpi_status status;
+ int ret = 0;
+
+ printk(KERN_INFO PREFIX "Try to make an fake ECDT\n");
+
+ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec_ecdt) {
+ ret = -ENOMEM;
+ goto error;
+ }
+ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+
+ status = acpi_get_devices (ACPI_EC_HID,
+ acpi_fake_ecdt_callback,
+ NULL,
+ NULL);
+ if (ACPI_FAILURE(status)) {
+ kfree(ec_ecdt);
+ ec_ecdt = NULL;
+ ret = -ENODEV;
+ goto error;
+ }
+ return 0;
+error:
+ printk(KERN_ERR PREFIX "Can't make an fake ECDT\n");
+ return ret;
+}
+
+static int __init
+acpi_ec_get_real_ecdt(void)
+{
+ acpi_status status;
+ struct acpi_table_ecdt *ecdt_ptr;
+
+ status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
+ (struct acpi_table_header **) &ecdt_ptr);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ printk(KERN_INFO PREFIX "Found ECDT\n");
+
+ /*
+ * Generate a temporary ec context to use until the namespace is scanned
+ */
+ ec_ecdt = kmalloc(sizeof(struct acpi_ec), GFP_KERNEL);
+ if (!ec_ecdt)
+ return -ENOMEM;
+ memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+
+ ec_ecdt->command_addr = ecdt_ptr->ec_control;
+ ec_ecdt->status_addr = ecdt_ptr->ec_control;
+ ec_ecdt->data_addr = ecdt_ptr->ec_data;
+ ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
+ spin_lock_init(&ec_ecdt->lock);
+ /* use the GL just to be safe */
+ ec_ecdt->global_lock = TRUE;
+ ec_ecdt->uid = ecdt_ptr->uid;
+
+ status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+ if (ACPI_FAILURE(status)) {
+ goto error;
+ }
+
+ return 0;
+error:
+ printk(KERN_ERR PREFIX "Could not use ECDT\n");
+ kfree(ec_ecdt);
+ ec_ecdt = NULL;
+
+ return -ENODEV;
+}
+
+static int __initdata acpi_fake_ecdt_enabled;
+int __init
+acpi_ec_ecdt_probe (void)
+{
+ acpi_status status;
+ int ret;
+
+ ret = acpi_ec_get_real_ecdt();
+ /* Try to make a fake ECDT */
+ if (ret && acpi_fake_ecdt_enabled) {
+ ret = acpi_ec_fake_ecdt();
+ }
+
+ if (ret)
+ return 0;
+
+ /*
+ * Install GPE handler
+ */
+ status = acpi_install_gpe_handler(NULL, ec_ecdt->gpe_bit,
+ ACPI_GPE_EDGE_TRIGGERED, &acpi_ec_gpe_handler,
+ ec_ecdt);
+ if (ACPI_FAILURE(status)) {
+ goto error;
+ }
+ acpi_set_gpe_type (NULL, ec_ecdt->gpe_bit, ACPI_GPE_TYPE_RUNTIME);
+ acpi_enable_gpe (NULL, ec_ecdt->gpe_bit, ACPI_NOT_ISR);
+
+ status = acpi_install_address_space_handler (ACPI_ROOT_OBJECT,
+ ACPI_ADR_SPACE_EC, &acpi_ec_space_handler,
+ &acpi_ec_space_setup, ec_ecdt);
+ if (ACPI_FAILURE(status)) {
+ acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit,
+ &acpi_ec_gpe_handler);
+ goto error;
+ }
+
+ return 0;
+
+error:
+ printk(KERN_ERR PREFIX "Could not use ECDT\n");
+ kfree(ec_ecdt);
+ ec_ecdt = NULL;
+
+ return -ENODEV;
+}
+
+
+static int __init acpi_ec_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_init");
+
+ if (acpi_disabled)
+ return_VALUE(0);
+
+ acpi_ec_dir = proc_mkdir(ACPI_EC_CLASS, acpi_root_dir);
+ if (!acpi_ec_dir)
+ return_VALUE(-ENODEV);
+
+ /* Now register the driver for the EC */
+ result = acpi_bus_register_driver(&acpi_ec_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(result);
+}
+
+subsys_initcall(acpi_ec_init);
+
+/* EC driver currently not unloadable */
+#if 0
+static void __exit
+acpi_ec_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_ec_exit");
+
+ acpi_bus_unregister_driver(&acpi_ec_driver);
+
+ remove_proc_entry(ACPI_EC_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+#endif /* 0 */
+
+static int __init acpi_fake_ecdt_setup(char *str)
+{
+ acpi_fake_ecdt_enabled = 1;
+ return 0;
+}
+__setup("acpi_fake_ecdt", acpi_fake_ecdt_setup);
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
new file mode 100644
index 000000000000..43c49f66a328
--- /dev/null
+++ b/drivers/acpi/event.c
@@ -0,0 +1,140 @@
+/*
+ * event.c - exporting ACPI events via procfs
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ *
+ */
+
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <acpi/acpi_drivers.h>
+
+#define _COMPONENT ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME ("event")
+
+/* Global vars for handling event proc entry */
+static DEFINE_SPINLOCK(acpi_system_event_lock);
+int event_is_open = 0;
+extern struct list_head acpi_bus_event_list;
+extern wait_queue_head_t acpi_bus_event_queue;
+
+static int
+acpi_system_open_event(struct inode *inode, struct file *file)
+{
+ spin_lock_irq (&acpi_system_event_lock);
+
+ if(event_is_open)
+ goto out_busy;
+
+ event_is_open = 1;
+
+ spin_unlock_irq (&acpi_system_event_lock);
+ return 0;
+
+out_busy:
+ spin_unlock_irq (&acpi_system_event_lock);
+ return -EBUSY;
+}
+
+static ssize_t
+acpi_system_read_event (
+ struct file *file,
+ char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ int result = 0;
+ struct acpi_bus_event event;
+ static char str[ACPI_MAX_STRING];
+ static int chars_remaining = 0;
+ static char *ptr;
+
+
+ ACPI_FUNCTION_TRACE("acpi_system_read_event");
+
+ if (!chars_remaining) {
+ memset(&event, 0, sizeof(struct acpi_bus_event));
+
+ if ((file->f_flags & O_NONBLOCK)
+ && (list_empty(&acpi_bus_event_list)))
+ return_VALUE(-EAGAIN);
+
+ result = acpi_bus_receive_event(&event);
+ if (result) {
+ return_VALUE(-EIO);
+ }
+
+ chars_remaining = sprintf(str, "%s %s %08x %08x\n",
+ event.device_class?event.device_class:"<unknown>",
+ event.bus_id?event.bus_id:"<unknown>",
+ event.type, event.data);
+ ptr = str;
+ }
+
+ if (chars_remaining < count) {
+ count = chars_remaining;
+ }
+
+ if (copy_to_user(buffer, ptr, count))
+ return_VALUE(-EFAULT);
+
+ *ppos += count;
+ chars_remaining -= count;
+ ptr += count;
+
+ return_VALUE(count);
+}
+
+static int
+acpi_system_close_event(struct inode *inode, struct file *file)
+{
+ spin_lock_irq (&acpi_system_event_lock);
+ event_is_open = 0;
+ spin_unlock_irq (&acpi_system_event_lock);
+ return 0;
+}
+
+static unsigned int
+acpi_system_poll_event(
+ struct file *file,
+ poll_table *wait)
+{
+ poll_wait(file, &acpi_bus_event_queue, wait);
+ if (!list_empty(&acpi_bus_event_list))
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+static struct file_operations acpi_system_event_ops = {
+ .open = acpi_system_open_event,
+ .read = acpi_system_read_event,
+ .release = acpi_system_close_event,
+ .poll = acpi_system_poll_event,
+};
+
+static int __init acpi_event_init(void)
+{
+ struct proc_dir_entry *entry;
+ int error = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_event_init");
+
+ if (acpi_disabled)
+ return_VALUE(0);
+
+ /* 'event' [R] */
+ entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
+ if (entry)
+ entry->proc_fops = &acpi_system_event_ops;
+ else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' proc fs entry\n","event" ));
+ error = -EFAULT;
+ }
+ return_VALUE(error);
+}
+
+subsys_initcall(acpi_event_init);
diff --git a/drivers/acpi/events/Makefile b/drivers/acpi/events/Makefile
new file mode 100644
index 000000000000..d29f2ee449cc
--- /dev/null
+++ b/drivers/acpi/events/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := evevent.o evregion.o evsci.o evxfevnt.o \
+ evmisc.o evrgnini.o evxface.o evxfregn.o \
+ evgpe.o evgpeblk.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
new file mode 100644
index 000000000000..2a213604ae51
--- /dev/null
+++ b/drivers/acpi/events/evevent.c
@@ -0,0 +1,297 @@
+/******************************************************************************
+ *
+ * Module Name: evevent - Fixed Event handling and dispatch
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evevent")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_initialize_events
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize global data structures for events.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_initialize_events (
+ void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_initialize_events");
+
+
+ /* Make sure we have ACPI tables */
+
+ if (!acpi_gbl_DSDT) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No ACPI tables present!\n"));
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ /*
+ * Initialize the Fixed and General Purpose Events. This is
+ * done prior to enabling SCIs to prevent interrupts from
+ * occurring before handers are installed.
+ */
+ status = acpi_ev_fixed_event_initialize ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "Unable to initialize fixed events, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ev_gpe_initialize ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "Unable to initialize general purpose events, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_xrupt_handlers
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install interrupt handlers for the SCI and Global Lock
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_install_xrupt_handlers (
+ void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_install_xrupt_handlers");
+
+
+ /* Install the SCI handler */
+
+ status = acpi_ev_install_sci_handler ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "Unable to install System Control Interrupt Handler, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ /* Install the handler for the Global Lock */
+
+ status = acpi_ev_init_global_lock_handler ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "Unable to initialize Global Lock handler, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ acpi_gbl_events_initialized = TRUE;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_fixed_event_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install the fixed event handlers and enable the fixed events.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_fixed_event_initialize (
+ void)
+{
+ acpi_native_uint i;
+ acpi_status status;
+
+
+ /*
+ * Initialize the structure that keeps track of fixed event handlers
+ * and enable the fixed events.
+ */
+ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+ acpi_gbl_fixed_event_handlers[i].handler = NULL;
+ acpi_gbl_fixed_event_handlers[i].context = NULL;
+
+ /* Enable the fixed event */
+
+ if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
+ status = acpi_set_register (acpi_gbl_fixed_event_info[i].enable_register_id,
+ 0, ACPI_MTX_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_fixed_event_detect
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Checks the PM status register for fixed events
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_fixed_event_detect (
+ void)
+{
+ u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
+ u32 fixed_status;
+ u32 fixed_enable;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_NAME ("ev_fixed_event_detect");
+
+
+ /*
+ * Read the fixed feature status and enable registers, as all the cases
+ * depend on their values. Ignore errors here.
+ */
+ (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, &fixed_status);
+ (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
+ "Fixed Event Block: Enable %08X Status %08X\n",
+ fixed_enable, fixed_status));
+
+ /*
+ * Check for all possible Fixed Events and dispatch those that are active
+ */
+ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+ /* Both the status and enable bits must be on for this event */
+
+ if ((fixed_status & acpi_gbl_fixed_event_info[i].status_bit_mask) &&
+ (fixed_enable & acpi_gbl_fixed_event_info[i].enable_bit_mask)) {
+ /* Found an active (signalled) event */
+
+ int_status |= acpi_ev_fixed_event_dispatch ((u32) i);
+ }
+ }
+
+ return (int_status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_fixed_event_dispatch
+ *
+ * PARAMETERS: Event - Event type
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Clears the status bit for the requested event, calls the
+ * handler that previously registered for the event.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_fixed_event_dispatch (
+ u32 event)
+{
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Clear the status bit */
+
+ (void) acpi_set_register (acpi_gbl_fixed_event_info[event].status_register_id,
+ 1, ACPI_MTX_DO_NOT_LOCK);
+
+ /*
+ * Make sure we've got a handler. If not, report an error.
+ * The event is disabled to prevent further interrupts.
+ */
+ if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
+ (void) acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id,
+ 0, ACPI_MTX_DO_NOT_LOCK);
+
+ ACPI_REPORT_ERROR (
+ ("No installed handler for fixed event [%08X]\n",
+ event));
+
+ return (ACPI_INTERRUPT_NOT_HANDLED);
+ }
+
+ /* Invoke the Fixed Event handler */
+
+ return ((acpi_gbl_fixed_event_handlers[event].handler)(
+ acpi_gbl_fixed_event_handlers[event].context));
+}
+
+
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
new file mode 100644
index 000000000000..118d72ac7c76
--- /dev/null
+++ b/drivers/acpi/events/evgpe.c
@@ -0,0 +1,756 @@
+/******************************************************************************
+ *
+ * Module Name: evgpe - General Purpose Event handling and dispatch
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evgpe")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_set_gpe_type
+ *
+ * PARAMETERS: gpe_event_info - GPE to set
+ * Type - New type
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Sets the new type for the GPE (wake, run, or wake/run)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_set_gpe_type (
+ struct acpi_gpe_event_info *gpe_event_info,
+ u8 type)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_set_gpe_type");
+
+
+ /* Validate type and update register enable masks */
+
+ switch (type) {
+ case ACPI_GPE_TYPE_WAKE:
+ case ACPI_GPE_TYPE_RUNTIME:
+ case ACPI_GPE_TYPE_WAKE_RUN:
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Disable the GPE if currently enabled */
+
+ status = acpi_ev_disable_gpe (gpe_event_info);
+
+ /* Type was validated above */
+
+ gpe_event_info->flags &= ~ACPI_GPE_TYPE_MASK; /* Clear type bits */
+ gpe_event_info->flags |= type; /* Insert type */
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_update_gpe_enable_masks
+ *
+ * PARAMETERS: gpe_event_info - GPE to update
+ * Type - What to do: ACPI_GPE_DISABLE or
+ * ACPI_GPE_ENABLE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Updates GPE register enable masks based on the GPE type
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_update_gpe_enable_masks (
+ struct acpi_gpe_event_info *gpe_event_info,
+ u8 type)
+{
+ struct acpi_gpe_register_info *gpe_register_info;
+ u8 register_bit;
+
+
+ ACPI_FUNCTION_TRACE ("ev_update_gpe_enable_masks");
+
+
+ gpe_register_info = gpe_event_info->register_info;
+ if (!gpe_register_info) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+ register_bit = gpe_event_info->register_bit;
+
+ /* 1) Disable case. Simply clear all enable bits */
+
+ if (type == ACPI_GPE_DISABLE) {
+ ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit);
+ ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit);
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* 2) Enable case. Set/Clear the appropriate enable bits */
+
+ switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
+ case ACPI_GPE_TYPE_WAKE:
+ ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit);
+ ACPI_CLEAR_BIT (gpe_register_info->enable_for_run, register_bit);
+ break;
+
+ case ACPI_GPE_TYPE_RUNTIME:
+ ACPI_CLEAR_BIT (gpe_register_info->enable_for_wake, register_bit);
+ ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit);
+ break;
+
+ case ACPI_GPE_TYPE_WAKE_RUN:
+ ACPI_SET_BIT (gpe_register_info->enable_for_wake, register_bit);
+ ACPI_SET_BIT (gpe_register_info->enable_for_run, register_bit);
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_enable_gpe
+ *
+ * PARAMETERS: gpe_event_info - GPE to enable
+ * write_to_hardware - Enable now, or just mark data structs
+ * (WAKE GPEs should be deferred)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable a GPE based on the GPE type
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_enable_gpe (
+ struct acpi_gpe_event_info *gpe_event_info,
+ u8 write_to_hardware)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_enable_gpe");
+
+
+ /* Make sure HW enable masks are updated */
+
+ status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_ENABLE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Mark wake-enabled or HW enable, or both */
+
+ switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
+ case ACPI_GPE_TYPE_WAKE:
+
+ ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
+ break;
+
+ case ACPI_GPE_TYPE_WAKE_RUN:
+
+ ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
+
+ /*lint -fallthrough */
+
+ case ACPI_GPE_TYPE_RUNTIME:
+
+ ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
+
+ if (write_to_hardware) {
+ /* Clear the GPE (of stale events), then enable it */
+
+ status = acpi_hw_clear_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Enable the requested runtime GPE */
+
+ status = acpi_hw_write_gpe_enable_reg (gpe_event_info);
+ }
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_disable_gpe
+ *
+ * PARAMETERS: gpe_event_info - GPE to disable
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable a GPE based on the GPE type
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_disable_gpe (
+ struct acpi_gpe_event_info *gpe_event_info)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_disable_gpe");
+
+
+ if (!(gpe_event_info->flags & ACPI_GPE_ENABLE_MASK)) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Make sure HW enable masks are updated */
+
+ status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Mark wake-disabled or HW disable, or both */
+
+ switch (gpe_event_info->flags & ACPI_GPE_TYPE_MASK) {
+ case ACPI_GPE_TYPE_WAKE:
+ ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
+ break;
+
+ case ACPI_GPE_TYPE_WAKE_RUN:
+ ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
+
+ /*lint -fallthrough */
+
+ case ACPI_GPE_TYPE_RUNTIME:
+
+ /* Disable the requested runtime GPE */
+
+ ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
+ status = acpi_hw_write_gpe_enable_reg (gpe_event_info);
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_get_gpe_event_info
+ *
+ * PARAMETERS: gpe_device - Device node. NULL for GPE0/GPE1
+ * gpe_number - Raw GPE number
+ *
+ * RETURN: A GPE event_info struct. NULL if not a valid GPE
+ *
+ * DESCRIPTION: Returns the event_info struct associated with this GPE.
+ * Validates the gpe_block and the gpe_number
+ *
+ * Should be called only when the GPE lists are semaphore locked
+ * and not subject to change.
+ *
+ ******************************************************************************/
+
+struct acpi_gpe_event_info *
+acpi_ev_get_gpe_event_info (
+ acpi_handle gpe_device,
+ u32 gpe_number)
+{
+ union acpi_operand_object *obj_desc;
+ struct acpi_gpe_block_info *gpe_block;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* A NULL gpe_block means use the FADT-defined GPE block(s) */
+
+ if (!gpe_device) {
+ /* Examine GPE Block 0 and 1 (These blocks are permanent) */
+
+ for (i = 0; i < ACPI_MAX_GPE_BLOCKS; i++) {
+ gpe_block = acpi_gbl_gpe_fadt_blocks[i];
+ if (gpe_block) {
+ if ((gpe_number >= gpe_block->block_base_number) &&
+ (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) {
+ return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]);
+ }
+ }
+ }
+
+ /* The gpe_number was not in the range of either FADT GPE block */
+
+ return (NULL);
+ }
+
+ /* A Non-NULL gpe_device means this is a GPE Block Device */
+
+ obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) gpe_device);
+ if (!obj_desc ||
+ !obj_desc->device.gpe_block) {
+ return (NULL);
+ }
+
+ gpe_block = obj_desc->device.gpe_block;
+
+ if ((gpe_number >= gpe_block->block_base_number) &&
+ (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) {
+ return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]);
+ }
+
+ return (NULL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_gpe_detect
+ *
+ * PARAMETERS: gpe_xrupt_list - Interrupt block for this interrupt.
+ * Can have multiple GPE blocks attached.
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Detect if any GP events have occurred. This function is
+ * executed at interrupt level.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_gpe_detect (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_list)
+{
+ u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
+ u8 enabled_status_byte;
+ struct acpi_gpe_register_info *gpe_register_info;
+ u32 status_reg;
+ u32 enable_reg;
+ acpi_status status;
+ struct acpi_gpe_block_info *gpe_block;
+ acpi_native_uint i;
+ acpi_native_uint j;
+
+
+ ACPI_FUNCTION_NAME ("ev_gpe_detect");
+
+ /* Check for the case where there are no GPEs */
+
+ if (!gpe_xrupt_list) {
+ return (int_status);
+ }
+
+ /* Examine all GPE blocks attached to this interrupt level */
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_ISR);
+ gpe_block = gpe_xrupt_list->gpe_block_list_head;
+ while (gpe_block) {
+ /*
+ * Read all of the 8-bit GPE status and enable registers
+ * in this GPE block, saving all of them.
+ * Find all currently active GP events.
+ */
+ for (i = 0; i < gpe_block->register_count; i++) {
+ /* Get the next status/enable pair */
+
+ gpe_register_info = &gpe_block->register_info[i];
+
+ /* Read the Status Register */
+
+ status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &status_reg,
+ &gpe_register_info->status_address);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Read the Enable Register */
+
+ status = acpi_hw_low_level_read (ACPI_GPE_REGISTER_WIDTH, &enable_reg,
+ &gpe_register_info->enable_address);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
+ "Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
+ gpe_register_info->base_gpe_number, status_reg, enable_reg));
+
+ /* First check if there is anything active at all in this register */
+
+ enabled_status_byte = (u8) (status_reg & enable_reg);
+ if (!enabled_status_byte) {
+ /* No active GPEs in this register, move on */
+
+ continue;
+ }
+
+ /* Now look at the individual GPEs in this byte register */
+
+ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+ /* Examine one GPE bit */
+
+ if (enabled_status_byte & acpi_gbl_decode_to8bit[j]) {
+ /*
+ * Found an active GPE. Dispatch the event to a handler
+ * or method.
+ */
+ int_status |= acpi_ev_gpe_dispatch (
+ &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j],
+ (u32) j + gpe_register_info->base_gpe_number);
+ }
+ }
+ }
+
+ gpe_block = gpe_block->next;
+ }
+
+unlock_and_exit:
+
+ acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_ISR);
+ return (int_status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_asynch_execute_gpe_method
+ *
+ * PARAMETERS: Context (gpe_event_info) - Info for this GPE
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Perform the actual execution of a GPE control method. This
+ * function is called from an invocation of acpi_os_queue_for_execution
+ * (and therefore does NOT execute at interrupt level) so that
+ * the control method itself is not executed in the context of
+ * an interrupt handler.
+ *
+ ******************************************************************************/
+
+static void ACPI_SYSTEM_XFACE
+acpi_ev_asynch_execute_gpe_method (
+ void *context)
+{
+ struct acpi_gpe_event_info *gpe_event_info = (void *) context;
+ u32 gpe_number = 0;
+ acpi_status status;
+ struct acpi_gpe_event_info local_gpe_event_info;
+ struct acpi_parameter_info info;
+
+
+ ACPI_FUNCTION_TRACE ("ev_asynch_execute_gpe_method");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_VOID;
+ }
+
+ /* Must revalidate the gpe_number/gpe_block */
+
+ if (!acpi_ev_valid_gpe_event (gpe_event_info)) {
+ status = acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_VOID;
+ }
+
+ /* Set the GPE flags for return to enabled state */
+
+ (void) acpi_ev_enable_gpe (gpe_event_info, FALSE);
+
+ /*
+ * Take a snapshot of the GPE info for this level - we copy the
+ * info to prevent a race condition with remove_handler/remove_block.
+ */
+ ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, sizeof (struct acpi_gpe_event_info));
+
+ status = acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_VOID;
+ }
+
+ /*
+ * Must check for control method type dispatch one more
+ * time to avoid race with ev_gpe_install_handler
+ */
+ if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) {
+ /*
+ * Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
+ * control method that corresponds to this GPE
+ */
+ info.node = local_gpe_event_info.dispatch.method_node;
+ info.parameters = ACPI_CAST_PTR (union acpi_operand_object *, gpe_event_info);
+ info.parameter_type = ACPI_PARAM_GPE;
+
+ status = acpi_ns_evaluate_by_handle (&info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "%s while evaluating method [%4.4s] for GPE[%2X]\n",
+ acpi_format_exception (status),
+ acpi_ut_get_node_name (local_gpe_event_info.dispatch.method_node),
+ gpe_number));
+ }
+ }
+
+ if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
+ /*
+ * GPE is level-triggered, we clear the GPE status bit after
+ * handling the event.
+ */
+ status = acpi_hw_clear_gpe (&local_gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ return_VOID;
+ }
+ }
+
+ /* Enable this GPE */
+
+ (void) acpi_hw_write_gpe_enable_reg (&local_gpe_event_info);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_gpe_dispatch
+ *
+ * PARAMETERS: gpe_event_info - info for this GPE
+ * gpe_number - Number relative to the parent GPE block
+ *
+ * RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Dispatch a General Purpose Event to either a function (e.g. EC)
+ * or method (e.g. _Lxx/_Exx) handler.
+ *
+ * This function executes at interrupt level.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_gpe_dispatch (
+ struct acpi_gpe_event_info *gpe_event_info,
+ u32 gpe_number)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_gpe_dispatch");
+
+
+ /*
+ * If edge-triggered, clear the GPE status bit now. Note that
+ * level-triggered events are cleared after the GPE is serviced.
+ */
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) {
+ status = acpi_hw_clear_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n",
+ acpi_format_exception (status), gpe_number));
+ return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
+ }
+ }
+
+ /* Save current system state */
+
+ if (acpi_gbl_system_awake_and_running) {
+ ACPI_SET_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
+ }
+ else {
+ ACPI_CLEAR_BIT (gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
+ }
+
+ /*
+ * Dispatch the GPE to either an installed handler, or the control
+ * method associated with this GPE (_Lxx or _Exx).
+ * If a handler exists, we invoke it and do not attempt to run the method.
+ * If there is neither a handler nor a method, we disable the level to
+ * prevent further events from coming in here.
+ */
+ switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
+ case ACPI_GPE_DISPATCH_HANDLER:
+
+ /*
+ * Invoke the installed handler (at interrupt level)
+ * Ignore return status for now. TBD: leave GPE disabled on error?
+ */
+ (void) gpe_event_info->dispatch.handler->address (
+ gpe_event_info->dispatch.handler->context);
+
+ /* It is now safe to clear level-triggered events. */
+
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
+ status = acpi_hw_clear_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n",
+ acpi_format_exception (status), gpe_number));
+ return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
+ }
+ }
+ break;
+
+ case ACPI_GPE_DISPATCH_METHOD:
+
+ /*
+ * Disable GPE, so it doesn't keep firing before the method has a
+ * chance to run.
+ */
+ status = acpi_ev_disable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "acpi_ev_gpe_dispatch: %s, Unable to disable GPE[%2X]\n",
+ acpi_format_exception (status), gpe_number));
+ return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
+ }
+
+ /*
+ * Execute the method associated with the GPE
+ * NOTE: Level-triggered GPEs are cleared after the method completes.
+ */
+ status = acpi_os_queue_for_execution (OSD_PRIORITY_GPE,
+ acpi_ev_asynch_execute_gpe_method, gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "acpi_ev_gpe_dispatch: %s, Unable to queue handler for GPE[%2X] - event disabled\n",
+ acpi_format_exception (status), gpe_number));
+ }
+ break;
+
+ default:
+
+ /* No handler or method to run! */
+
+ ACPI_REPORT_ERROR ((
+ "acpi_ev_gpe_dispatch: No handler or method for GPE[%2X], disabling event\n",
+ gpe_number));
+
+ /*
+ * Disable the GPE. The GPE will remain disabled until the ACPI
+ * Core Subsystem is restarted, or a handler is installed.
+ */
+ status = acpi_ev_disable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "acpi_ev_gpe_dispatch: %s, Unable to disable GPE[%2X]\n",
+ acpi_format_exception (status), gpe_number));
+ return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
+ }
+ break;
+ }
+
+ return_VALUE (ACPI_INTERRUPT_HANDLED);
+}
+
+
+#ifdef ACPI_GPE_NOTIFY_CHECK
+
+/*******************************************************************************
+ * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
+ *
+ * FUNCTION: acpi_ev_check_for_wake_only_gpe
+ *
+ * PARAMETERS: gpe_event_info - info for this GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Determine if a a GPE is "wake-only".
+ *
+ * Called from Notify() code in interpreter when a "device_wake"
+ * Notify comes in.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_check_for_wake_only_gpe (
+ struct acpi_gpe_event_info *gpe_event_info)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_check_for_wake_only_gpe");
+
+
+ if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */
+ ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) /* System state at GPE time */ {
+ /* This must be a wake-only GPE, disable it */
+
+ status = acpi_ev_disable_gpe (gpe_event_info);
+
+ /* Set GPE to wake-only. Do not change wake disabled/enabled status */
+
+ acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE);
+
+ ACPI_REPORT_INFO (("GPE %p was updated from wake/run to wake-only\n",
+ gpe_event_info));
+
+ /* This was a wake-only GPE */
+
+ return_ACPI_STATUS (AE_WAKE_ONLY_GPE);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+#endif
+
+
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
new file mode 100644
index 000000000000..00d981f53c6a
--- /dev/null
+++ b/drivers/acpi/events/evgpeblk.c
@@ -0,0 +1,1141 @@
+/******************************************************************************
+ *
+ * Module Name: evgpeblk - GPE block creation and initialization.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evgpeblk")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_valid_gpe_event
+ *
+ * PARAMETERS: gpe_event_info - Info for this GPE
+ *
+ * RETURN: TRUE if the gpe_event is valid
+ *
+ * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL.
+ * Should be called only when the GPE lists are semaphore locked
+ * and not subject to change.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ev_valid_gpe_event (
+ struct acpi_gpe_event_info *gpe_event_info)
+{
+ struct acpi_gpe_xrupt_info *gpe_xrupt_block;
+ struct acpi_gpe_block_info *gpe_block;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* No need for spin lock since we are not changing any list elements */
+
+ /* Walk the GPE interrupt levels */
+
+ gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head;
+ while (gpe_xrupt_block) {
+ gpe_block = gpe_xrupt_block->gpe_block_list_head;
+
+ /* Walk the GPE blocks on this interrupt level */
+
+ while (gpe_block) {
+ if ((&gpe_block->event_info[0] <= gpe_event_info) &&
+ (&gpe_block->event_info[((acpi_size) gpe_block->register_count) * 8] > gpe_event_info)) {
+ return (TRUE);
+ }
+
+ gpe_block = gpe_block->next;
+ }
+
+ gpe_xrupt_block = gpe_xrupt_block->next;
+ }
+
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_walk_gpe_list
+ *
+ * PARAMETERS: gpe_walk_callback - Routine called for each GPE block
+ * Flags - ACPI_NOT_ISR or ACPI_ISR
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk the GPE lists.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_walk_gpe_list (
+ ACPI_GPE_CALLBACK gpe_walk_callback,
+ u32 flags)
+{
+ struct acpi_gpe_block_info *gpe_block;
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ev_walk_gpe_list");
+
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, flags);
+
+ /* Walk the interrupt level descriptor list */
+
+ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+ while (gpe_xrupt_info) {
+ /* Walk all Gpe Blocks attached to this interrupt level */
+
+ gpe_block = gpe_xrupt_info->gpe_block_list_head;
+ while (gpe_block) {
+ /* One callback per GPE block */
+
+ status = gpe_walk_callback (gpe_xrupt_info, gpe_block);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ gpe_block = gpe_block->next;
+ }
+
+ gpe_xrupt_info = gpe_xrupt_info->next;
+ }
+
+unlock_and_exit:
+ acpi_os_release_lock (acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ev_delete_gpe_handlers
+ *
+ * PARAMETERS: gpe_xrupt_info - GPE Interrupt info
+ * gpe_block - Gpe Block info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete all Handler objects found in the GPE data structs.
+ * Used only prior to termination.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_delete_gpe_handlers (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block)
+{
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_native_uint i;
+ acpi_native_uint j;
+
+
+ ACPI_FUNCTION_TRACE ("ev_delete_gpe_handlers");
+
+
+ /* Examine each GPE Register within the block */
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ /* Now look at the individual GPEs in this byte register */
+
+ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+ gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j];
+
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) {
+ ACPI_MEM_FREE (gpe_event_info->dispatch.handler);
+ gpe_event_info->dispatch.handler = NULL;
+ gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK;
+ }
+ }
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_save_method_info
+ *
+ * PARAMETERS: Callback from walk_namespace
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
+ * control method under the _GPE portion of the namespace.
+ * Extract the name and GPE type from the object, saving this
+ * information for quick lookup during GPE dispatch
+ *
+ * The name of each GPE control method is of the form:
+ * "_Lxx" or "_Exx"
+ * Where:
+ * L - means that the GPE is level triggered
+ * E - means that the GPE is edge triggered
+ * xx - is the GPE number [in HEX]
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_save_method_info (
+ acpi_handle obj_handle,
+ u32 level,
+ void *obj_desc,
+ void **return_value)
+{
+ struct acpi_gpe_block_info *gpe_block = (void *) obj_desc;
+ struct acpi_gpe_event_info *gpe_event_info;
+ u32 gpe_number;
+ char name[ACPI_NAME_SIZE + 1];
+ u8 type;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_save_method_info");
+
+
+ /*
+ * _Lxx and _Exx GPE method support
+ *
+ * 1) Extract the name from the object and convert to a string
+ */
+ ACPI_MOVE_32_TO_32 (name,
+ &((struct acpi_namespace_node *) obj_handle)->name.integer);
+ name[ACPI_NAME_SIZE] = 0;
+
+ /*
+ * 2) Edge/Level determination is based on the 2nd character
+ * of the method name
+ *
+ * NOTE: Default GPE type is RUNTIME. May be changed later to WAKE
+ * if a _PRW object is found that points to this GPE.
+ */
+ switch (name[1]) {
+ case 'L':
+ type = ACPI_GPE_LEVEL_TRIGGERED;
+ break;
+
+ case 'E':
+ type = ACPI_GPE_EDGE_TRIGGERED;
+ break;
+
+ default:
+ /* Unknown method type, just ignore it! */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown GPE method type: %s (name not of form _Lxx or _Exx)\n",
+ name));
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Convert the last two characters of the name to the GPE Number */
+
+ gpe_number = ACPI_STRTOUL (&name[2], NULL, 16);
+ if (gpe_number == ACPI_UINT32_MAX) {
+ /* Conversion failed; invalid method, just ignore it */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not extract GPE number from name: %s (name is not of form _Lxx or _Exx)\n",
+ name));
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Ensure that we have a valid GPE number for this GPE block */
+
+ if ((gpe_number < gpe_block->block_base_number) ||
+ (gpe_number >= (gpe_block->block_base_number + (gpe_block->register_count * 8)))) {
+ /*
+ * Not valid for this GPE block, just ignore it
+ * However, it may be valid for a different GPE block, since GPE0 and GPE1
+ * methods both appear under \_GPE.
+ */
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Now we can add this information to the gpe_event_info block
+ * for use during dispatch of this GPE. Default type is RUNTIME, although
+ * this may change when the _PRW methods are executed later.
+ */
+ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number];
+
+ gpe_event_info->flags = (u8) (type | ACPI_GPE_DISPATCH_METHOD |
+ ACPI_GPE_TYPE_RUNTIME);
+
+ gpe_event_info->dispatch.method_node = (struct acpi_namespace_node *) obj_handle;
+
+ /* Update enable mask, but don't enable the HW GPE as of yet */
+
+ status = acpi_ev_enable_gpe (gpe_event_info, FALSE);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD,
+ "Registered GPE method %s as GPE number 0x%.2X\n",
+ name, gpe_number));
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_match_prw_and_gpe
+ *
+ * PARAMETERS: Callback from walk_namespace
+ *
+ * RETURN: Status. NOTE: We ignore errors so that the _PRW walk is
+ * not aborted on a single _PRW failure.
+ *
+ * DESCRIPTION: Called from acpi_walk_namespace. Expects each object to be a
+ * Device. Run the _PRW method. If present, extract the GPE
+ * number and mark the GPE as a WAKE GPE.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_match_prw_and_gpe (
+ acpi_handle obj_handle,
+ u32 level,
+ void *info,
+ void **return_value)
+{
+ struct acpi_gpe_walk_info *gpe_info = (void *) info;
+ struct acpi_namespace_node *gpe_device;
+ struct acpi_gpe_block_info *gpe_block;
+ struct acpi_namespace_node *target_gpe_device;
+ struct acpi_gpe_event_info *gpe_event_info;
+ union acpi_operand_object *pkg_desc;
+ union acpi_operand_object *obj_desc;
+ u32 gpe_number;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_match_prw_and_gpe");
+
+
+ /* Check for a _PRW method under this device */
+
+ status = acpi_ut_evaluate_object (obj_handle, METHOD_NAME__PRW,
+ ACPI_BTYPE_PACKAGE, &pkg_desc);
+ if (ACPI_FAILURE (status)) {
+ /* Ignore all errors from _PRW, we don't want to abort the subsystem */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* The returned _PRW package must have at least two elements */
+
+ if (pkg_desc->package.count < 2) {
+ goto cleanup;
+ }
+
+ /* Extract pointers from the input context */
+
+ gpe_device = gpe_info->gpe_device;
+ gpe_block = gpe_info->gpe_block;
+
+ /*
+ * The _PRW object must return a package, we are only interested
+ * in the first element
+ */
+ obj_desc = pkg_desc->package.elements[0];
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ /* Use FADT-defined GPE device (from definition of _PRW) */
+
+ target_gpe_device = acpi_gbl_fadt_gpe_device;
+
+ /* Integer is the GPE number in the FADT described GPE blocks */
+
+ gpe_number = (u32) obj_desc->integer.value;
+ }
+ else if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) {
+ /* Package contains a GPE reference and GPE number within a GPE block */
+
+ if ((obj_desc->package.count < 2) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[0]) != ACPI_TYPE_LOCAL_REFERENCE) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc->package.elements[1]) != ACPI_TYPE_INTEGER)) {
+ goto cleanup;
+ }
+
+ /* Get GPE block reference and decode */
+
+ target_gpe_device = obj_desc->package.elements[0]->reference.node;
+ gpe_number = (u32) obj_desc->package.elements[1]->integer.value;
+ }
+ else {
+ /* Unknown type, just ignore it */
+
+ goto cleanup;
+ }
+
+ /*
+ * Is this GPE within this block?
+ *
+ * TRUE iff these conditions are true:
+ * 1) The GPE devices match.
+ * 2) The GPE index(number) is within the range of the Gpe Block
+ * associated with the GPE device.
+ */
+ if ((gpe_device == target_gpe_device) &&
+ (gpe_number >= gpe_block->block_base_number) &&
+ (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) {
+ gpe_event_info = &gpe_block->event_info[gpe_number - gpe_block->block_base_number];
+
+ /* Mark GPE for WAKE-ONLY but WAKE_DISABLED */
+
+ gpe_event_info->flags &= ~(ACPI_GPE_WAKE_ENABLED | ACPI_GPE_RUN_ENABLED);
+ status = acpi_ev_set_gpe_type (gpe_event_info, ACPI_GPE_TYPE_WAKE);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ status = acpi_ev_update_gpe_enable_masks (gpe_event_info, ACPI_GPE_DISABLE);
+ }
+
+cleanup:
+ acpi_ut_remove_reference (pkg_desc);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_get_gpe_xrupt_block
+ *
+ * PARAMETERS: interrupt_level - Interrupt for a GPE block
+ *
+ * RETURN: A GPE interrupt block
+ *
+ * DESCRIPTION: Get or Create a GPE interrupt block. There is one interrupt
+ * block per unique interrupt level used for GPEs.
+ * Should be called only when the GPE lists are semaphore locked
+ * and not subject to change.
+ *
+ ******************************************************************************/
+
+static struct acpi_gpe_xrupt_info *
+acpi_ev_get_gpe_xrupt_block (
+ u32 interrupt_level)
+{
+ struct acpi_gpe_xrupt_info *next_gpe_xrupt;
+ struct acpi_gpe_xrupt_info *gpe_xrupt;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_get_gpe_xrupt_block");
+
+
+ /* No need for spin lock since we are not changing any list elements here */
+
+ next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
+ while (next_gpe_xrupt) {
+ if (next_gpe_xrupt->interrupt_level == interrupt_level) {
+ return_PTR (next_gpe_xrupt);
+ }
+
+ next_gpe_xrupt = next_gpe_xrupt->next;
+ }
+
+ /* Not found, must allocate a new xrupt descriptor */
+
+ gpe_xrupt = ACPI_MEM_CALLOCATE (sizeof (struct acpi_gpe_xrupt_info));
+ if (!gpe_xrupt) {
+ return_PTR (NULL);
+ }
+
+ gpe_xrupt->interrupt_level = interrupt_level;
+
+ /* Install new interrupt descriptor with spin lock */
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+ if (acpi_gbl_gpe_xrupt_list_head) {
+ next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
+ while (next_gpe_xrupt->next) {
+ next_gpe_xrupt = next_gpe_xrupt->next;
+ }
+
+ next_gpe_xrupt->next = gpe_xrupt;
+ gpe_xrupt->previous = next_gpe_xrupt;
+ }
+ else {
+ acpi_gbl_gpe_xrupt_list_head = gpe_xrupt;
+ }
+ acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+
+ /* Install new interrupt handler if not SCI_INT */
+
+ if (interrupt_level != acpi_gbl_FADT->sci_int) {
+ status = acpi_os_install_interrupt_handler (interrupt_level,
+ acpi_ev_gpe_xrupt_handler, gpe_xrupt);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not install GPE interrupt handler at level 0x%X\n",
+ interrupt_level));
+ return_PTR (NULL);
+ }
+ }
+
+ return_PTR (gpe_xrupt);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_delete_gpe_xrupt
+ *
+ * PARAMETERS: gpe_xrupt - A GPE interrupt info block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove and free a gpe_xrupt block. Remove an associated
+ * interrupt handler if not the SCI interrupt.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_delete_gpe_xrupt (
+ struct acpi_gpe_xrupt_info *gpe_xrupt)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_delete_gpe_xrupt");
+
+
+ /* We never want to remove the SCI interrupt handler */
+
+ if (gpe_xrupt->interrupt_level == acpi_gbl_FADT->sci_int) {
+ gpe_xrupt->gpe_block_list_head = NULL;
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Disable this interrupt */
+
+ status = acpi_os_remove_interrupt_handler (gpe_xrupt->interrupt_level,
+ acpi_ev_gpe_xrupt_handler);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Unlink the interrupt block with lock */
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+ if (gpe_xrupt->previous) {
+ gpe_xrupt->previous->next = gpe_xrupt->next;
+ }
+
+ if (gpe_xrupt->next) {
+ gpe_xrupt->next->previous = gpe_xrupt->previous;
+ }
+ acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+
+ /* Free the block */
+
+ ACPI_MEM_FREE (gpe_xrupt);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_gpe_block
+ *
+ * PARAMETERS: gpe_block - New GPE block
+ * interrupt_level - Level to be associated with this GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install new GPE block with mutex support
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_install_gpe_block (
+ struct acpi_gpe_block_info *gpe_block,
+ u32 interrupt_level)
+{
+ struct acpi_gpe_block_info *next_gpe_block;
+ struct acpi_gpe_xrupt_info *gpe_xrupt_block;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_install_gpe_block");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ gpe_xrupt_block = acpi_ev_get_gpe_xrupt_block (interrupt_level);
+ if (!gpe_xrupt_block) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Install the new block at the end of the list for this interrupt with lock */
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+ if (gpe_xrupt_block->gpe_block_list_head) {
+ next_gpe_block = gpe_xrupt_block->gpe_block_list_head;
+ while (next_gpe_block->next) {
+ next_gpe_block = next_gpe_block->next;
+ }
+
+ next_gpe_block->next = gpe_block;
+ gpe_block->previous = next_gpe_block;
+ }
+ else {
+ gpe_xrupt_block->gpe_block_list_head = gpe_block;
+ }
+
+ gpe_block->xrupt_block = gpe_xrupt_block;
+ acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+
+unlock_and_exit:
+ status = acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_delete_gpe_block
+ *
+ * PARAMETERS: gpe_block - Existing GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a GPE block
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_delete_gpe_block (
+ struct acpi_gpe_block_info *gpe_block)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_install_gpe_block");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Disable all GPEs in this block */
+
+ status = acpi_hw_disable_gpe_block (gpe_block->xrupt_block, gpe_block);
+
+ if (!gpe_block->previous && !gpe_block->next) {
+ /* This is the last gpe_block on this interrupt */
+
+ status = acpi_ev_delete_gpe_xrupt (gpe_block->xrupt_block);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+ else {
+ /* Remove the block on this interrupt with lock */
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+ if (gpe_block->previous) {
+ gpe_block->previous->next = gpe_block->next;
+ }
+ else {
+ gpe_block->xrupt_block->gpe_block_list_head = gpe_block->next;
+ }
+
+ if (gpe_block->next) {
+ gpe_block->next->previous = gpe_block->previous;
+ }
+ acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+ }
+
+ /* Free the gpe_block */
+
+ ACPI_MEM_FREE (gpe_block->register_info);
+ ACPI_MEM_FREE (gpe_block->event_info);
+ ACPI_MEM_FREE (gpe_block);
+
+unlock_and_exit:
+ status = acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_create_gpe_info_blocks
+ *
+ * PARAMETERS: gpe_block - New GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create the register_info and event_info blocks for this GPE block
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ev_create_gpe_info_blocks (
+ struct acpi_gpe_block_info *gpe_block)
+{
+ struct acpi_gpe_register_info *gpe_register_info = NULL;
+ struct acpi_gpe_event_info *gpe_event_info = NULL;
+ struct acpi_gpe_event_info *this_event;
+ struct acpi_gpe_register_info *this_register;
+ acpi_native_uint i;
+ acpi_native_uint j;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_create_gpe_info_blocks");
+
+
+ /* Allocate the GPE register information block */
+
+ gpe_register_info = ACPI_MEM_CALLOCATE (
+ (acpi_size) gpe_block->register_count *
+ sizeof (struct acpi_gpe_register_info));
+ if (!gpe_register_info) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not allocate the gpe_register_info table\n"));
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Allocate the GPE event_info block. There are eight distinct GPEs
+ * per register. Initialization to zeros is sufficient.
+ */
+ gpe_event_info = ACPI_MEM_CALLOCATE (
+ ((acpi_size) gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) *
+ sizeof (struct acpi_gpe_event_info));
+ if (!gpe_event_info) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the gpe_event_info table\n"));
+ status = AE_NO_MEMORY;
+ goto error_exit;
+ }
+
+ /* Save the new Info arrays in the GPE block */
+
+ gpe_block->register_info = gpe_register_info;
+ gpe_block->event_info = gpe_event_info;
+
+ /*
+ * Initialize the GPE Register and Event structures. A goal of these
+ * tables is to hide the fact that there are two separate GPE register sets
+ * in a given gpe hardware block, the status registers occupy the first half,
+ * and the enable registers occupy the second half.
+ */
+ this_register = gpe_register_info;
+ this_event = gpe_event_info;
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ /* Init the register_info for this GPE register (8 GPEs) */
+
+ this_register->base_gpe_number = (u8) (gpe_block->block_base_number +
+ (i * ACPI_GPE_REGISTER_WIDTH));
+
+ ACPI_STORE_ADDRESS (this_register->status_address.address,
+ (gpe_block->block_address.address
+ + i));
+
+ ACPI_STORE_ADDRESS (this_register->enable_address.address,
+ (gpe_block->block_address.address
+ + i
+ + gpe_block->register_count));
+
+ this_register->status_address.address_space_id = gpe_block->block_address.address_space_id;
+ this_register->enable_address.address_space_id = gpe_block->block_address.address_space_id;
+ this_register->status_address.register_bit_width = ACPI_GPE_REGISTER_WIDTH;
+ this_register->enable_address.register_bit_width = ACPI_GPE_REGISTER_WIDTH;
+ this_register->status_address.register_bit_offset = ACPI_GPE_REGISTER_WIDTH;
+ this_register->enable_address.register_bit_offset = ACPI_GPE_REGISTER_WIDTH;
+
+ /* Init the event_info for each GPE within this register */
+
+ for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
+ this_event->register_bit = acpi_gbl_decode_to8bit[j];
+ this_event->register_info = this_register;
+ this_event++;
+ }
+
+ /*
+ * Clear the status/enable registers. Note that status registers
+ * are cleared by writing a '1', while enable registers are cleared
+ * by writing a '0'.
+ */
+ status = acpi_hw_low_level_write (ACPI_GPE_REGISTER_WIDTH, 0x00,
+ &this_register->enable_address);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ status = acpi_hw_low_level_write (ACPI_GPE_REGISTER_WIDTH, 0xFF,
+ &this_register->status_address);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ this_register++;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+
+
+error_exit:
+ if (gpe_register_info) {
+ ACPI_MEM_FREE (gpe_register_info);
+ }
+ if (gpe_event_info) {
+ ACPI_MEM_FREE (gpe_event_info);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_create_gpe_block
+ *
+ * PARAMETERS: gpe_device - Handle to the parent GPE block
+ * gpe_block_address - Address and space_iD
+ * register_count - Number of GPE register pairs in the block
+ * gpe_block_base_number - Starting GPE number for the block
+ * interrupt_level - H/W interrupt for the block
+ * return_gpe_block - Where the new block descriptor is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create and Install a block of GPE registers
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_create_gpe_block (
+ struct acpi_namespace_node *gpe_device,
+ struct acpi_generic_address *gpe_block_address,
+ u32 register_count,
+ u8 gpe_block_base_number,
+ u32 interrupt_level,
+ struct acpi_gpe_block_info **return_gpe_block)
+{
+ struct acpi_gpe_block_info *gpe_block;
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_native_uint i;
+ acpi_native_uint j;
+ u32 wake_gpe_count;
+ u32 gpe_enabled_count;
+ acpi_status status;
+ struct acpi_gpe_walk_info gpe_info;
+
+
+ ACPI_FUNCTION_TRACE ("ev_create_gpe_block");
+
+
+ if (!register_count) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Allocate a new GPE block */
+
+ gpe_block = ACPI_MEM_CALLOCATE (sizeof (struct acpi_gpe_block_info));
+ if (!gpe_block) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Initialize the new GPE block */
+
+ gpe_block->register_count = register_count;
+ gpe_block->block_base_number = gpe_block_base_number;
+ gpe_block->node = gpe_device;
+
+ ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address, sizeof (struct acpi_generic_address));
+
+ /* Create the register_info and event_info sub-structures */
+
+ status = acpi_ev_create_gpe_info_blocks (gpe_block);
+ if (ACPI_FAILURE (status)) {
+ ACPI_MEM_FREE (gpe_block);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Install the new block in the global list(s) */
+
+ status = acpi_ev_install_gpe_block (gpe_block, interrupt_level);
+ if (ACPI_FAILURE (status)) {
+ ACPI_MEM_FREE (gpe_block);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Find all GPE methods (_Lxx, _Exx) for this block */
+
+ status = acpi_ns_walk_namespace (ACPI_TYPE_METHOD, gpe_device,
+ ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK, acpi_ev_save_method_info,
+ gpe_block, NULL);
+
+ /*
+ * Runtime option: Should Wake GPEs be enabled at runtime? The default
+ * is No, they should only be enabled just as the machine goes to sleep.
+ */
+ if (acpi_gbl_leave_wake_gpes_disabled) {
+ /*
+ * Differentiate RUNTIME vs WAKE GPEs, via the _PRW control methods.
+ * (Each GPE that has one or more _PRWs that reference it is by
+ * definition a WAKE GPE and will not be enabled while the machine
+ * is running.)
+ */
+ gpe_info.gpe_block = gpe_block;
+ gpe_info.gpe_device = gpe_device;
+
+ status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, acpi_ev_match_prw_and_gpe,
+ &gpe_info, NULL);
+ }
+
+ /*
+ * Enable all GPEs in this block that are 1) "runtime" or "run/wake" GPEs,
+ * and 2) have a corresponding _Lxx or _Exx method. All other GPEs must
+ * be enabled via the acpi_enable_gpe() external interface.
+ */
+ wake_gpe_count = 0;
+ gpe_enabled_count = 0;
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ for (j = 0; j < 8; j++) {
+ /* Get the info block for this particular GPE */
+
+ gpe_event_info = &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j];
+
+ if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_METHOD) &&
+ (gpe_event_info->flags & ACPI_GPE_TYPE_RUNTIME)) {
+ gpe_enabled_count++;
+ }
+
+ if (gpe_event_info->flags & ACPI_GPE_TYPE_WAKE) {
+ wake_gpe_count++;
+ }
+ }
+ }
+
+ /* Dump info about this GPE block */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "GPE %02X to %02X [%4.4s] %u regs on int 0x%X\n",
+ (u32) gpe_block->block_base_number,
+ (u32) (gpe_block->block_base_number +
+ ((gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) -1)),
+ gpe_device->name.ascii,
+ gpe_block->register_count,
+ interrupt_level));
+
+ /* Enable all valid GPEs found above */
+
+ status = acpi_hw_enable_runtime_gpe_block (NULL, gpe_block);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "Found %u Wake, Enabled %u Runtime GPEs in this block\n",
+ wake_gpe_count, gpe_enabled_count));
+
+ /* Return the new block */
+
+ if (return_gpe_block) {
+ (*return_gpe_block) = gpe_block;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_gpe_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the GPE data structures
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_gpe_initialize (
+ void)
+{
+ u32 register_count0 = 0;
+ u32 register_count1 = 0;
+ u32 gpe_number_max = 0;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_gpe_initialize");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Initialize the GPE Block(s) defined in the FADT
+ *
+ * Why the GPE register block lengths are divided by 2: From the ACPI Spec,
+ * section "General-Purpose Event Registers", we have:
+ *
+ * "Each register block contains two registers of equal length
+ * GPEx_STS and GPEx_EN (where x is 0 or 1). The length of the
+ * GPE0_STS and GPE0_EN registers is equal to half the GPE0_LEN
+ * The length of the GPE1_STS and GPE1_EN registers is equal to
+ * half the GPE1_LEN. If a generic register block is not supported
+ * then its respective block pointer and block length values in the
+ * FADT table contain zeros. The GPE0_LEN and GPE1_LEN do not need
+ * to be the same size."
+ */
+
+ /*
+ * Determine the maximum GPE number for this machine.
+ *
+ * Note: both GPE0 and GPE1 are optional, and either can exist without
+ * the other.
+ *
+ * If EITHER the register length OR the block address are zero, then that
+ * particular block is not supported.
+ */
+ if (acpi_gbl_FADT->gpe0_blk_len &&
+ acpi_gbl_FADT->xgpe0_blk.address) {
+ /* GPE block 0 exists (has both length and address > 0) */
+
+ register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
+
+ gpe_number_max = (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
+
+ /* Install GPE Block 0 */
+
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk,
+ register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "Could not create GPE Block 0, %s\n",
+ acpi_format_exception (status)));
+ }
+ }
+
+ if (acpi_gbl_FADT->gpe1_blk_len &&
+ acpi_gbl_FADT->xgpe1_blk.address) {
+ /* GPE block 1 exists (has both length and address > 0) */
+
+ register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
+
+ /* Check for GPE0/GPE1 overlap (if both banks exist) */
+
+ if ((register_count0) &&
+ (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) {
+ ACPI_REPORT_ERROR ((
+ "GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1\n",
+ gpe_number_max, acpi_gbl_FADT->gpe1_base,
+ acpi_gbl_FADT->gpe1_base +
+ ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1)));
+
+ /* Ignore GPE1 block by setting the register count to zero */
+
+ register_count1 = 0;
+ }
+ else {
+ /* Install GPE Block 1 */
+
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk,
+ register_count1, acpi_gbl_FADT->gpe1_base,
+ acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR ((
+ "Could not create GPE Block 1, %s\n",
+ acpi_format_exception (status)));
+ }
+
+ /*
+ * GPE0 and GPE1 do not have to be contiguous in the GPE number
+ * space. However, GPE0 always starts at GPE number zero.
+ */
+ gpe_number_max = acpi_gbl_FADT->gpe1_base +
+ ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
+ }
+ }
+
+ /* Exit if there are no GPE registers */
+
+ if ((register_count0 + register_count1) == 0) {
+ /* GPEs are not required by ACPI, this is OK */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "There are no GPE blocks defined in the FADT\n"));
+ status = AE_OK;
+ goto cleanup;
+ }
+
+ /* Check for Max GPE number out-of-range */
+
+ if (gpe_number_max > ACPI_GPE_MAX) {
+ ACPI_REPORT_ERROR (("Maximum GPE number from FADT is too large: 0x%X\n",
+ gpe_number_max));
+ status = AE_BAD_VALUE;
+ goto cleanup;
+ }
+
+cleanup:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
new file mode 100644
index 000000000000..2548efa7a45f
--- /dev/null
+++ b/drivers/acpi/events/evmisc.c
@@ -0,0 +1,588 @@
+/******************************************************************************
+ *
+ * Module Name: evmisc - Miscellaneous event manager support functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evmisc")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_is_notify_object
+ *
+ * PARAMETERS: Node - Node to check
+ *
+ * RETURN: TRUE if notifies allowed on this object
+ *
+ * DESCRIPTION: Check type of node for a object that supports notifies.
+ *
+ * TBD: This could be replaced by a flag bit in the node.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ev_is_notify_object (
+ struct acpi_namespace_node *node)
+{
+ switch (node->type) {
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_THERMAL:
+ /*
+ * These are the ONLY objects that can receive ACPI notifications
+ */
+ return (TRUE);
+
+ default:
+ return (FALSE);
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_queue_notify_request
+ *
+ * PARAMETERS: Node - NS node for the notified object
+ * notify_value - Value from the Notify() request
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Dispatch a device notification event to a previously
+ * installed handler.
+ *
+ ******************************************************************************/
+
+#ifdef ACPI_DEBUG_OUTPUT
+static const char *acpi_notify_value_names[] =
+{
+ "Bus Check",
+ "Device Check",
+ "Device Wake",
+ "Eject request",
+ "Device Check Light",
+ "Frequency Mismatch",
+ "Bus Mode Mismatch",
+ "Power Fault"
+};
+#endif
+
+acpi_status
+acpi_ev_queue_notify_request (
+ struct acpi_namespace_node *node,
+ u32 notify_value)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj = NULL;
+ union acpi_generic_state *notify_info;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_NAME ("ev_queue_notify_request");
+
+
+ /*
+ * For value 3 (Ejection Request), some device method may need to be run.
+ * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
+ * For value 0x80 (Status Change) on the power button or sleep button,
+ * initiate soft-off or sleep operation?
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Dispatching Notify(%X) on node %p\n", notify_value, node));
+
+ if (notify_value <= 7) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: %s\n",
+ acpi_notify_value_names[notify_value]));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Notify value: 0x%2.2X **Device Specific**\n",
+ notify_value));
+ }
+
+ /* Get the notify object attached to the NS Node */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (obj_desc) {
+ /* We have the notify object, Get the right handler */
+
+ switch (node->type) {
+ case ACPI_TYPE_DEVICE:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_POWER:
+
+ if (notify_value <= ACPI_MAX_SYS_NOTIFY) {
+ handler_obj = obj_desc->common_notify.system_notify;
+ }
+ else {
+ handler_obj = obj_desc->common_notify.device_notify;
+ }
+ break;
+
+ default:
+ /* All other types are not supported */
+ return (AE_TYPE);
+ }
+ }
+
+ /* If there is any handler to run, schedule the dispatcher */
+
+ if ((acpi_gbl_system_notify.handler && (notify_value <= ACPI_MAX_SYS_NOTIFY)) ||
+ (acpi_gbl_device_notify.handler && (notify_value > ACPI_MAX_SYS_NOTIFY)) ||
+ handler_obj) {
+ notify_info = acpi_ut_create_generic_state ();
+ if (!notify_info) {
+ return (AE_NO_MEMORY);
+ }
+
+ notify_info->common.data_type = ACPI_DESC_TYPE_STATE_NOTIFY;
+ notify_info->notify.node = node;
+ notify_info->notify.value = (u16) notify_value;
+ notify_info->notify.handler_obj = handler_obj;
+
+ status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH,
+ acpi_ev_notify_dispatch, notify_info);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_delete_generic_state (notify_info);
+ }
+ }
+
+ if (!handler_obj) {
+ /*
+ * There is no per-device notify handler for this device.
+ * This may or may not be a problem.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "No notify handler for Notify(%4.4s, %X) node %p\n",
+ acpi_ut_get_node_name (node), notify_value, node));
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_notify_dispatch
+ *
+ * PARAMETERS: Context - To be passsed to the notify handler
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Dispatch a device notification event to a previously
+ * installed handler.
+ *
+ ******************************************************************************/
+
+void ACPI_SYSTEM_XFACE
+acpi_ev_notify_dispatch (
+ void *context)
+{
+ union acpi_generic_state *notify_info = (union acpi_generic_state *) context;
+ acpi_notify_handler global_handler = NULL;
+ void *global_context = NULL;
+ union acpi_operand_object *handler_obj;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * We will invoke a global notify handler if installed.
+ * This is done _before_ we invoke the per-device handler attached to the device.
+ */
+ if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
+ /* Global system notification handler */
+
+ if (acpi_gbl_system_notify.handler) {
+ global_handler = acpi_gbl_system_notify.handler;
+ global_context = acpi_gbl_system_notify.context;
+ }
+ }
+ else {
+ /* Global driver notification handler */
+
+ if (acpi_gbl_device_notify.handler) {
+ global_handler = acpi_gbl_device_notify.handler;
+ global_context = acpi_gbl_device_notify.context;
+ }
+ }
+
+ /* Invoke the system handler first, if present */
+
+ if (global_handler) {
+ global_handler (notify_info->notify.node, notify_info->notify.value, global_context);
+ }
+
+ /* Now invoke the per-device handler, if present */
+
+ handler_obj = notify_info->notify.handler_obj;
+ if (handler_obj) {
+ handler_obj->notify.handler (notify_info->notify.node, notify_info->notify.value,
+ handler_obj->notify.context);
+ }
+
+ /* All done with the info object */
+
+ acpi_ut_delete_generic_state (notify_info);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_global_lock_thread
+ *
+ * PARAMETERS: Context - From thread interface, not used
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
+ * Global Lock. Simply signal all threads that are waiting
+ * for the lock.
+ *
+ ******************************************************************************/
+
+static void ACPI_SYSTEM_XFACE
+acpi_ev_global_lock_thread (
+ void *context)
+{
+ acpi_status status;
+
+
+ /* Signal threads that are waiting for the lock */
+
+ if (acpi_gbl_global_lock_thread_count) {
+ /* Send sufficient units to the semaphore */
+
+ status = acpi_os_signal_semaphore (acpi_gbl_global_lock_semaphore,
+ acpi_gbl_global_lock_thread_count);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not signal Global Lock semaphore\n"));
+ }
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_global_lock_handler
+ *
+ * PARAMETERS: Context - From thread interface, not used
+ *
+ * RETURN: ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED
+ *
+ * DESCRIPTION: Invoked directly from the SCI handler when a global lock
+ * release interrupt occurs. Grab the global lock and queue
+ * the global lock thread for execution
+ *
+ ******************************************************************************/
+
+static u32
+acpi_ev_global_lock_handler (
+ void *context)
+{
+ u8 acquired = FALSE;
+ acpi_status status;
+
+
+ /*
+ * Attempt to get the lock
+ * If we don't get it now, it will be marked pending and we will
+ * take another interrupt when it becomes free.
+ */
+ ACPI_ACQUIRE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, acquired);
+ if (acquired) {
+ /* Got the lock, now wake all threads waiting for it */
+
+ acpi_gbl_global_lock_acquired = TRUE;
+
+ /* Run the Global Lock thread which will signal all waiting threads */
+
+ status = acpi_os_queue_for_execution (OSD_PRIORITY_HIGH,
+ acpi_ev_global_lock_thread, context);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not queue Global Lock thread, %s\n",
+ acpi_format_exception (status)));
+
+ return (ACPI_INTERRUPT_NOT_HANDLED);
+ }
+ }
+
+ return (ACPI_INTERRUPT_HANDLED);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_init_global_lock_handler
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for the global lock release event
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_init_global_lock_handler (void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_init_global_lock_handler");
+
+
+ acpi_gbl_global_lock_present = TRUE;
+ status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL,
+ acpi_ev_global_lock_handler, NULL);
+
+ /*
+ * If the global lock does not exist on this platform, the attempt
+ * to enable GBL_STATUS will fail (the GBL_ENABLE bit will not stick)
+ * Map to AE_OK, but mark global lock as not present.
+ * Any attempt to actually use the global lock will be flagged
+ * with an error.
+ */
+ if (status == AE_NO_HARDWARE_RESPONSE) {
+ acpi_gbl_global_lock_present = FALSE;
+ status = AE_OK;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ev_acquire_global_lock
+ *
+ * PARAMETERS: Timeout - Max time to wait for the lock, in millisec.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Attempt to gain ownership of the Global Lock.
+ *
+ *****************************************************************************/
+
+acpi_status
+acpi_ev_acquire_global_lock (
+ u16 timeout)
+{
+ acpi_status status = AE_OK;
+ u8 acquired = FALSE;
+
+
+ ACPI_FUNCTION_TRACE ("ev_acquire_global_lock");
+
+
+#ifndef ACPI_APPLICATION
+ /* Make sure that we actually have a global lock */
+
+ if (!acpi_gbl_global_lock_present) {
+ return_ACPI_STATUS (AE_NO_GLOBAL_LOCK);
+ }
+#endif
+
+ /* One more thread wants the global lock */
+
+ acpi_gbl_global_lock_thread_count++;
+
+ /* If we (OS side vs. BIOS side) have the hardware lock already, we are done */
+
+ if (acpi_gbl_global_lock_acquired) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* We must acquire the actual hardware lock */
+
+ ACPI_ACQUIRE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, acquired);
+ if (acquired) {
+ /* We got the lock */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Acquired the HW Global Lock\n"));
+
+ acpi_gbl_global_lock_acquired = TRUE;
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Did not get the lock. The pending bit was set above, and we must now
+ * wait until we get the global lock released interrupt.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n"));
+
+ /*
+ * Acquire the global lock semaphore first.
+ * Since this wait will block, we must release the interpreter
+ */
+ status = acpi_ex_system_wait_semaphore (acpi_gbl_global_lock_semaphore,
+ timeout);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_release_global_lock
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Releases ownership of the Global Lock.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_release_global_lock (void)
+{
+ u8 pending = FALSE;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ev_release_global_lock");
+
+
+ if (!acpi_gbl_global_lock_thread_count) {
+ ACPI_REPORT_WARNING(("Cannot release HW Global Lock, it has not been acquired\n"));
+ return_ACPI_STATUS (AE_NOT_ACQUIRED);
+ }
+
+ /* One fewer thread has the global lock */
+
+ acpi_gbl_global_lock_thread_count--;
+ if (acpi_gbl_global_lock_thread_count) {
+ /* There are still some threads holding the lock, cannot release */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * No more threads holding lock, we can do the actual hardware
+ * release
+ */
+ ACPI_RELEASE_GLOBAL_LOCK (acpi_gbl_common_fACS.global_lock, pending);
+ acpi_gbl_global_lock_acquired = FALSE;
+
+ /*
+ * If the pending bit was set, we must write GBL_RLS to the control
+ * register
+ */
+ if (pending) {
+ status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, 1, ACPI_MTX_LOCK);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ev_terminate
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Disable events and free memory allocated for table storage.
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_terminate (void)
+{
+ acpi_native_uint i;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_terminate");
+
+
+ if (acpi_gbl_events_initialized) {
+ /*
+ * Disable all event-related functionality.
+ * In all cases, on error, print a message but obviously we don't abort.
+ */
+
+ /* Disable all fixed events */
+
+ for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
+ status = acpi_disable_event ((u32) i, 0);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable fixed event %d\n", (u32) i));
+ }
+ }
+
+ /* Disable all GPEs in all GPE blocks */
+
+ status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, ACPI_NOT_ISR);
+
+ /* Remove SCI handler */
+
+ status = acpi_ev_remove_sci_handler ();
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n"));
+ }
+ }
+
+ /* Deallocate all handler objects installed within GPE info structs */
+
+ status = acpi_ev_walk_gpe_list (acpi_ev_delete_gpe_handlers, ACPI_NOT_ISR);
+
+ /* Return to original mode if necessary */
+
+ if (acpi_gbl_original_mode == ACPI_SYS_MODE_LEGACY) {
+ status = acpi_disable ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "acpi_disable failed\n"));
+ }
+ }
+ return_VOID;
+}
+
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
new file mode 100644
index 000000000000..772342708a7a
--- /dev/null
+++ b/drivers/acpi/events/evregion.c
@@ -0,0 +1,1067 @@
+/******************************************************************************
+ *
+ * Module Name: evregion - ACPI address_space (op_region) handler dispatch
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evregion")
+
+#define ACPI_NUM_DEFAULT_SPACES 4
+
+static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPACES] = {
+ ACPI_ADR_SPACE_SYSTEM_MEMORY,
+ ACPI_ADR_SPACE_SYSTEM_IO,
+ ACPI_ADR_SPACE_PCI_CONFIG,
+ ACPI_ADR_SPACE_DATA_TABLE};
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_region_handlers
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Installs the core subsystem default address space handlers.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_install_region_handlers (
+ void) {
+ acpi_status status;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_TRACE ("ev_install_region_handlers");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * All address spaces (PCI Config, EC, SMBus) are scope dependent
+ * and registration must occur for a specific device.
+ *
+ * In the case of the system memory and IO address spaces there is currently
+ * no device associated with the address space. For these we use the root.
+ *
+ * We install the default PCI config space handler at the root so
+ * that this space is immediately available even though the we have
+ * not enumerated all the PCI Root Buses yet. This is to conform
+ * to the ACPI specification which states that the PCI config
+ * space must be always available -- even though we are nowhere
+ * near ready to find the PCI root buses at this point.
+ *
+ * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler
+ * has already been installed (via acpi_install_address_space_handler).
+ * Similar for AE_SAME_HANDLER.
+ */
+ for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+ status = acpi_ev_install_space_handler (acpi_gbl_root_node,
+ acpi_gbl_default_address_spaces[i],
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+ switch (status) {
+ case AE_OK:
+ case AE_SAME_HANDLER:
+ case AE_ALREADY_EXISTS:
+
+ /* These exceptions are all OK */
+
+ status = AE_OK;
+ break;
+
+ default:
+
+ goto unlock_and_exit;
+ }
+ }
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_initialize_op_regions
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute _REG methods for all Operation Regions that have
+ * an installed default region handler.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_initialize_op_regions (
+ void)
+{
+ acpi_status status;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_TRACE ("ev_initialize_op_regions");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Run the _REG methods for op_regions in each default address space
+ */
+ for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) {
+ /* TBD: Make sure handler is the DEFAULT handler, otherwise
+ * _REG will have already been run.
+ */
+ status = acpi_ev_execute_reg_methods (acpi_gbl_root_node,
+ acpi_gbl_default_address_spaces[i]);
+ }
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_execute_reg_method
+ *
+ * PARAMETERS: region_obj - Object structure
+ * Function - Passed to _REG: On (1) or Off (0)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute _REG method for a region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_execute_reg_method (
+ union acpi_operand_object *region_obj,
+ u32 function)
+{
+ struct acpi_parameter_info info;
+ union acpi_operand_object *params[3];
+ union acpi_operand_object *region_obj2;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_execute_reg_method");
+
+
+ region_obj2 = acpi_ns_get_secondary_object (region_obj);
+ if (!region_obj2) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ if (region_obj2->extra.method_REG == NULL) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * The _REG method has two arguments:
+ *
+ * Arg0, Integer: Operation region space ID
+ * Same value as region_obj->Region.space_id
+ * Arg1, Integer: connection status
+ * 1 for connecting the handler,
+ * 0 for disconnecting the handler
+ * Passed as a parameter
+ */
+ params[0] = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!params[0]) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ params[1] = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!params[1]) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Setup the parameter objects */
+
+ params[0]->integer.value = region_obj->region.space_id;
+ params[1]->integer.value = function;
+ params[2] = NULL;
+
+ info.node = region_obj2->extra.method_REG;
+ info.parameters = params;
+ info.parameter_type = ACPI_PARAM_ARGS;
+
+ /* Execute the method, no return value */
+
+ ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (
+ ACPI_TYPE_METHOD, info.node, NULL));
+ status = acpi_ns_evaluate_by_handle (&info);
+
+ acpi_ut_remove_reference (params[1]);
+
+cleanup:
+ acpi_ut_remove_reference (params[0]);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_address_space_dispatch
+ *
+ * PARAMETERS: region_obj - Internal region object
+ * Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * bit_width - Field width in bits (8, 16, 32, or 64)
+ * Value - Pointer to in or out value
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Dispatch an address space or operation region access to
+ * a previously installed handler.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_address_space_dispatch (
+ union acpi_operand_object *region_obj,
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ void *value)
+{
+ acpi_status status;
+ acpi_status status2;
+ acpi_adr_space_handler handler;
+ acpi_adr_space_setup region_setup;
+ union acpi_operand_object *handler_desc;
+ union acpi_operand_object *region_obj2;
+ void *region_context = NULL;
+
+
+ ACPI_FUNCTION_TRACE ("ev_address_space_dispatch");
+
+
+ region_obj2 = acpi_ns_get_secondary_object (region_obj);
+ if (!region_obj2) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /* Ensure that there is a handler associated with this region */
+
+ handler_desc = region_obj->region.handler;
+ if (!handler_desc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "No handler for Region [%4.4s] (%p) [%s]\n",
+ acpi_ut_get_node_name (region_obj->region.node),
+ region_obj, acpi_ut_get_region_name (region_obj->region.space_id)));
+
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /*
+ * It may be the case that the region has never been initialized
+ * Some types of regions require special init code
+ */
+ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
+ /*
+ * This region has not been initialized yet, do it
+ */
+ region_setup = handler_desc->address_space.setup;
+ if (!region_setup) {
+ /* No initialization routine, exit with error */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No init routine for region(%p) [%s]\n",
+ region_obj, acpi_ut_get_region_name (region_obj->region.space_id)));
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /*
+ * We must exit the interpreter because the region setup will potentially
+ * execute control methods (e.g., _REG method for this region)
+ */
+ acpi_ex_exit_interpreter ();
+
+ status = region_setup (region_obj, ACPI_REGION_ACTIVATE,
+ handler_desc->address_space.context, &region_context);
+
+ /* Re-enter the interpreter */
+
+ status2 = acpi_ex_enter_interpreter ();
+ if (ACPI_FAILURE (status2)) {
+ return_ACPI_STATUS (status2);
+ }
+
+ /* Check for failure of the Region Setup */
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region Init: %s [%s]\n",
+ acpi_format_exception (status),
+ acpi_ut_get_region_name (region_obj->region.space_id)));
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Region initialization may have been completed by region_setup
+ */
+ if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) {
+ region_obj->region.flags |= AOPOBJ_SETUP_COMPLETE;
+
+ if (region_obj2->extra.region_context) {
+ /* The handler for this region was already installed */
+
+ ACPI_MEM_FREE (region_context);
+ }
+ else {
+ /*
+ * Save the returned context for use in all accesses to
+ * this particular region
+ */
+ region_obj2->extra.region_context = region_context;
+ }
+ }
+ }
+
+ /* We have everything we need, we can invoke the address space handler */
+
+ handler = handler_desc->address_space.handler;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Handler %p (@%p) Address %8.8X%8.8X [%s]\n",
+ &region_obj->region.handler->address_space, handler,
+ ACPI_FORMAT_UINT64 (address),
+ acpi_ut_get_region_name (region_obj->region.space_id)));
+
+ if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ /*
+ * For handlers other than the default (supplied) handlers, we must
+ * exit the interpreter because the handler *might* block -- we don't
+ * know what it will do, so we can't hold the lock on the intepreter.
+ */
+ acpi_ex_exit_interpreter();
+ }
+
+ /* Call the handler */
+
+ status = handler (function, address, bit_width, value,
+ handler_desc->address_space.context,
+ region_obj2->extra.region_context);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Handler for [%s] returned %s\n",
+ acpi_ut_get_region_name (region_obj->region.space_id),
+ acpi_format_exception (status)));
+ }
+
+ if (!(handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) {
+ /*
+ * We just returned from a non-default handler, we must re-enter the
+ * interpreter
+ */
+ status2 = acpi_ex_enter_interpreter ();
+ if (ACPI_FAILURE (status2)) {
+ return_ACPI_STATUS (status2);
+ }
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_detach_region
+ *
+ * PARAMETERS: region_obj - Region Object
+ * acpi_ns_is_locked - Namespace Region Already Locked?
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Break the association between the handler and the region
+ * this is a two way association.
+ *
+ ******************************************************************************/
+
+void
+acpi_ev_detach_region(
+ union acpi_operand_object *region_obj,
+ u8 acpi_ns_is_locked)
+{
+ union acpi_operand_object *handler_obj;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object **last_obj_ptr;
+ acpi_adr_space_setup region_setup;
+ void **region_context;
+ union acpi_operand_object *region_obj2;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_detach_region");
+
+
+ region_obj2 = acpi_ns_get_secondary_object (region_obj);
+ if (!region_obj2) {
+ return_VOID;
+ }
+ region_context = &region_obj2->extra.region_context;
+
+ /* Get the address handler from the region object */
+
+ handler_obj = region_obj->region.handler;
+ if (!handler_obj) {
+ /* This region has no handler, all done */
+
+ return_VOID;
+ }
+
+ /* Find this region in the handler's list */
+
+ obj_desc = handler_obj->address_space.region_list;
+ last_obj_ptr = &handler_obj->address_space.region_list;
+
+ while (obj_desc) {
+ /* Is this the correct Region? */
+
+ if (obj_desc == region_obj) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Removing Region %p from address handler %p\n",
+ region_obj, handler_obj));
+
+ /* This is it, remove it from the handler's list */
+
+ *last_obj_ptr = obj_desc->region.next;
+ obj_desc->region.next = NULL; /* Must clear field */
+
+ if (acpi_ns_is_locked) {
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_VOID;
+ }
+ }
+
+ /* Now stop region accesses by executing the _REG method */
+
+ status = acpi_ev_execute_reg_method (region_obj, 0);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s from region _REG, [%s]\n",
+ acpi_format_exception (status),
+ acpi_ut_get_region_name (region_obj->region.space_id)));
+ }
+
+ if (acpi_ns_is_locked) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_VOID;
+ }
+ }
+
+ /* Call the setup handler with the deactivate notification */
+
+ region_setup = handler_obj->address_space.setup;
+ status = region_setup (region_obj, ACPI_REGION_DEACTIVATE,
+ handler_obj->address_space.context, region_context);
+
+ /* Init routine may fail, Just ignore errors */
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s from region init, [%s]\n",
+ acpi_format_exception (status),
+ acpi_ut_get_region_name (region_obj->region.space_id)));
+ }
+
+ region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE);
+
+ /*
+ * Remove handler reference in the region
+ *
+ * NOTE: this doesn't mean that the region goes away
+ * The region is just inaccessible as indicated to
+ * the _REG method
+ *
+ * If the region is on the handler's list
+ * this better be the region's handler
+ */
+ region_obj->region.handler = NULL;
+ acpi_ut_remove_reference (handler_obj);
+
+ return_VOID;
+ }
+
+ /* Walk the linked list of handlers */
+
+ last_obj_ptr = &obj_desc->region.next;
+ obj_desc = obj_desc->region.next;
+ }
+
+ /* If we get here, the region was not in the handler's region list */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Cannot remove region %p from address handler %p\n",
+ region_obj, handler_obj));
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_attach_region
+ *
+ * PARAMETERS: handler_obj - Handler Object
+ * region_obj - Region Object
+ * acpi_ns_is_locked - Namespace Region Already Locked?
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Create the association between the handler and the region
+ * this is a two way association.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_attach_region (
+ union acpi_operand_object *handler_obj,
+ union acpi_operand_object *region_obj,
+ u8 acpi_ns_is_locked)
+{
+
+ ACPI_FUNCTION_TRACE ("ev_attach_region");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Adding Region [%4.4s] %p to address handler %p [%s]\n",
+ acpi_ut_get_node_name (region_obj->region.node),
+ region_obj, handler_obj,
+ acpi_ut_get_region_name (region_obj->region.space_id)));
+
+ /* Link this region to the front of the handler's list */
+
+ region_obj->region.next = handler_obj->address_space.region_list;
+ handler_obj->address_space.region_list = region_obj;
+
+ /* Install the region's handler */
+
+ if (region_obj->region.handler) {
+ return_ACPI_STATUS (AE_ALREADY_EXISTS);
+ }
+
+ region_obj->region.handler = handler_obj;
+ acpi_ut_add_reference (handler_obj);
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_handler
+ *
+ * PARAMETERS: walk_namespace callback
+ *
+ * DESCRIPTION: This routine installs an address handler into objects that are
+ * of type Region or Device.
+ *
+ * If the Object is a Device, and the device has a handler of
+ * the same type then the search is terminated in that branch.
+ *
+ * This is because the existing handler is closer in proximity
+ * to any more regions than the one we are trying to install.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_install_handler (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ union acpi_operand_object *handler_obj;
+ union acpi_operand_object *next_handler_obj;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_NAME ("ev_install_handler");
+
+
+ handler_obj = (union acpi_operand_object *) context;
+
+ /* Parameter validation */
+
+ if (!handler_obj) {
+ return (AE_OK);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_map_handle_to_node (obj_handle);
+ if (!node) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We only care about regions.and objects
+ * that are allowed to have address space handlers
+ */
+ if ((node->type != ACPI_TYPE_DEVICE) &&
+ (node->type != ACPI_TYPE_REGION) &&
+ (node != acpi_gbl_root_node)) {
+ return (AE_OK);
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ /* No object, just exit */
+
+ return (AE_OK);
+ }
+
+ /* Devices are handled different than regions */
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_DEVICE) {
+ /* Check if this Device already has a handler for this address space */
+
+ next_handler_obj = obj_desc->device.handler;
+ while (next_handler_obj) {
+ /* Found a handler, is it for the same address space? */
+
+ if (next_handler_obj->address_space.space_id == handler_obj->address_space.space_id) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Found handler for region [%s] in device %p(%p) handler %p\n",
+ acpi_ut_get_region_name (handler_obj->address_space.space_id),
+ obj_desc, next_handler_obj, handler_obj));
+
+ /*
+ * Since the object we found it on was a device, then it
+ * means that someone has already installed a handler for
+ * the branch of the namespace from this device on. Just
+ * bail out telling the walk routine to not traverse this
+ * branch. This preserves the scoping rule for handlers.
+ */
+ return (AE_CTRL_DEPTH);
+ }
+
+ /* Walk the linked list of handlers attached to this device */
+
+ next_handler_obj = next_handler_obj->address_space.next;
+ }
+
+ /*
+ * As long as the device didn't have a handler for this
+ * space we don't care about it. We just ignore it and
+ * proceed.
+ */
+ return (AE_OK);
+ }
+
+ /* Object is a Region */
+
+ if (obj_desc->region.space_id != handler_obj->address_space.space_id) {
+ /*
+ * This region is for a different address space
+ * -- just ignore it
+ */
+ return (AE_OK);
+ }
+
+ /*
+ * Now we have a region and it is for the handler's address
+ * space type.
+ *
+ * First disconnect region for any previous handler (if any)
+ */
+ acpi_ev_detach_region (obj_desc, FALSE);
+
+ /* Connect the region to the new handler */
+
+ status = acpi_ev_attach_region (handler_obj, obj_desc, FALSE);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_space_handler
+ *
+ * PARAMETERS: Node - Namespace node for the device
+ * space_id - The address space ID
+ * Handler - Address of the handler
+ * Setup - Address of the setup function
+ * Context - Value passed to the handler on each access
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for all op_regions of a given space_id.
+ * Assumes namespace is locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_install_space_handler (
+ struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup,
+ void *context)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj;
+ acpi_status status;
+ acpi_object_type type;
+ u16 flags = 0;
+
+
+ ACPI_FUNCTION_TRACE ("ev_install_space_handler");
+
+
+ /*
+ * This registration is valid for only the types below
+ * and the root. This is where the default handlers
+ * get placed.
+ */
+ if ((node->type != ACPI_TYPE_DEVICE) &&
+ (node->type != ACPI_TYPE_PROCESSOR) &&
+ (node->type != ACPI_TYPE_THERMAL) &&
+ (node != acpi_gbl_root_node)) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ if (handler == ACPI_DEFAULT_HANDLER) {
+ flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED;
+
+ switch (space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+ handler = acpi_ex_system_memory_space_handler;
+ setup = acpi_ev_system_memory_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+ handler = acpi_ex_system_io_space_handler;
+ setup = acpi_ev_io_space_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_PCI_CONFIG:
+ handler = acpi_ex_pci_config_space_handler;
+ setup = acpi_ev_pci_config_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_CMOS:
+ handler = acpi_ex_cmos_space_handler;
+ setup = acpi_ev_cmos_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_PCI_BAR_TARGET:
+ handler = acpi_ex_pci_bar_space_handler;
+ setup = acpi_ev_pci_bar_region_setup;
+ break;
+
+ case ACPI_ADR_SPACE_DATA_TABLE:
+ handler = acpi_ex_data_table_space_handler;
+ setup = NULL;
+ break;
+
+ default:
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ }
+
+ /* If the caller hasn't specified a setup routine, use the default */
+
+ if (!setup) {
+ setup = acpi_ev_default_region_setup;
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (obj_desc) {
+ /*
+ * The attached device object already exists.
+ * Make sure the handler is not already installed.
+ */
+ handler_obj = obj_desc->device.handler;
+
+ /* Walk the handler list for this device */
+
+ while (handler_obj) {
+ /* Same space_id indicates a handler already installed */
+
+ if (handler_obj->address_space.space_id == space_id) {
+ if (handler_obj->address_space.handler == handler) {
+ /*
+ * It is (relatively) OK to attempt to install the SAME
+ * handler twice. This can easily happen with PCI_Config space.
+ */
+ status = AE_SAME_HANDLER;
+ goto unlock_and_exit;
+ }
+ else {
+ /* A handler is already installed */
+
+ status = AE_ALREADY_EXISTS;
+ }
+ goto unlock_and_exit;
+ }
+
+ /* Walk the linked list of handlers */
+
+ handler_obj = handler_obj->address_space.next;
+ }
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Creating object on Device %p while installing handler\n", node));
+
+ /* obj_desc does not exist, create one */
+
+ if (node->type == ACPI_TYPE_ANY) {
+ type = ACPI_TYPE_DEVICE;
+ }
+ else {
+ type = node->type;
+ }
+
+ obj_desc = acpi_ut_create_internal_object (type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Init new descriptor */
+
+ obj_desc->common.type = (u8) type;
+
+ /* Attach the new object to the Node */
+
+ status = acpi_ns_attach_object (node, obj_desc, type);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n",
+ acpi_ut_get_region_name (space_id), space_id,
+ acpi_ut_get_node_name (node), node, obj_desc));
+
+ /*
+ * Install the handler
+ *
+ * At this point there is no existing handler.
+ * Just allocate the object for the handler and link it
+ * into the list.
+ */
+ handler_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_ADDRESS_HANDLER);
+ if (!handler_obj) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Init handler obj */
+
+ handler_obj->address_space.space_id = (u8) space_id;
+ handler_obj->address_space.hflags = flags;
+ handler_obj->address_space.region_list = NULL;
+ handler_obj->address_space.node = node;
+ handler_obj->address_space.handler = handler;
+ handler_obj->address_space.context = context;
+ handler_obj->address_space.setup = setup;
+
+ /* Install at head of Device.address_space list */
+
+ handler_obj->address_space.next = obj_desc->device.handler;
+
+ /*
+ * The Device object is the first reference on the handler_obj.
+ * Each region that uses the handler adds a reference.
+ */
+ obj_desc->device.handler = handler_obj;
+
+ /*
+ * Walk the namespace finding all of the regions this
+ * handler will manage.
+ *
+ * Start at the device and search the branch toward
+ * the leaf nodes until either the leaf is encountered or
+ * a device is detected that has an address handler of the
+ * same type.
+ *
+ * In either case, back up and search down the remainder
+ * of the branch
+ */
+ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
+ ACPI_NS_WALK_UNLOCK, acpi_ev_install_handler,
+ handler_obj, NULL);
+
+unlock_and_exit:
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_execute_reg_methods
+ *
+ * PARAMETERS: Node - Namespace node for the device
+ * space_id - The address space ID
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Run all _REG methods for the input Space ID;
+ * Note: assumes namespace is locked, or system init time.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_execute_reg_methods (
+ struct acpi_namespace_node *node,
+ acpi_adr_space_type space_id)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_execute_reg_methods");
+
+
+ /*
+ * Run all _REG methods for all Operation Regions for this
+ * space ID. This is a separate walk in order to handle any
+ * interdependencies between regions and _REG methods. (i.e. handlers
+ * must be installed for all regions of this Space ID before we
+ * can run any _REG methods)
+ */
+ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, node, ACPI_UINT32_MAX,
+ ACPI_NS_WALK_UNLOCK, acpi_ev_reg_run,
+ &space_id, NULL);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_reg_run
+ *
+ * PARAMETERS: walk_namespace callback
+ *
+ * DESCRIPTION: Run _REg method for region objects of the requested space_iD
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_reg_run (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ acpi_adr_space_type space_id;
+ acpi_status status;
+
+
+ space_id = *ACPI_CAST_PTR (acpi_adr_space_type, context);
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_map_handle_to_node (obj_handle);
+ if (!node) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We only care about regions.and objects
+ * that are allowed to have address space handlers
+ */
+ if ((node->type != ACPI_TYPE_REGION) &&
+ (node != acpi_gbl_root_node)) {
+ return (AE_OK);
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ /* No object, just exit */
+
+ return (AE_OK);
+ }
+
+ /* Object is a Region */
+
+ if (obj_desc->region.space_id != space_id) {
+ /*
+ * This region is for a different address space
+ * -- just ignore it
+ */
+ return (AE_OK);
+ }
+
+ status = acpi_ev_execute_reg_method (obj_desc, 1);
+ return (status);
+}
+
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
new file mode 100644
index 000000000000..4983a3378be5
--- /dev/null
+++ b/drivers/acpi/events/evrgnini.c
@@ -0,0 +1,580 @@
+/******************************************************************************
+ *
+ * Module Name: evrgnini- ACPI address_space (op_region) init
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evrgnini")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_system_memory_region_setup
+ *
+ * PARAMETERS: Handle - Region we are interested in
+ * Function - Start or stop
+ * handler_context - Address space handler context
+ * region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling, a nop for now
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_system_memory_region_setup (
+ acpi_handle handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ union acpi_operand_object *region_desc = (union acpi_operand_object *) handle;
+ struct acpi_mem_space_context *local_region_context;
+
+
+ ACPI_FUNCTION_TRACE ("ev_system_memory_region_setup");
+
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ if (*region_context) {
+ ACPI_MEM_FREE (*region_context);
+ *region_context = NULL;
+ }
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Create a new context */
+
+ local_region_context = ACPI_MEM_CALLOCATE (sizeof (struct acpi_mem_space_context));
+ if (!(local_region_context)) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Save the region length and address for use in the handler */
+
+ local_region_context->length = region_desc->region.length;
+ local_region_context->address = region_desc->region.address;
+
+ *region_context = local_region_context;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_io_space_region_setup
+ *
+ * PARAMETERS: Handle - Region we are interested in
+ * Function - Start or stop
+ * handler_context - Address space handler context
+ * region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_io_space_region_setup (
+ acpi_handle handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ ACPI_FUNCTION_TRACE ("ev_io_space_region_setup");
+
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ *region_context = NULL;
+ }
+ else {
+ *region_context = handler_context;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_pci_config_region_setup
+ *
+ * PARAMETERS: Handle - Region we are interested in
+ * Function - Start or stop
+ * handler_context - Address space handler context
+ * region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ * MUTEX: Assumes namespace is not locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_pci_config_region_setup (
+ acpi_handle handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ acpi_status status = AE_OK;
+ acpi_integer pci_value;
+ struct acpi_pci_id *pci_id = *region_context;
+ union acpi_operand_object *handler_obj;
+ struct acpi_namespace_node *parent_node;
+ struct acpi_namespace_node *pci_root_node;
+ union acpi_operand_object *region_obj = (union acpi_operand_object *) handle;
+ struct acpi_device_id object_hID;
+
+
+ ACPI_FUNCTION_TRACE ("ev_pci_config_region_setup");
+
+
+ handler_obj = region_obj->region.handler;
+ if (!handler_obj) {
+ /*
+ * No installed handler. This shouldn't happen because the dispatch
+ * routine checks before we get here, but we check again just in case.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Attempting to init a region %p, with no handler\n", region_obj));
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ *region_context = NULL;
+ if (function == ACPI_REGION_DEACTIVATE) {
+ if (pci_id) {
+ ACPI_MEM_FREE (pci_id);
+ }
+ return_ACPI_STATUS (status);
+ }
+
+ parent_node = acpi_ns_get_parent_node (region_obj->region.node);
+
+ /*
+ * Get the _SEG and _BBN values from the device upon which the handler
+ * is installed.
+ *
+ * We need to get the _SEG and _BBN objects relative to the PCI BUS device.
+ * This is the device the handler has been registered to handle.
+ */
+
+ /*
+ * If the address_space.Node is still pointing to the root, we need
+ * to scan upward for a PCI Root bridge and re-associate the op_region
+ * handlers with that device.
+ */
+ if (handler_obj->address_space.node == acpi_gbl_root_node) {
+ /* Start search from the parent object */
+
+ pci_root_node = parent_node;
+ while (pci_root_node != acpi_gbl_root_node) {
+ status = acpi_ut_execute_HID (pci_root_node, &object_hID);
+ if (ACPI_SUCCESS (status)) {
+ /* Got a valid _HID, check if this is a PCI root */
+
+ if (!(ACPI_STRNCMP (object_hID.value, PCI_ROOT_HID_STRING,
+ sizeof (PCI_ROOT_HID_STRING)))) {
+ /* Install a handler for this PCI root bridge */
+
+ status = acpi_install_address_space_handler ((acpi_handle) pci_root_node,
+ ACPI_ADR_SPACE_PCI_CONFIG,
+ ACPI_DEFAULT_HANDLER, NULL, NULL);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_SAME_HANDLER) {
+ /*
+ * It is OK if the handler is already installed on the root
+ * bridge. Still need to return a context object for the
+ * new PCI_Config operation region, however.
+ */
+ status = AE_OK;
+ }
+ else {
+ ACPI_REPORT_ERROR ((
+ "Could not install pci_config handler for Root Bridge %4.4s, %s\n",
+ acpi_ut_get_node_name (pci_root_node), acpi_format_exception (status)));
+ }
+ }
+ break;
+ }
+ }
+
+ pci_root_node = acpi_ns_get_parent_node (pci_root_node);
+ }
+
+ /* PCI root bridge not found, use namespace root node */
+ }
+ else {
+ pci_root_node = handler_obj->address_space.node;
+ }
+
+ /*
+ * If this region is now initialized, we are done.
+ * (install_address_space_handler could have initialized it)
+ */
+ if (region_obj->region.flags & AOPOBJ_SETUP_COMPLETE) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Region is still not initialized. Create a new context */
+
+ pci_id = ACPI_MEM_CALLOCATE (sizeof (struct acpi_pci_id));
+ if (!pci_id) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * For PCI_Config space access, we need the segment, bus,
+ * device and function numbers. Acquire them here.
+ */
+
+ /*
+ * Get the PCI device and function numbers from the _ADR object
+ * contained in the parent's scope.
+ */
+ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, parent_node, &pci_value);
+
+ /*
+ * The default is zero, and since the allocation above zeroed
+ * the data, just do nothing on failure.
+ */
+ if (ACPI_SUCCESS (status)) {
+ pci_id->device = ACPI_HIWORD (ACPI_LODWORD (pci_value));
+ pci_id->function = ACPI_LOWORD (ACPI_LODWORD (pci_value));
+ }
+
+ /* The PCI segment number comes from the _SEG method */
+
+ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__SEG, pci_root_node, &pci_value);
+ if (ACPI_SUCCESS (status)) {
+ pci_id->segment = ACPI_LOWORD (pci_value);
+ }
+
+ /* The PCI bus number comes from the _BBN method */
+
+ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__BBN, pci_root_node, &pci_value);
+ if (ACPI_SUCCESS (status)) {
+ pci_id->bus = ACPI_LOWORD (pci_value);
+ }
+
+ /* Complete this device's pci_id */
+
+ acpi_os_derive_pci_id (pci_root_node, region_obj->region.node, &pci_id);
+
+ *region_context = pci_id;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_pci_bar_region_setup
+ *
+ * PARAMETERS: Handle - Region we are interested in
+ * Function - Start or stop
+ * handler_context - Address space handler context
+ * region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ * MUTEX: Assumes namespace is not locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_pci_bar_region_setup (
+ acpi_handle handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ ACPI_FUNCTION_TRACE ("ev_pci_bar_region_setup");
+
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_cmos_region_setup
+ *
+ * PARAMETERS: Handle - Region we are interested in
+ * Function - Start or stop
+ * handler_context - Address space handler context
+ * region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ * MUTEX: Assumes namespace is not locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_cmos_region_setup (
+ acpi_handle handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ ACPI_FUNCTION_TRACE ("ev_cmos_region_setup");
+
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_default_region_setup
+ *
+ * PARAMETERS: Handle - Region we are interested in
+ * Function - Start or stop
+ * handler_context - Address space handler context
+ * region_context - Region specific context
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Do any prep work for region handling
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_default_region_setup (
+ acpi_handle handle,
+ u32 function,
+ void *handler_context,
+ void **region_context)
+{
+ ACPI_FUNCTION_TRACE ("ev_default_region_setup");
+
+
+ if (function == ACPI_REGION_DEACTIVATE) {
+ *region_context = NULL;
+ }
+ else {
+ *region_context = handler_context;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_initialize_region
+ *
+ * PARAMETERS: region_obj - Region we are initializing
+ * acpi_ns_locked - Is namespace locked?
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initializes the region, finds any _REG methods and saves them
+ * for execution at a later time
+ *
+ * Get the appropriate address space handler for a newly
+ * created region.
+ *
+ * This also performs address space specific initialization. For
+ * example, PCI regions must have an _ADR object that contains
+ * a PCI address in the scope of the definition. This address is
+ * required to perform an access to PCI config space.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_initialize_region (
+ union acpi_operand_object *region_obj,
+ u8 acpi_ns_locked)
+{
+ union acpi_operand_object *handler_obj;
+ union acpi_operand_object *obj_desc;
+ acpi_adr_space_type space_id;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ struct acpi_namespace_node *method_node;
+ acpi_name *reg_name_ptr = (acpi_name *) METHOD_NAME__REG;
+ union acpi_operand_object *region_obj2;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ev_initialize_region", acpi_ns_locked);
+
+
+ if (!region_obj) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (region_obj->common.flags & AOPOBJ_OBJECT_INITIALIZED) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ region_obj2 = acpi_ns_get_secondary_object (region_obj);
+ if (!region_obj2) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ node = acpi_ns_get_parent_node (region_obj->region.node);
+ space_id = region_obj->region.space_id;
+
+ /* Setup defaults */
+
+ region_obj->region.handler = NULL;
+ region_obj2->extra.method_REG = NULL;
+ region_obj->common.flags &= ~(AOPOBJ_SETUP_COMPLETE);
+ region_obj->common.flags |= AOPOBJ_OBJECT_INITIALIZED;
+
+ /* Find any "_REG" method associated with this region definition */
+
+ status = acpi_ns_search_node (*reg_name_ptr, node,
+ ACPI_TYPE_METHOD, &method_node);
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * The _REG method is optional and there can be only one per region
+ * definition. This will be executed when the handler is attached
+ * or removed
+ */
+ region_obj2->extra.method_REG = method_node;
+ }
+
+ /*
+ * The following loop depends upon the root Node having no parent
+ * ie: acpi_gbl_root_node->parent_entry being set to NULL
+ */
+ while (node) {
+ /* Check to see if a handler exists */
+
+ handler_obj = NULL;
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (obj_desc) {
+ /* Can only be a handler if the object exists */
+
+ switch (node->type) {
+ case ACPI_TYPE_DEVICE:
+
+ handler_obj = obj_desc->device.handler;
+ break;
+
+ case ACPI_TYPE_PROCESSOR:
+
+ handler_obj = obj_desc->processor.handler;
+ break;
+
+ case ACPI_TYPE_THERMAL:
+
+ handler_obj = obj_desc->thermal_zone.handler;
+ break;
+
+ default:
+ /* Ignore other objects */
+ break;
+ }
+
+ while (handler_obj) {
+ /* Is this handler of the correct type? */
+
+ if (handler_obj->address_space.space_id == space_id) {
+ /* Found correct handler */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Found handler %p for region %p in obj %p\n",
+ handler_obj, region_obj, obj_desc));
+
+ status = acpi_ev_attach_region (handler_obj, region_obj,
+ acpi_ns_locked);
+
+ /*
+ * Tell all users that this region is usable by running the _REG
+ * method
+ */
+ if (acpi_ns_locked) {
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ status = acpi_ev_execute_reg_method (region_obj, 1);
+
+ if (acpi_ns_locked) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Try next handler in the list */
+
+ handler_obj = handler_obj->address_space.next;
+ }
+ }
+
+ /*
+ * This node does not have the handler we need;
+ * Pop up one level
+ */
+ node = acpi_ns_get_parent_node (node);
+ }
+
+ /* If we get here, there is no handler for this region */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "No handler for region_type %s(%X) (region_obj %p)\n",
+ acpi_ut_get_region_name (space_id), space_id, region_obj));
+
+ return_ACPI_STATUS (AE_NOT_EXIST);
+}
+
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
new file mode 100644
index 000000000000..46b31995c827
--- /dev/null
+++ b/drivers/acpi/events/evsci.c
@@ -0,0 +1,199 @@
+/*******************************************************************************
+ *
+ * Module Name: evsci - System Control Interrupt configuration and
+ * legacy to ACPI mode state transition functions
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evsci")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_sci_xrupt_handler
+ *
+ * PARAMETERS: Context - Calling Context
+ *
+ * RETURN: Status code indicates whether interrupt was handled.
+ *
+ * DESCRIPTION: Interrupt handler that will figure out what function or
+ * control method to call to deal with a SCI.
+ *
+ ******************************************************************************/
+
+static u32 ACPI_SYSTEM_XFACE
+acpi_ev_sci_xrupt_handler (
+ void *context)
+{
+ struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
+ u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
+
+
+ ACPI_FUNCTION_TRACE("ev_sci_xrupt_handler");
+
+
+ /*
+ * We are guaranteed by the ACPI CA initialization/shutdown code that
+ * if this interrupt handler is installed, ACPI is enabled.
+ */
+
+ /*
+ * Fixed Events:
+ * Check for and dispatch any Fixed Events that have occurred
+ */
+ interrupt_handled |= acpi_ev_fixed_event_detect ();
+
+ /*
+ * General Purpose Events:
+ * Check for and dispatch any GPEs that have occurred
+ */
+ interrupt_handled |= acpi_ev_gpe_detect (gpe_xrupt_list);
+
+ return_VALUE (interrupt_handled);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ev_gpe_xrupt_handler
+ *
+ * PARAMETERS: Context - Calling Context
+ *
+ * RETURN: Status code indicates whether interrupt was handled.
+ *
+ * DESCRIPTION: Handler for GPE Block Device interrupts
+ *
+ ******************************************************************************/
+
+u32 ACPI_SYSTEM_XFACE
+acpi_ev_gpe_xrupt_handler (
+ void *context)
+{
+ struct acpi_gpe_xrupt_info *gpe_xrupt_list = context;
+ u32 interrupt_handled = ACPI_INTERRUPT_NOT_HANDLED;
+
+
+ ACPI_FUNCTION_TRACE("ev_gpe_xrupt_handler");
+
+
+ /*
+ * We are guaranteed by the ACPI CA initialization/shutdown code that
+ * if this interrupt handler is installed, ACPI is enabled.
+ */
+
+ /*
+ * GPEs:
+ * Check for and dispatch any GPEs that have occurred
+ */
+ interrupt_handled |= acpi_ev_gpe_detect (gpe_xrupt_list);
+
+ return_VALUE (interrupt_handled);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ev_install_sci_handler
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Installs SCI handler.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ev_install_sci_handler (void)
+{
+ u32 status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ev_install_sci_handler");
+
+
+ status = acpi_os_install_interrupt_handler ((u32) acpi_gbl_FADT->sci_int,
+ acpi_ev_sci_xrupt_handler, acpi_gbl_gpe_xrupt_list_head);
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ev_remove_sci_handler
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: E_OK if handler uninstalled OK, E_ERROR if handler was not
+ * installed to begin with
+ *
+ * DESCRIPTION: Remove the SCI interrupt handler. No further SCIs will be
+ * taken.
+ *
+ * Note: It doesn't seem important to disable all events or set the event
+ * enable registers to their original values. The OS should disable
+ * the SCI interrupt level when the handler is removed, so no more
+ * events will come in.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ev_remove_sci_handler (void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ev_remove_sci_handler");
+
+
+ /* Just let the OS remove the handler and disable the level */
+
+ status = acpi_os_remove_interrupt_handler ((u32) acpi_gbl_FADT->sci_int,
+ acpi_ev_sci_xrupt_handler);
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
new file mode 100644
index 000000000000..0bfec10a5f1e
--- /dev/null
+++ b/drivers/acpi/events/evxface.c
@@ -0,0 +1,834 @@
+/******************************************************************************
+ *
+ * Module Name: evxface - External interfaces for ACPI events
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evxface")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_exception_handler
+ *
+ * PARAMETERS: Handler - Pointer to the handler function for the
+ * event
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_install_exception_handler (
+ acpi_exception_handler handler)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_install_exception_handler");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Don't allow two handlers. */
+
+ if (acpi_gbl_exception_handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
+
+ /* Install the handler */
+
+ acpi_gbl_exception_handler = handler;
+
+cleanup:
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_ACPI_STATUS (status);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_fixed_event_handler
+ *
+ * PARAMETERS: Event - Event type to enable.
+ * Handler - Pointer to the handler function for the
+ * event
+ * Context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Saves the pointer to the handler function and then enables the
+ * event.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_install_fixed_event_handler (
+ u32 event,
+ acpi_event_handler handler,
+ void *context)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_install_fixed_event_handler");
+
+
+ /* Parameter validation */
+
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Don't allow two handlers. */
+
+ if (NULL != acpi_gbl_fixed_event_handlers[event].handler) {
+ status = AE_ALREADY_EXISTS;
+ goto cleanup;
+ }
+
+ /* Install the handler before enabling the event */
+
+ acpi_gbl_fixed_event_handlers[event].handler = handler;
+ acpi_gbl_fixed_event_handlers[event].context = context;
+
+ status = acpi_clear_event (event);
+ if (ACPI_SUCCESS(status))
+ status = acpi_enable_event (event, 0);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Could not enable fixed event.\n"));
+
+ /* Remove the handler */
+
+ acpi_gbl_fixed_event_handlers[event].handler = NULL;
+ acpi_gbl_fixed_event_handlers[event].context = NULL;
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Enabled fixed event %X, Handler=%p\n", event, handler));
+ }
+
+
+cleanup:
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_install_fixed_event_handler);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_fixed_event_handler
+ *
+ * PARAMETERS: Event - Event type to disable.
+ * Handler - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disables the event and unregisters the event handler.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_remove_fixed_event_handler (
+ u32 event,
+ acpi_event_handler handler)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_remove_fixed_event_handler");
+
+
+ /* Parameter validation */
+
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Disable the event before removing the handler */
+
+ status = acpi_disable_event (event, 0);
+
+ /* Always Remove the handler */
+
+ acpi_gbl_fixed_event_handlers[event].handler = NULL;
+ acpi_gbl_fixed_event_handlers[event].context = NULL;
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN,
+ "Could not write to fixed event enable register.\n"));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Disabled fixed event %X.\n", event));
+ }
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_remove_fixed_event_handler);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_notify_handler
+ *
+ * PARAMETERS: Device - The device for which notifies will be handled
+ * handler_type - The type of handler:
+ * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
+ * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
+ * ACPI_ALL_NOTIFY: both system and device
+ * Handler - Address of the handler
+ * Context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for notifies on an ACPI device
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_install_notify_handler (
+ acpi_handle device,
+ u32 handler_type,
+ acpi_notify_handler handler,
+ void *context)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *notify_obj;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_install_notify_handler");
+
+
+ /* Parameter validation */
+
+ if ((!device) ||
+ (!handler) ||
+ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_map_handle_to_node (device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Root Object:
+ * Registering a notify handler on the root object indicates that the
+ * caller wishes to receive notifications for all objects. Note that
+ * only one <external> global handler can be regsitered (per notify type).
+ */
+ if (device == ACPI_ROOT_OBJECT) {
+ /* Make sure the handler is not already installed */
+
+ if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
+ acpi_gbl_system_notify.handler) ||
+ ((handler_type & ACPI_DEVICE_NOTIFY) &&
+ acpi_gbl_device_notify.handler)) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
+
+ if (handler_type & ACPI_SYSTEM_NOTIFY) {
+ acpi_gbl_system_notify.node = node;
+ acpi_gbl_system_notify.handler = handler;
+ acpi_gbl_system_notify.context = context;
+ }
+
+ if (handler_type & ACPI_DEVICE_NOTIFY) {
+ acpi_gbl_device_notify.node = node;
+ acpi_gbl_device_notify.handler = handler;
+ acpi_gbl_device_notify.context = context;
+ }
+
+ /* Global notify handler installed */
+ }
+
+ /*
+ * All Other Objects:
+ * Caller will only receive notifications specific to the target object.
+ * Note that only certain object types can receive notifications.
+ */
+ else {
+ /* Notifies allowed on this object? */
+
+ if (!acpi_ev_is_notify_object (node)) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (obj_desc) {
+ /* Object exists - make sure there's no handler */
+
+ if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
+ obj_desc->common_notify.system_notify) ||
+ ((handler_type & ACPI_DEVICE_NOTIFY) &&
+ obj_desc->common_notify.device_notify)) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
+ }
+ else {
+ /* Create a new object */
+
+ obj_desc = acpi_ut_create_internal_object (node->type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /* Attach new object to the Node */
+
+ status = acpi_ns_attach_object (device, obj_desc, node->type);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Install the handler */
+
+ notify_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_NOTIFY);
+ if (!notify_obj) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ notify_obj->notify.node = node;
+ notify_obj->notify.handler = handler;
+ notify_obj->notify.context = context;
+
+ if (handler_type & ACPI_SYSTEM_NOTIFY) {
+ obj_desc->common_notify.system_notify = notify_obj;
+ }
+
+ if (handler_type & ACPI_DEVICE_NOTIFY) {
+ obj_desc->common_notify.device_notify = notify_obj;
+ }
+
+ if (handler_type == ACPI_ALL_NOTIFY) {
+ /* Extra ref if installed in both */
+
+ acpi_ut_add_reference (notify_obj);
+ }
+ }
+
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_install_notify_handler);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_notify_handler
+ *
+ * PARAMETERS: Device - The device for which notifies will be handled
+ * handler_type - The type of handler:
+ * ACPI_SYSTEM_NOTIFY: system_handler (00-7f)
+ * ACPI_DEVICE_NOTIFY: driver_handler (80-ff)
+ * ACPI_ALL_NOTIFY: both system and device
+ * Handler - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a handler for notifies on an ACPI device
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_remove_notify_handler (
+ acpi_handle device,
+ u32 handler_type,
+ acpi_notify_handler handler)
+{
+ union acpi_operand_object *notify_obj;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_remove_notify_handler");
+
+
+ /* Parameter validation */
+
+ if ((!device) ||
+ (!handler) ||
+ (handler_type > ACPI_MAX_NOTIFY_HANDLER_TYPE)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_map_handle_to_node (device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Root Object */
+
+ if (device == ACPI_ROOT_OBJECT) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n"));
+
+ if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
+ !acpi_gbl_system_notify.handler) ||
+ ((handler_type & ACPI_DEVICE_NOTIFY) &&
+ !acpi_gbl_device_notify.handler)) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /* Make sure all deferred tasks are completed */
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ acpi_os_wait_events_complete(NULL);
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (handler_type & ACPI_SYSTEM_NOTIFY) {
+ acpi_gbl_system_notify.node = NULL;
+ acpi_gbl_system_notify.handler = NULL;
+ acpi_gbl_system_notify.context = NULL;
+ }
+
+ if (handler_type & ACPI_DEVICE_NOTIFY) {
+ acpi_gbl_device_notify.node = NULL;
+ acpi_gbl_device_notify.handler = NULL;
+ acpi_gbl_device_notify.context = NULL;
+ }
+ }
+
+ /* All Other Objects */
+
+ else {
+ /* Notifies allowed on this object? */
+
+ if (!acpi_ev_is_notify_object (node)) {
+ status = AE_TYPE;
+ goto unlock_and_exit;
+ }
+
+ /* Check for an existing internal object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /* Object exists - make sure there's an existing handler */
+
+ if (handler_type & ACPI_SYSTEM_NOTIFY) {
+ notify_obj = obj_desc->common_notify.system_notify;
+ if ((!notify_obj) ||
+ (notify_obj->notify.handler != handler)) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ /* Make sure all deferred tasks are completed */
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ acpi_os_wait_events_complete(NULL);
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Remove the handler */
+ obj_desc->common_notify.system_notify = NULL;
+ acpi_ut_remove_reference (notify_obj);
+ }
+
+ if (handler_type & ACPI_DEVICE_NOTIFY) {
+ notify_obj = obj_desc->common_notify.device_notify;
+ if ((!notify_obj) ||
+ (notify_obj->notify.handler != handler)) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ /* Make sure all deferred tasks are completed */
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ acpi_os_wait_events_complete(NULL);
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Remove the handler */
+ obj_desc->common_notify.device_notify = NULL;
+ acpi_ut_remove_reference (notify_obj);
+ }
+ }
+
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_remove_notify_handler);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_gpe_handler
+ *
+ * PARAMETERS: gpe_number - The GPE number within the GPE block
+ * gpe_block - GPE block (NULL == FADT GPEs)
+ * Type - Whether this GPE should be treated as an
+ * edge- or level-triggered interrupt.
+ * Address - Address of the handler
+ * Context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for a General Purpose Event.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_install_gpe_handler (
+ acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 type,
+ acpi_event_handler address,
+ void *context)
+{
+ struct acpi_gpe_event_info *gpe_event_info;
+ struct acpi_handler_info *handler;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_install_gpe_handler");
+
+
+ /* Parameter validation */
+
+ if ((!address) || (type > ACPI_GPE_XRUPT_TYPE_MASK)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Make sure that there isn't a handler there already */
+
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) == ACPI_GPE_DISPATCH_HANDLER) {
+ status = AE_ALREADY_EXISTS;
+ goto unlock_and_exit;
+ }
+
+ /* Allocate and init handler object */
+
+ handler = ACPI_MEM_CALLOCATE (sizeof (struct acpi_handler_info));
+ if (!handler) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ handler->address = address;
+ handler->context = context;
+ handler->method_node = gpe_event_info->dispatch.method_node;
+
+ /* Disable the GPE before installing the handler */
+
+ status = acpi_ev_disable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Install the handler */
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+ gpe_event_info->dispatch.handler = handler;
+
+ /* Setup up dispatch flags to indicate handler (vs. method) */
+
+ gpe_event_info->flags &= ~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK); /* Clear bits */
+ gpe_event_info->flags |= (u8) (type | ACPI_GPE_DISPATCH_HANDLER);
+
+ acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_install_gpe_handler);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_gpe_handler
+ *
+ * PARAMETERS: gpe_number - The event to remove a handler
+ * gpe_block - GPE block (NULL == FADT GPEs)
+ * Address - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a handler for a General Purpose acpi_event.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_remove_gpe_handler (
+ acpi_handle gpe_device,
+ u32 gpe_number,
+ acpi_event_handler address)
+{
+ struct acpi_gpe_event_info *gpe_event_info;
+ struct acpi_handler_info *handler;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_remove_gpe_handler");
+
+
+ /* Parameter validation */
+
+ if (!address) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Make sure that a handler is indeed installed */
+
+ if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) != ACPI_GPE_DISPATCH_HANDLER) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /* Make sure that the installed handler is the same */
+
+ if (gpe_event_info->dispatch.handler->address != address) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Disable the GPE before removing the handler */
+
+ status = acpi_ev_disable_gpe (gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Make sure all deferred tasks are completed */
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ acpi_os_wait_events_complete(NULL);
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Remove the handler */
+
+ acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+ handler = gpe_event_info->dispatch.handler;
+
+ /* Restore Method node (if any), set dispatch flags */
+
+ gpe_event_info->dispatch.method_node = handler->method_node;
+ gpe_event_info->flags &= ~ACPI_GPE_DISPATCH_MASK; /* Clear bits */
+ if (handler->method_node) {
+ gpe_event_info->flags |= ACPI_GPE_DISPATCH_METHOD;
+ }
+ acpi_os_release_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
+
+ /* Now we can free the handler object */
+
+ ACPI_MEM_FREE (handler);
+
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_remove_gpe_handler);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_acquire_global_lock
+ *
+ * PARAMETERS: Timeout - How long the caller is willing to wait
+ * out_handle - A handle to the lock if acquired
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire the ACPI Global Lock
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_acquire_global_lock (
+ u16 timeout,
+ u32 *handle)
+{
+ acpi_status status;
+
+
+ if (!handle) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ex_enter_interpreter ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ status = acpi_ev_acquire_global_lock (timeout);
+ acpi_ex_exit_interpreter ();
+
+ if (ACPI_SUCCESS (status)) {
+ acpi_gbl_global_lock_handle++;
+ *handle = acpi_gbl_global_lock_handle;
+ }
+
+ return (status);
+}
+EXPORT_SYMBOL(acpi_acquire_global_lock);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_release_global_lock
+ *
+ * PARAMETERS: Handle - Returned from acpi_acquire_global_lock
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release the ACPI Global Lock
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_release_global_lock (
+ u32 handle)
+{
+ acpi_status status;
+
+
+ if (handle != acpi_gbl_global_lock_handle) {
+ return (AE_NOT_ACQUIRED);
+ }
+
+ status = acpi_ev_release_global_lock ();
+ return (status);
+}
+EXPORT_SYMBOL(acpi_release_global_lock);
+
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
new file mode 100644
index 000000000000..fa8d5f25be62
--- /dev/null
+++ b/drivers/acpi/events/evxfevnt.c
@@ -0,0 +1,778 @@
+/******************************************************************************
+ *
+ * Module Name: evxfevnt - External Interfaces, ACPI event disable/enable
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acevents.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evxfevnt")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_enable
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transfers the system into ACPI mode.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_enable (void)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_enable");
+
+
+ /* Make sure we have the FADT*/
+
+ if (!acpi_gbl_FADT) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No FADT information present!\n"));
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "System is already in ACPI mode\n"));
+ }
+ else {
+ /* Transition to ACPI mode */
+
+ status = acpi_hw_set_mode (ACPI_SYS_MODE_ACPI);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not transition to ACPI mode.\n"));
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Transition to ACPI mode successful\n"));
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_disable
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transfers the system into LEGACY mode.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_disable (void)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_disable");
+
+
+ if (!acpi_gbl_FADT) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "No FADT information present!\n"));
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "System is already in legacy (non-ACPI) mode\n"));
+ }
+ else {
+ /* Transition to LEGACY mode */
+
+ status = acpi_hw_set_mode (ACPI_SYS_MODE_LEGACY);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not exit ACPI mode to legacy mode"));
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "ACPI mode disabled\n"));
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_enable_event
+ *
+ * PARAMETERS: Event - The fixed eventto be enabled
+ * Flags - Reserved
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable an ACPI event (fixed)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_enable_event (
+ u32 event,
+ u32 flags)
+{
+ acpi_status status = AE_OK;
+ u32 value;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_enable_event");
+
+
+ /* Decode the Fixed Event */
+
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Enable the requested fixed event (by writing a one to the
+ * enable register bit)
+ */
+ status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id,
+ 1, ACPI_MTX_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Make sure that the hardware responded */
+
+ status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id,
+ &value, ACPI_MTX_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (value != 1) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not enable %s event\n", acpi_ut_get_event_name (event)));
+ return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
+ }
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_enable_event);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_set_gpe_type
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device
+ * gpe_number - GPE level within the GPE block
+ * Type - New GPE type
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable an ACPI event (general purpose)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_set_gpe_type (
+ acpi_handle gpe_device,
+ u32 gpe_number,
+ u8 type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_set_gpe_type");
+
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ if ((gpe_event_info->flags & ACPI_GPE_TYPE_MASK) == type) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Set the new type (will disable GPE if currently enabled) */
+
+ status = acpi_ev_set_gpe_type (gpe_event_info, type);
+
+unlock_and_exit:
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_set_gpe_type);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_enable_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device
+ * gpe_number - GPE level within the GPE block
+ * Flags - Just enable, or also wake enable?
+ * Called from ISR or not
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable an ACPI event (general purpose)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_enable_gpe (
+ acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 flags)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_enable_gpe");
+
+
+ /* Use semaphore lock if not executing at interrupt level */
+
+ if (flags & ACPI_NOT_ISR) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Perform the enable */
+
+ status = acpi_ev_enable_gpe (gpe_event_info, TRUE);
+
+unlock_and_exit:
+ if (flags & ACPI_NOT_ISR) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ }
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_enable_gpe);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_disable_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device
+ * gpe_number - GPE level within the GPE block
+ * Flags - Just disable, or also wake disable?
+ * Called from ISR or not
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable an ACPI event (general purpose)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_disable_gpe (
+ acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 flags)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_disable_gpe");
+
+
+ /* Use semaphore lock if not executing at interrupt level */
+
+ if (flags & ACPI_NOT_ISR) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ev_disable_gpe (gpe_event_info);
+
+unlock_and_exit:
+ if (flags & ACPI_NOT_ISR) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_disable_event
+ *
+ * PARAMETERS: Event - The fixed eventto be enabled
+ * Flags - Reserved
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable an ACPI event (fixed)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_disable_event (
+ u32 event,
+ u32 flags)
+{
+ acpi_status status = AE_OK;
+ u32 value;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_disable_event");
+
+
+ /* Decode the Fixed Event */
+
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Disable the requested fixed event (by writing a zero to the
+ * enable register bit)
+ */
+ status = acpi_set_register (acpi_gbl_fixed_event_info[event].enable_register_id,
+ 0, ACPI_MTX_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_get_register (acpi_gbl_fixed_event_info[event].enable_register_id,
+ &value, ACPI_MTX_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (value != 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not disable %s events\n", acpi_ut_get_event_name (event)));
+ return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
+ }
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_disable_event);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_clear_event
+ *
+ * PARAMETERS: Event - The fixed event to be cleared
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear an ACPI event (fixed)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_clear_event (
+ u32 event)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_clear_event");
+
+
+ /* Decode the Fixed Event */
+
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Clear the requested fixed event (By writing a one to the
+ * status register bit)
+ */
+ status = acpi_set_register (acpi_gbl_fixed_event_info[event].status_register_id,
+ 1, ACPI_MTX_LOCK);
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_clear_event);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_clear_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device
+ * gpe_number - GPE level within the GPE block
+ * Flags - Called from an ISR or not
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear an ACPI event (general purpose)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_clear_gpe (
+ acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 flags)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_clear_gpe");
+
+
+ /* Use semaphore lock if not executing at interrupt level */
+
+ if (flags & ACPI_NOT_ISR) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_hw_clear_gpe (gpe_event_info);
+
+unlock_and_exit:
+ if (flags & ACPI_NOT_ISR) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_event_status
+ *
+ * PARAMETERS: Event - The fixed event
+ * Event Status - Where the current status of the event will
+ * be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtains and returns the current status of the event
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_event_status (
+ u32 event,
+ acpi_event_status *event_status)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_event_status");
+
+
+ if (!event_status) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Decode the Fixed Event */
+
+ if (event > ACPI_EVENT_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Get the status of the requested fixed event */
+
+ status = acpi_get_register (acpi_gbl_fixed_event_info[event].status_register_id,
+ event_status, ACPI_MTX_LOCK);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_gpe_status
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device
+ * gpe_number - GPE level within the GPE block
+ * Flags - Called from an ISR or not
+ * Event Status - Where the current status of the event will
+ * be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get status of an event (general purpose)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_gpe_status (
+ acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 flags,
+ acpi_event_status *event_status)
+{
+ acpi_status status = AE_OK;
+ struct acpi_gpe_event_info *gpe_event_info;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_gpe_status");
+
+
+ /* Use semaphore lock if not executing at interrupt level */
+
+ if (flags & ACPI_NOT_ISR) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EVENTS);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info (gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Obtain status on the requested GPE number */
+
+ status = acpi_hw_get_gpe_status (gpe_event_info, event_status);
+
+unlock_and_exit:
+ if (flags & ACPI_NOT_ISR) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_EVENTS);
+ }
+ return_ACPI_STATUS (status);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_gpe_block
+ *
+ * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
+ * gpe_block_address - Address and space_iD
+ * register_count - Number of GPE register pairs in the block
+ * interrupt_level - H/W interrupt for the block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create and Install a block of GPE registers
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_install_gpe_block (
+ acpi_handle gpe_device,
+ struct acpi_generic_address *gpe_block_address,
+ u32 register_count,
+ u32 interrupt_level)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ struct acpi_gpe_block_info *gpe_block;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_install_gpe_block");
+
+
+ if ((!gpe_device) ||
+ (!gpe_block_address) ||
+ (!register_count)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ node = acpi_ns_map_handle_to_node (gpe_device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * For user-installed GPE Block Devices, the gpe_block_base_number
+ * is always zero
+ */
+ status = acpi_ev_create_gpe_block (node, gpe_block_address, register_count,
+ 0, interrupt_level, &gpe_block);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Get the device_object attached to the node */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ /* No object, create a new one */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_DEVICE);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_DEVICE);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Install the GPE block in the device_object */
+
+ obj_desc->device.gpe_block = gpe_block;
+
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_install_gpe_block);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_gpe_block
+ *
+ * PARAMETERS: gpe_device - Handle to the parent GPE Block Device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a previously installed block of GPE registers
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_remove_gpe_block (
+ acpi_handle gpe_device)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+ struct acpi_namespace_node *node;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_remove_gpe_block");
+
+
+ if (!gpe_device) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ node = acpi_ns_map_handle_to_node (gpe_device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Get the device_object attached to the node */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc ||
+ !obj_desc->device.gpe_block) {
+ return_ACPI_STATUS (AE_NULL_OBJECT);
+ }
+
+ /* Delete the GPE block (but not the device_object) */
+
+ status = acpi_ev_delete_gpe_block (obj_desc->device.gpe_block);
+ if (ACPI_SUCCESS (status)) {
+ obj_desc->device.gpe_block = NULL;
+ }
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_remove_gpe_block);
diff --git a/drivers/acpi/events/evxfregn.c b/drivers/acpi/events/evxfregn.c
new file mode 100644
index 000000000000..d058587b3427
--- /dev/null
+++ b/drivers/acpi/events/evxfregn.c
@@ -0,0 +1,247 @@
+/******************************************************************************
+ *
+ * Module Name: evxfregn - External Interfaces, ACPI Operation Regions and
+ * Address Spaces.
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+
+#define _COMPONENT ACPI_EVENTS
+ ACPI_MODULE_NAME ("evxfregn")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_address_space_handler
+ *
+ * PARAMETERS: Device - Handle for the device
+ * space_id - The address space ID
+ * Handler - Address of the handler
+ * Setup - Address of the setup function
+ * Context - Value passed to the handler on each access
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for all op_regions of a given space_id.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_install_address_space_handler (
+ acpi_handle device,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler,
+ acpi_adr_space_setup setup,
+ void *context)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_install_address_space_handler");
+
+
+ /* Parameter validation */
+
+ if (!device) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_map_handle_to_node (device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Install the handler for all Regions for this Space ID */
+
+ status = acpi_ev_install_space_handler (node, space_id, handler, setup, context);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Run all _REG methods for this address space */
+
+ status = acpi_ev_execute_reg_methods (node, space_id);
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_install_address_space_handler);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_remove_address_space_handler
+ *
+ * PARAMETERS: Device - Handle for the device
+ * space_id - The address space ID
+ * Handler - Address of the handler
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a previously installed handler.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_remove_address_space_handler (
+ acpi_handle device,
+ acpi_adr_space_type space_id,
+ acpi_adr_space_handler handler)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *handler_obj;
+ union acpi_operand_object *region_obj;
+ union acpi_operand_object **last_obj_ptr;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_remove_address_space_handler");
+
+
+ /* Parameter validation */
+
+ if (!device) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Convert and validate the device handle */
+
+ node = acpi_ns_map_handle_to_node (device);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Make sure the internal object exists */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ status = AE_NOT_EXIST;
+ goto unlock_and_exit;
+ }
+
+ /* Find the address handler the user requested */
+
+ handler_obj = obj_desc->device.handler;
+ last_obj_ptr = &obj_desc->device.handler;
+ while (handler_obj) {
+ /* We have a handler, see if user requested this one */
+
+ if (handler_obj->address_space.space_id == space_id) {
+ /* Matched space_id, first dereference this in the Regions */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Removing address handler %p(%p) for region %s on Device %p(%p)\n",
+ handler_obj, handler, acpi_ut_get_region_name (space_id),
+ node, obj_desc));
+
+ region_obj = handler_obj->address_space.region_list;
+
+ /* Walk the handler's region list */
+
+ while (region_obj) {
+ /*
+ * First disassociate the handler from the region.
+ *
+ * NOTE: this doesn't mean that the region goes away
+ * The region is just inaccessible as indicated to
+ * the _REG method
+ */
+ acpi_ev_detach_region (region_obj, TRUE);
+
+ /*
+ * Walk the list: Just grab the head because the
+ * detach_region removed the previous head.
+ */
+ region_obj = handler_obj->address_space.region_list;
+
+ }
+
+ /* Remove this Handler object from the list */
+
+ *last_obj_ptr = handler_obj->address_space.next;
+
+ /* Now we can delete the handler object */
+
+ acpi_ut_remove_reference (handler_obj);
+ goto unlock_and_exit;
+ }
+
+ /* Walk the linked list of handlers */
+
+ last_obj_ptr = &handler_obj->address_space.next;
+ handler_obj = handler_obj->address_space.next;
+ }
+
+ /* The handler does not exist */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
+ "Unable to remove address handler %p for %s(%X), dev_node %p, obj %p\n",
+ handler, acpi_ut_get_region_name (space_id), space_id, node, obj_desc));
+
+ status = AE_NOT_EXIST;
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_remove_address_space_handler);
+
diff --git a/drivers/acpi/executer/Makefile b/drivers/acpi/executer/Makefile
new file mode 100644
index 000000000000..e09998aa012f
--- /dev/null
+++ b/drivers/acpi/executer/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := exconfig.o exfield.o exnames.o exoparg6.o exresolv.o exstorob.o\
+ exconvrt.o exfldio.o exoparg1.o exprep.o exresop.o exsystem.o\
+ excreate.o exmisc.o exoparg2.o exregion.o exstore.o exutils.o \
+ exdump.o exmutex.o exoparg3.o exresnte.o exstoren.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
new file mode 100644
index 000000000000..ac3c061967f2
--- /dev/null
+++ b/drivers/acpi/executer/exconfig.c
@@ -0,0 +1,487 @@
+/******************************************************************************
+ *
+ * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+#include <acpi/actables.h>
+#include <acpi/acdispat.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exconfig")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_add_table
+ *
+ * PARAMETERS: Table - Pointer to raw table
+ * parent_node - Where to load the table (scope)
+ * ddb_handle - Where to return the table handle.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Common function to Install and Load an ACPI table with a
+ * returned table handle.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_add_table (
+ struct acpi_table_header *table,
+ struct acpi_namespace_node *parent_node,
+ union acpi_operand_object **ddb_handle)
+{
+ acpi_status status;
+ struct acpi_table_desc table_info;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE ("ex_add_table");
+
+
+ /* Create an object to be the table handle */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_REFERENCE);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Install the new table into the local data structures */
+
+ ACPI_MEMSET (&table_info, 0, sizeof (struct acpi_table_desc));
+
+ table_info.type = ACPI_TABLE_SSDT;
+ table_info.pointer = table;
+ table_info.length = (acpi_size) table->length;
+ table_info.allocation = ACPI_MEM_ALLOCATED;
+
+ status = acpi_tb_install_table (&table_info);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Add the table to the namespace */
+
+ status = acpi_ns_load_table (table_info.installed_desc, parent_node);
+ if (ACPI_FAILURE (status)) {
+ /* Uninstall table on error */
+
+ (void) acpi_tb_uninstall_table (table_info.installed_desc);
+ goto cleanup;
+ }
+
+ /* Init the table handle */
+
+ obj_desc->reference.opcode = AML_LOAD_OP;
+ obj_desc->reference.object = table_info.installed_desc;
+ *ddb_handle = obj_desc;
+ return_ACPI_STATUS (AE_OK);
+
+
+cleanup:
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_load_table_op
+ *
+ * PARAMETERS: walk_state - Current state with operands
+ * return_desc - Where to store the return object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load an ACPI table
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_load_table_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object **return_desc)
+{
+ acpi_status status;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ struct acpi_table_header *table;
+ struct acpi_namespace_node *parent_node;
+ struct acpi_namespace_node *start_node;
+ struct acpi_namespace_node *parameter_node = NULL;
+ union acpi_operand_object *ddb_handle;
+
+
+ ACPI_FUNCTION_TRACE ("ex_load_table_op");
+
+
+#if 0
+ /*
+ * Make sure that the signature does not match one of the tables that
+ * is already loaded.
+ */
+ status = acpi_tb_match_signature (operand[0]->string.pointer, NULL);
+ if (status == AE_OK) {
+ /* Signature matched -- don't allow override */
+
+ return_ACPI_STATUS (AE_ALREADY_EXISTS);
+ }
+#endif
+
+ /* Find the ACPI table */
+
+ status = acpi_tb_find_table (operand[0]->string.pointer,
+ operand[1]->string.pointer,
+ operand[2]->string.pointer, &table);
+ if (ACPI_FAILURE (status)) {
+ if (status != AE_NOT_FOUND) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Table not found, return an Integer=0 and AE_OK */
+
+ ddb_handle = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!ddb_handle) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ ddb_handle->integer.value = 0;
+ *return_desc = ddb_handle;
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Default nodes */
+
+ start_node = walk_state->scope_info->scope.node;
+ parent_node = acpi_gbl_root_node;
+
+ /* root_path (optional parameter) */
+
+ if (operand[3]->string.length > 0) {
+ /*
+ * Find the node referenced by the root_path_string. This is the
+ * location within the namespace where the table will be loaded.
+ */
+ status = acpi_ns_get_node_by_path (operand[3]->string.pointer, start_node,
+ ACPI_NS_SEARCH_PARENT, &parent_node);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* parameter_path (optional parameter) */
+
+ if (operand[4]->string.length > 0) {
+ if ((operand[4]->string.pointer[0] != '\\') &&
+ (operand[4]->string.pointer[0] != '^')) {
+ /*
+ * Path is not absolute, so it will be relative to the node
+ * referenced by the root_path_string (or the NS root if omitted)
+ */
+ start_node = parent_node;
+ }
+
+ /*
+ * Find the node referenced by the parameter_path_string
+ */
+ status = acpi_ns_get_node_by_path (operand[4]->string.pointer, start_node,
+ ACPI_NS_SEARCH_PARENT, &parameter_node);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Load the table into the namespace */
+
+ status = acpi_ex_add_table (table, parent_node, &ddb_handle);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Parameter Data (optional) */
+
+ if (parameter_node) {
+ /* Store the parameter data into the optional parameter object */
+
+ status = acpi_ex_store (operand[5], ACPI_CAST_PTR (union acpi_operand_object, parameter_node),
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ (void) acpi_ex_unload_table (ddb_handle);
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ *return_desc = ddb_handle;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_load_op
+ *
+ * PARAMETERS: obj_desc - Region or Field where the table will be
+ * obtained
+ * Target - Where a handle to the table will be stored
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load an ACPI table from a field or operation region
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_load_op (
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object *target,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_operand_object *ddb_handle;
+ union acpi_operand_object *buffer_desc = NULL;
+ struct acpi_table_header *table_ptr = NULL;
+ acpi_physical_address address;
+ struct acpi_table_header table_header;
+ u32 i;
+
+ ACPI_FUNCTION_TRACE ("ex_load_op");
+
+
+ /* Object can be either an op_region or a Field */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_REGION:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Region %p %s\n",
+ obj_desc, acpi_ut_get_object_type_name (obj_desc)));
+
+ /*
+ * If the Region Address and Length have not been previously evaluated,
+ * evaluate them now and save the results.
+ */
+ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
+ status = acpi_ds_get_region_arguments (obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Get the base physical address of the region */
+
+ address = obj_desc->region.address;
+
+ /* Get the table length from the table header */
+
+ table_header.length = 0;
+ for (i = 0; i < 8; i++) {
+ status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ,
+ (acpi_physical_address) (i + address), 8,
+ ((u8 *) &table_header) + i);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Sanity check the table length */
+
+ if (table_header.length < sizeof (struct acpi_table_header)) {
+ return_ACPI_STATUS (AE_BAD_HEADER);
+ }
+
+ /* Allocate a buffer for the entire table */
+
+ table_ptr = ACPI_MEM_ALLOCATE (table_header.length);
+ if (!table_ptr) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Get the entire table from the op region */
+
+ for (i = 0; i < table_header.length; i++) {
+ status = acpi_ev_address_space_dispatch (obj_desc, ACPI_READ,
+ (acpi_physical_address) (i + address), 8,
+ ((u8 *) table_ptr + i));
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ }
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Load from Field %p %s\n",
+ obj_desc, acpi_ut_get_object_type_name (obj_desc)));
+
+ /*
+ * The length of the field must be at least as large as the table.
+ * Read the entire field and thus the entire table. Buffer is
+ * allocated during the read.
+ */
+ status = acpi_ex_read_data_from_field (walk_state, obj_desc, &buffer_desc);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer);
+
+ /* Sanity check the table length */
+
+ if (table_ptr->length < sizeof (struct acpi_table_header)) {
+ return_ACPI_STATUS (AE_BAD_HEADER);
+ }
+ break;
+
+
+ default:
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /* The table must be either an SSDT or a PSDT */
+
+ if ((!ACPI_STRNCMP (table_ptr->signature,
+ acpi_gbl_table_data[ACPI_TABLE_PSDT].signature,
+ acpi_gbl_table_data[ACPI_TABLE_PSDT].sig_length)) &&
+ (!ACPI_STRNCMP (table_ptr->signature,
+ acpi_gbl_table_data[ACPI_TABLE_SSDT].signature,
+ acpi_gbl_table_data[ACPI_TABLE_SSDT].sig_length))) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Table has invalid signature [%4.4s], must be SSDT or PSDT\n",
+ table_ptr->signature));
+ status = AE_BAD_SIGNATURE;
+ goto cleanup;
+ }
+
+ /* Install the new table into the local data structures */
+
+ status = acpi_ex_add_table (table_ptr, acpi_gbl_root_node, &ddb_handle);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Store the ddb_handle into the Target operand */
+
+ status = acpi_ex_store (ddb_handle, target, walk_state);
+ if (ACPI_FAILURE (status)) {
+ (void) acpi_ex_unload_table (ddb_handle);
+ }
+
+ return_ACPI_STATUS (status);
+
+
+cleanup:
+
+ if (buffer_desc) {
+ acpi_ut_remove_reference (buffer_desc);
+ }
+ else {
+ ACPI_MEM_FREE (table_ptr);
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_unload_table
+ *
+ * PARAMETERS: ddb_handle - Handle to a previously loaded table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Unload an ACPI table
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_unload_table (
+ union acpi_operand_object *ddb_handle)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *table_desc = ddb_handle;
+ struct acpi_table_desc *table_info;
+
+
+ ACPI_FUNCTION_TRACE ("ex_unload_table");
+
+
+ /*
+ * Validate the handle
+ * Although the handle is partially validated in acpi_ex_reconfiguration(),
+ * when it calls acpi_ex_resolve_operands(), the handle is more completely
+ * validated here.
+ */
+ if ((!ddb_handle) ||
+ (ACPI_GET_DESCRIPTOR_TYPE (ddb_handle) != ACPI_DESC_TYPE_OPERAND) ||
+ (ACPI_GET_OBJECT_TYPE (ddb_handle) != ACPI_TYPE_LOCAL_REFERENCE)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Get the actual table descriptor from the ddb_handle */
+
+ table_info = (struct acpi_table_desc *) table_desc->reference.object;
+
+ /*
+ * Delete the entire namespace under this table Node
+ * (Offset contains the table_id)
+ */
+ acpi_ns_delete_namespace_by_owner (table_info->table_id);
+
+ /* Delete the table itself */
+
+ (void) acpi_tb_uninstall_table (table_info->installed_desc);
+
+ /* Delete the table descriptor (ddb_handle) */
+
+ acpi_ut_remove_reference (table_desc);
+ return_ACPI_STATUS (status);
+}
+
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
new file mode 100644
index 000000000000..df7ba1219bf6
--- /dev/null
+++ b/drivers/acpi/executer/exconvrt.c
@@ -0,0 +1,708 @@
+/******************************************************************************
+ *
+ * Module Name: exconvrt - Object conversion routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exconvrt")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_convert_to_integer
+ *
+ * PARAMETERS: obj_desc - Object to be converted. Must be an
+ * Integer, Buffer, or String
+ * result_desc - Where the new Integer object is returned
+ * Flags - Used for string conversion
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an ACPI Object to an integer.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_convert_to_integer (
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc,
+ u32 flags)
+{
+ union acpi_operand_object *return_desc;
+ u8 *pointer;
+ acpi_integer result;
+ u32 i;
+ u32 count;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_integer", obj_desc);
+
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_INTEGER:
+
+ /* No conversion necessary */
+
+ *result_desc = obj_desc;
+ return_ACPI_STATUS (AE_OK);
+
+ case ACPI_TYPE_BUFFER:
+ case ACPI_TYPE_STRING:
+
+ /* Note: Takes advantage of common buffer/string fields */
+
+ pointer = obj_desc->buffer.pointer;
+ count = obj_desc->buffer.length;
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_TYPE);
+ }
+
+ /*
+ * 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.
+ *
+ * There are two terminating conditions for the loop:
+ * 1) The size of an integer has been reached, or
+ * 2) The end of the buffer or string has been reached
+ */
+ result = 0;
+
+ /*
+ * String conversion is different than Buffer conversion
+ */
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_STRING:
+
+ /*
+ * Convert string to an integer - for most cases, the string must be
+ * hexadecimal as per the ACPI specification. The only exception (as
+ * of ACPI 3.0) is that the to_integer() operator allows both decimal
+ * and hexadecimal strings (hex prefixed with "0x").
+ */
+ status = acpi_ut_strtoul64 ((char *) pointer, flags, &result);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ /* Check for zero-length buffer */
+
+ if (!count) {
+ return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
+ }
+
+ /* Transfer no more than an integer's worth of data */
+
+ if (count > acpi_gbl_integer_byte_width) {
+ count = acpi_gbl_integer_byte_width;
+ }
+
+ /*
+ * Convert buffer to an integer - we simply grab enough raw data
+ * from the buffer to fill an integer
+ */
+ for (i = 0; i < count; i++) {
+ /*
+ * Get next byte and shift it into the Result.
+ * Little endian is used, meaning that the first byte of the buffer
+ * is the LSB of the integer
+ */
+ result |= (((acpi_integer) pointer[i]) << (i * 8));
+ }
+ break;
+
+
+ default:
+ /* No other types can get here */
+ break;
+ }
+
+ /*
+ * Create a new integer
+ */
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Save the Result */
+
+ return_desc->integer.value = result;
+ acpi_ex_truncate_for32bit_table (return_desc);
+ *result_desc = return_desc;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_convert_to_buffer
+ *
+ * PARAMETERS: obj_desc - Object to be converted. Must be an
+ * Integer, Buffer, or String
+ * result_desc - Where the new buffer object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an ACPI Object to a Buffer
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_convert_to_buffer (
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc)
+{
+ union acpi_operand_object *return_desc;
+ u8 *new_buf;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_buffer", obj_desc);
+
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_BUFFER:
+
+ /* No conversion necessary */
+
+ *result_desc = obj_desc;
+ return_ACPI_STATUS (AE_OK);
+
+
+ case ACPI_TYPE_INTEGER:
+
+ /*
+ * Create a new Buffer object.
+ * Need enough space for one integer
+ */
+ return_desc = acpi_ut_create_buffer_object (acpi_gbl_integer_byte_width);
+ if (!return_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Copy the integer to the buffer, LSB first */
+
+ new_buf = return_desc->buffer.pointer;
+ ACPI_MEMCPY (new_buf,
+ &obj_desc->integer.value,
+ acpi_gbl_integer_byte_width);
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ /*
+ * Create a new Buffer object
+ * Size will be the string length
+ *
+ * NOTE: Add one to the string length to include the null terminator.
+ * The ACPI spec is unclear on this subject, but there is existing
+ * ASL/AML code that depends on the null being transferred to the new
+ * buffer.
+ */
+ return_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length + 1);
+ if (!return_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Copy the string to the buffer */
+
+ new_buf = return_desc->buffer.pointer;
+ ACPI_STRNCPY ((char *) new_buf, (char *) obj_desc->string.pointer,
+ obj_desc->string.length);
+ break;
+
+
+ default:
+ return_ACPI_STATUS (AE_TYPE);
+ }
+
+ /* Mark buffer initialized */
+
+ return_desc->common.flags |= AOPOBJ_DATA_VALID;
+ *result_desc = return_desc;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_convert_to_ascii
+ *
+ * PARAMETERS: Integer - Value to be converted
+ * Base - ACPI_STRING_DECIMAL or ACPI_STRING_HEX
+ * String - Where the string is returned
+ * data_width - Size of data item to be converted, in bytes
+ *
+ * RETURN: Actual string length
+ *
+ * DESCRIPTION: Convert an ACPI Integer to a hex or decimal string
+ *
+ ******************************************************************************/
+
+u32
+acpi_ex_convert_to_ascii (
+ acpi_integer integer,
+ u16 base,
+ u8 *string,
+ u8 data_width)
+{
+ acpi_integer digit;
+ acpi_native_uint i;
+ acpi_native_uint j;
+ acpi_native_uint k = 0;
+ acpi_native_uint hex_length;
+ acpi_native_uint decimal_length;
+ u32 remainder;
+ u8 supress_zeros;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ switch (base) {
+ case 10:
+
+ /* Setup max length for the decimal number */
+
+ switch (data_width) {
+ case 1:
+ decimal_length = ACPI_MAX8_DECIMAL_DIGITS;
+ break;
+
+ case 4:
+ decimal_length = ACPI_MAX32_DECIMAL_DIGITS;
+ break;
+
+ case 8:
+ default:
+ decimal_length = ACPI_MAX64_DECIMAL_DIGITS;
+ break;
+ }
+
+ supress_zeros = TRUE; /* No leading zeros */
+ remainder = 0;
+
+ for (i = decimal_length; i > 0; i--) {
+ /* Divide by nth factor of 10 */
+
+ digit = integer;
+ for (j = 0; j < i; j++) {
+ (void) acpi_ut_short_divide (digit, 10, &digit, &remainder);
+ }
+
+ /* Handle leading zeros */
+
+ if (remainder != 0) {
+ supress_zeros = FALSE;
+ }
+
+ if (!supress_zeros) {
+ string[k] = (u8) (ACPI_ASCII_ZERO + remainder);
+ k++;
+ }
+ }
+ break;
+
+ case 16:
+
+ hex_length = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */
+
+ for (i = 0, j = (hex_length-1); i < hex_length; i++, j--) {
+ /* Get one hex digit, most significant digits first */
+
+ string[k] = (u8) acpi_ut_hex_to_ascii_char (integer, ACPI_MUL_4 (j));
+ k++;
+ }
+ break;
+
+ default:
+ return (0);
+ }
+
+ /*
+ * Since leading zeros are supressed, we must check for the case where
+ * the integer equals 0
+ *
+ * Finally, null terminate the string and return the length
+ */
+ if (!k) {
+ string [0] = ACPI_ASCII_ZERO;
+ k = 1;
+ }
+
+ string [k] = 0;
+ return ((u32) k);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_convert_to_string
+ *
+ * PARAMETERS: obj_desc - Object to be converted. Must be an
+ * Integer, Buffer, or String
+ * result_desc - Where the string object is returned
+ * Type - String flags (base and conversion type)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an ACPI Object to a string
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_convert_to_string (
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc,
+ u32 type)
+{
+ union acpi_operand_object *return_desc;
+ u8 *new_buf;
+ u32 i;
+ u32 string_length = 0;
+ u16 base = 16;
+ u8 separator = ',';
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_convert_to_string", obj_desc);
+
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_STRING:
+
+ /* No conversion necessary */
+
+ *result_desc = obj_desc;
+ return_ACPI_STATUS (AE_OK);
+
+
+ case ACPI_TYPE_INTEGER:
+
+ switch (type) {
+ case ACPI_EXPLICIT_CONVERT_DECIMAL:
+
+ /* Make room for maximum decimal number */
+
+ string_length = ACPI_MAX_DECIMAL_DIGITS;
+ base = 10;
+ break;
+
+ default:
+
+ /* Two hex string characters for each integer byte */
+
+ string_length = ACPI_MUL_2 (acpi_gbl_integer_byte_width);
+ break;
+ }
+
+ /*
+ * Create a new String
+ * Need enough space for one ASCII integer (plus null terminator)
+ */
+ return_desc = acpi_ut_create_string_object ((acpi_size) string_length);
+ if (!return_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ new_buf = return_desc->buffer.pointer;
+
+ /* Convert integer to string */
+
+ string_length = acpi_ex_convert_to_ascii (obj_desc->integer.value, base,
+ new_buf, acpi_gbl_integer_byte_width);
+
+ /* Null terminate at the correct place */
+
+ return_desc->string.length = string_length;
+ new_buf [string_length] = 0;
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ /* Setup string length, base, and separator */
+
+ switch (type) {
+ case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string operator */
+ /*
+ * From ACPI: "If Data is a buffer, it is converted to a string of
+ * decimal values separated by commas."
+ */
+ base = 10;
+
+ /*
+ * Calculate the final string length. Individual string values
+ * are variable length (include separator for each)
+ */
+ for (i = 0; i < obj_desc->buffer.length; i++) {
+ if (obj_desc->buffer.pointer[i] >= 100) {
+ string_length += 4;
+ }
+ else if (obj_desc->buffer.pointer[i] >= 10) {
+ string_length += 3;
+ }
+ else {
+ string_length += 2;
+ }
+ }
+ break;
+
+ case ACPI_IMPLICIT_CONVERT_HEX:
+ /*
+ * From the ACPI spec:
+ *"The entire contents of the buffer are converted to a string of
+ * two-character hexadecimal numbers, each separated by a space."
+ */
+ separator = ' ';
+ string_length = (obj_desc->buffer.length * 3);
+ break;
+
+ case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string operator */
+ /*
+ * From ACPI: "If Data is a buffer, it is converted to a string of
+ * hexadecimal values separated by commas."
+ */
+ string_length = (obj_desc->buffer.length * 3);
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Perform the conversion.
+ * (-1 because of extra separator included in string_length from above)
+ */
+ string_length--;
+ if (string_length > ACPI_MAX_STRING_CONVERSION) /* ACPI limit */ {
+ return_ACPI_STATUS (AE_AML_STRING_LIMIT);
+ }
+
+ /*
+ * Create a new string object and string buffer
+ */
+ return_desc = acpi_ut_create_string_object ((acpi_size) string_length);
+ if (!return_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ new_buf = return_desc->buffer.pointer;
+
+ /*
+ * Convert buffer bytes to hex or decimal values
+ * (separated by commas or spaces)
+ */
+ for (i = 0; i < obj_desc->buffer.length; i++) {
+ new_buf += acpi_ex_convert_to_ascii (
+ (acpi_integer) obj_desc->buffer.pointer[i], base,
+ new_buf, 1);
+ *new_buf++ = separator; /* each separated by a comma or space */
+ }
+
+ /* Null terminate the string (overwrites final comma/space from above) */
+
+ new_buf--;
+ *new_buf = 0;
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_TYPE);
+ }
+
+ *result_desc = return_desc;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_convert_to_target_type
+ *
+ * PARAMETERS: destination_type - Current type of the destination
+ * source_desc - Source object to be converted.
+ * result_desc - Where the converted object is returned
+ * walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implements "implicit conversion" rules for storing an object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_convert_to_target_type (
+ acpi_object_type destination_type,
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object **result_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_convert_to_target_type");
+
+
+ /* Default behavior */
+
+ *result_desc = source_desc;
+
+ /*
+ * If required by the target,
+ * perform implicit conversion on the source before we store it.
+ */
+ switch (GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)) {
+ case ARGI_SIMPLE_TARGET:
+ case ARGI_FIXED_TARGET:
+ case ARGI_INTEGER_REF: /* Handles Increment, Decrement cases */
+
+ switch (destination_type) {
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ /*
+ * Named field can always handle conversions
+ */
+ break;
+
+ default:
+ /* No conversion allowed for these types */
+
+ if (destination_type != ACPI_GET_OBJECT_TYPE (source_desc)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Explicit operator, will store (%s) over existing type (%s)\n",
+ acpi_ut_get_object_type_name (source_desc),
+ acpi_ut_get_type_name (destination_type)));
+ status = AE_TYPE;
+ }
+ }
+ break;
+
+
+ case ARGI_TARGETREF:
+
+ switch (destination_type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ /*
+ * These types require an Integer operand. We can convert
+ * a Buffer or a String to an Integer if necessary.
+ */
+ status = acpi_ex_convert_to_integer (source_desc, result_desc,
+ 16);
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ /*
+ * The operand must be a String. We can convert an
+ * Integer or Buffer if necessary
+ */
+ status = acpi_ex_convert_to_string (source_desc, result_desc,
+ ACPI_IMPLICIT_CONVERT_HEX);
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * The operand must be a Buffer. We can convert an
+ * Integer or String if necessary
+ */
+ status = acpi_ex_convert_to_buffer (source_desc, result_desc);
+ break;
+
+
+ default:
+ ACPI_REPORT_ERROR (("Bad destination type during conversion: %X\n",
+ destination_type));
+ status = AE_AML_INTERNAL;
+ break;
+ }
+ break;
+
+
+ case ARGI_REFERENCE:
+ /*
+ * create_xxxx_field cases - we are storing the field object into the name
+ */
+ break;
+
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown Target type ID 0x%X Op %s dest_type %s\n",
+ GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args),
+ walk_state->op_info->name, acpi_ut_get_type_name (destination_type)));
+
+ ACPI_REPORT_ERROR (("Bad Target Type (ARGI): %X\n",
+ GET_CURRENT_ARG_TYPE (walk_state->op_info->runtime_args)))
+ status = AE_AML_INTERNAL;
+ }
+
+ /*
+ * Source-to-Target conversion semantics:
+ *
+ * If conversion to the target type cannot be performed, then simply
+ * overwrite the target with the new object and type.
+ */
+ if (status == AE_TYPE) {
+ status = AE_OK;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
new file mode 100644
index 000000000000..d94c260dac6d
--- /dev/null
+++ b/drivers/acpi/executer/excreate.c
@@ -0,0 +1,646 @@
+/******************************************************************************
+ *
+ * Module Name: excreate - Named object creation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+#include <acpi/actables.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("excreate")
+
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_alias
+ *
+ * PARAMETERS: walk_state - Current state, contains operands
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new named alias
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_alias (
+ struct acpi_walk_state *walk_state)
+{
+ struct acpi_namespace_node *target_node;
+ struct acpi_namespace_node *alias_node;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_create_alias");
+
+
+ /* Get the source/alias operands (both namespace nodes) */
+
+ alias_node = (struct acpi_namespace_node *) walk_state->operands[0];
+ target_node = (struct acpi_namespace_node *) walk_state->operands[1];
+
+ if ((target_node->type == ACPI_TYPE_LOCAL_ALIAS) ||
+ (target_node->type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
+ /*
+ * Dereference an existing alias so that we don't create a chain
+ * of aliases. With this code, we guarantee that an alias is
+ * always exactly one level of indirection away from the
+ * actual aliased name.
+ */
+ target_node = ACPI_CAST_PTR (struct acpi_namespace_node, target_node->object);
+ }
+
+ /*
+ * For objects that can never change (i.e., the NS node will
+ * permanently point to the same object), we can simply attach
+ * the object to the new NS node. For other objects (such as
+ * Integers, buffers, etc.), we have to point the Alias node
+ * to the original Node.
+ */
+ switch (target_node->type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ case ACPI_TYPE_PACKAGE:
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ /*
+ * The new alias has the type ALIAS and points to the original
+ * NS node, not the object itself. This is because for these
+ * types, the object can change dynamically via a Store.
+ */
+ alias_node->type = ACPI_TYPE_LOCAL_ALIAS;
+ alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node);
+ break;
+
+ case ACPI_TYPE_METHOD:
+
+ /*
+ * The new alias has the type ALIAS and points to the original
+ * NS node, not the object itself. This is because for these
+ * types, the object can change dynamically via a Store.
+ */
+ alias_node->type = ACPI_TYPE_LOCAL_METHOD_ALIAS;
+ alias_node->object = ACPI_CAST_PTR (union acpi_operand_object, target_node);
+ break;
+
+ default:
+
+ /* Attach the original source object to the new Alias Node */
+
+ /*
+ * The new alias assumes the type of the target, and it points
+ * to the same object. The reference count of the object has an
+ * additional reference to prevent deletion out from under either the
+ * target node or the alias Node
+ */
+ status = acpi_ns_attach_object (alias_node,
+ acpi_ns_get_attached_object (target_node),
+ target_node->type);
+ break;
+ }
+
+ /* Since both operands are Nodes, we don't need to delete them */
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_event
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new event object
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_event (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE ("ex_create_event");
+
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_EVENT);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Create the actual OS semaphore, with zero initial units -- meaning
+ * that the event is created in an unsignalled state
+ */
+ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0,
+ &obj_desc->event.semaphore);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Attach object to the Node */
+
+ status = acpi_ns_attach_object ((struct acpi_namespace_node *) walk_state->operands[0],
+ obj_desc, ACPI_TYPE_EVENT);
+
+cleanup:
+ /*
+ * Remove local reference to the object (on error, will cause deletion
+ * of both object and semaphore if present.)
+ */
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_mutex
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new mutex object
+ *
+ * Mutex (Name[0], sync_level[1])
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_mutex (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_create_mutex", ACPI_WALK_OPERANDS);
+
+
+ /* Create the new mutex object */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_MUTEX);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Create the actual OS semaphore.
+ * One unit max to make it a mutex, with one initial unit to allow
+ * the mutex to be acquired.
+ */
+ status = acpi_os_create_semaphore (1, 1, &obj_desc->mutex.semaphore);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Init object and attach to NS node */
+
+ obj_desc->mutex.sync_level = (u8) walk_state->operands[1]->integer.value;
+ obj_desc->mutex.node = (struct acpi_namespace_node *) walk_state->operands[0];
+
+ status = acpi_ns_attach_object (obj_desc->mutex.node,
+ obj_desc, ACPI_TYPE_MUTEX);
+
+
+cleanup:
+ /*
+ * Remove local reference to the object (on error, will cause deletion
+ * of both object and semaphore if present.)
+ */
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_region
+ *
+ * PARAMETERS: aml_start - Pointer to the region declaration AML
+ * aml_length - Max length of the declaration AML
+ * Operands - List of operands for the opcode
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new operation region object
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_region (
+ u8 *aml_start,
+ u32 aml_length,
+ u8 region_space,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *region_obj2;
+
+
+ ACPI_FUNCTION_TRACE ("ex_create_region");
+
+
+ /* Get the Namespace Node */
+
+ node = walk_state->op->common.node;
+
+ /*
+ * If the region object is already attached to this node,
+ * just return
+ */
+ if (acpi_ns_get_attached_object (node)) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Space ID must be one of the predefined IDs, or in the user-defined
+ * range
+ */
+ if ((region_space >= ACPI_NUM_PREDEFINED_REGIONS) &&
+ (region_space < ACPI_USER_REGION_BEGIN)) {
+ ACPI_REPORT_ERROR (("Invalid address_space type %X\n", region_space));
+ return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (%X)\n",
+ acpi_ut_get_region_name (region_space), region_space));
+
+ /* Create the region descriptor */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Remember location in AML stream of address & length
+ * operands since they need to be evaluated at run time.
+ */
+ region_obj2 = obj_desc->common.next_object;
+ region_obj2->extra.aml_start = aml_start;
+ region_obj2->extra.aml_length = aml_length;
+
+ /* Init the region from the operands */
+
+ obj_desc->region.space_id = region_space;
+ obj_desc->region.address = 0;
+ obj_desc->region.length = 0;
+ obj_desc->region.node = node;
+
+ /* Install the new region object in the parent Node */
+
+ status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION);
+
+
+cleanup:
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_table_region
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new data_table_region object
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_table_region (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *obj_desc;
+ struct acpi_namespace_node *node;
+ struct acpi_table_header *table;
+ union acpi_operand_object *region_obj2;
+
+
+ ACPI_FUNCTION_TRACE ("ex_create_table_region");
+
+
+ /* Get the Node from the object stack */
+
+ node = walk_state->op->common.node;
+
+ /*
+ * If the region object is already attached to this node,
+ * just return
+ */
+ if (acpi_ns_get_attached_object (node)) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Find the ACPI table */
+
+ status = acpi_tb_find_table (operand[1]->string.pointer,
+ operand[2]->string.pointer,
+ operand[3]->string.pointer, &table);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Create the region descriptor */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_REGION);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ region_obj2 = obj_desc->common.next_object;
+ region_obj2->extra.region_context = NULL;
+
+ /* Init the region from the operands */
+
+ obj_desc->region.space_id = REGION_DATA_TABLE;
+ obj_desc->region.address = (acpi_physical_address) ACPI_TO_INTEGER (table);
+ obj_desc->region.length = table->length;
+ obj_desc->region.node = node;
+ obj_desc->region.flags = AOPOBJ_DATA_VALID;
+
+ /* Install the new region object in the parent Node */
+
+ status = acpi_ns_attach_object (node, obj_desc, ACPI_TYPE_REGION);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_ev_initialize_region (obj_desc, FALSE);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_NOT_EXIST) {
+ status = AE_OK;
+ }
+ else {
+ goto cleanup;
+ }
+ }
+
+ obj_desc->region.flags |= AOPOBJ_SETUP_COMPLETE;
+
+
+cleanup:
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_processor
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new processor object and populate the fields
+ *
+ * Processor (Name[0], cpu_iD[1], pblock_addr[2], pblock_length[3])
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_processor (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_create_processor", walk_state);
+
+
+ /* Create the processor object */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_PROCESSOR);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Initialize the processor object from the operands
+ */
+ obj_desc->processor.proc_id = (u8) operand[1]->integer.value;
+ obj_desc->processor.address = (acpi_io_address) operand[2]->integer.value;
+ obj_desc->processor.length = (u8) operand[3]->integer.value;
+
+ /* Install the processor object in the parent Node */
+
+ status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0],
+ obj_desc, ACPI_TYPE_PROCESSOR);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_power_resource
+ *
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new power_resource object and populate the fields
+ *
+ * power_resource (Name[0], system_level[1], resource_order[2])
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_power_resource (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_create_power_resource", walk_state);
+
+
+ /* Create the power resource object */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_POWER);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Initialize the power object from the operands */
+
+ obj_desc->power_resource.system_level = (u8) operand[1]->integer.value;
+ obj_desc->power_resource.resource_order = (u16) operand[2]->integer.value;
+
+ /* Install the power resource object in the parent Node */
+
+ status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0],
+ obj_desc, ACPI_TYPE_POWER);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+#endif
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_create_method
+ *
+ * PARAMETERS: aml_start - First byte of the method's AML
+ * aml_length - AML byte count for this method
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a new method object
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_ex_create_method (
+ u8 *aml_start,
+ u32 aml_length,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+ u8 method_flags;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_create_method", walk_state);
+
+
+ /* Create a new method object */
+
+ obj_desc = acpi_ut_create_internal_object (ACPI_TYPE_METHOD);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Save the method's AML pointer and length */
+
+ obj_desc->method.aml_start = aml_start;
+ obj_desc->method.aml_length = aml_length;
+
+ /*
+ * Disassemble the method flags. Split off the Arg Count
+ * for efficiency
+ */
+ method_flags = (u8) operand[1]->integer.value;
+
+ obj_desc->method.method_flags = (u8) (method_flags & ~AML_METHOD_ARG_COUNT);
+ obj_desc->method.param_count = (u8) (method_flags & AML_METHOD_ARG_COUNT);
+
+ /*
+ * Get the concurrency count. If required, a semaphore will be
+ * created for this method when it is parsed.
+ */
+ if (acpi_gbl_all_methods_serialized) {
+ obj_desc->method.concurrency = 1;
+ obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
+ }
+ else if (method_flags & AML_METHOD_SERIALIZED) {
+ /*
+ * ACPI 1.0: Concurrency = 1
+ * ACPI 2.0: Concurrency = (sync_level (in method declaration) + 1)
+ */
+ obj_desc->method.concurrency = (u8)
+ (((method_flags & AML_METHOD_SYNCH_LEVEL) >> 4) + 1);
+ }
+ else {
+ obj_desc->method.concurrency = ACPI_INFINITE_CONCURRENCY;
+ }
+
+ /* Attach the new object to the method Node */
+
+ status = acpi_ns_attach_object ((struct acpi_namespace_node *) operand[0],
+ obj_desc, ACPI_TYPE_METHOD);
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+
+ /* Remove a reference to the operand */
+
+ acpi_ut_remove_reference (operand[1]);
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
new file mode 100644
index 000000000000..e2f7c32f28de
--- /dev/null
+++ b/drivers/acpi/executer/exdump.c
@@ -0,0 +1,793 @@
+/******************************************************************************
+ *
+ * Module Name: exdump - Interpreter debug output routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exdump")
+
+
+/*
+ * The following routines are used for debug output only
+ */
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_dump_operand
+ *
+ * PARAMETERS: *obj_desc - Pointer to entry to be dumped
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Dump an operand object
+ *
+ ****************************************************************************/
+
+void
+acpi_ex_dump_operand (
+ union acpi_operand_object *obj_desc,
+ u32 depth)
+{
+ u32 length;
+ u32 index;
+
+
+ ACPI_FUNCTION_NAME ("ex_dump_operand")
+
+
+ if (!((ACPI_LV_EXEC & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
+ return;
+ }
+
+ if (!obj_desc) {
+ /*
+ * This could be a null element of a package
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n"));
+ return;
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p is a NS Node: ", obj_desc));
+ ACPI_DUMP_ENTRY (obj_desc, ACPI_LV_EXEC);
+ return;
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "%p is not a node or operand object: [%s]\n",
+ obj_desc, acpi_ut_get_descriptor_name (obj_desc)));
+ ACPI_DUMP_BUFFER (obj_desc, sizeof (union acpi_operand_object));
+ return;
+ }
+
+ /* obj_desc is a valid object */
+
+ if (depth > 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%*s[%u] %p ",
+ depth, " ", depth, obj_desc));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc));
+ }
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ switch (obj_desc->reference.opcode) {
+ case AML_DEBUG_OP:
+
+ acpi_os_printf ("Reference: Debug\n");
+ break;
+
+
+ case AML_NAME_OP:
+
+ ACPI_DUMP_PATHNAME (obj_desc->reference.object,
+ "Reference: Name: ", ACPI_LV_INFO, _COMPONENT);
+ ACPI_DUMP_ENTRY (obj_desc->reference.object, ACPI_LV_INFO);
+ break;
+
+
+ case AML_INDEX_OP:
+
+ acpi_os_printf ("Reference: Index %p\n",
+ obj_desc->reference.object);
+ break;
+
+
+ case AML_REF_OF_OP:
+
+ acpi_os_printf ("Reference: (ref_of) %p\n",
+ obj_desc->reference.object);
+ break;
+
+
+ case AML_ARG_OP:
+
+ acpi_os_printf ("Reference: Arg%d",
+ obj_desc->reference.offset);
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ /* Value is an Integer */
+
+ acpi_os_printf (" value is [%8.8X%8.8x]",
+ ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+ }
+
+ acpi_os_printf ("\n");
+ break;
+
+
+ case AML_LOCAL_OP:
+
+ acpi_os_printf ("Reference: Local%d",
+ obj_desc->reference.offset);
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+
+ /* Value is an Integer */
+
+ acpi_os_printf (" value is [%8.8X%8.8x]",
+ ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+ }
+
+ acpi_os_printf ("\n");
+ break;
+
+
+ case AML_INT_NAMEPATH_OP:
+
+ acpi_os_printf ("Reference.Node->Name %X\n",
+ obj_desc->reference.node->name.integer);
+ break;
+
+
+ default:
+
+ /* Unknown opcode */
+
+ acpi_os_printf ("Unknown Reference opcode=%X\n",
+ obj_desc->reference.opcode);
+ break;
+
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ acpi_os_printf ("Buffer len %X @ %p \n",
+ obj_desc->buffer.length, obj_desc->buffer.pointer);
+
+ length = obj_desc->buffer.length;
+ if (length > 64) {
+ length = 64;
+ }
+
+ /* Debug only -- dump the buffer contents */
+
+ if (obj_desc->buffer.pointer) {
+ acpi_os_printf ("Buffer Contents: ");
+
+ for (index = 0; index < length; index++) {
+ acpi_os_printf (" %02x", obj_desc->buffer.pointer[index]);
+ }
+ acpi_os_printf ("\n");
+ }
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+
+ acpi_os_printf ("Integer %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ acpi_os_printf ("Package [Len %X] element_array %p\n",
+ obj_desc->package.count, obj_desc->package.elements);
+
+ /*
+ * If elements exist, package element pointer is valid,
+ * and debug_level exceeds 1, dump package's elements.
+ */
+ if (obj_desc->package.count &&
+ obj_desc->package.elements &&
+ acpi_dbg_level > 1) {
+ for (index = 0; index < obj_desc->package.count; index++) {
+ acpi_ex_dump_operand (obj_desc->package.elements[index], depth+1);
+ }
+ }
+ break;
+
+
+ case ACPI_TYPE_REGION:
+
+ acpi_os_printf ("Region %s (%X)",
+ acpi_ut_get_region_name (obj_desc->region.space_id),
+ obj_desc->region.space_id);
+
+ /*
+ * If the address and length have not been evaluated,
+ * don't print them.
+ */
+ if (!(obj_desc->region.flags & AOPOBJ_DATA_VALID)) {
+ acpi_os_printf ("\n");
+ }
+ else {
+ acpi_os_printf (" base %8.8X%8.8X Length %X\n",
+ ACPI_FORMAT_UINT64 (obj_desc->region.address),
+ obj_desc->region.length);
+ }
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ acpi_os_printf ("String length %X @ %p ",
+ obj_desc->string.length, obj_desc->string.pointer);
+ acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX);
+ acpi_os_printf ("\n");
+ break;
+
+
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ acpi_os_printf ("bank_field\n");
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+ acpi_os_printf (
+ "region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n",
+ obj_desc->field.bit_length, obj_desc->field.access_byte_width,
+ obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK,
+ obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK,
+ obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset);
+ acpi_ex_dump_operand (obj_desc->field.region_obj, depth+1);
+ break;
+
+
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ acpi_os_printf ("index_field\n");
+ break;
+
+
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ acpi_os_printf (
+ "buffer_field: %X bits at byte %X bit %X of \n",
+ obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset,
+ obj_desc->buffer_field.start_field_bit_offset);
+
+ if (!obj_desc->buffer_field.buffer_obj) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n"));
+ }
+ else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != ACPI_TYPE_BUFFER) {
+ acpi_os_printf ("*not a Buffer* \n");
+ }
+ else {
+ acpi_ex_dump_operand (obj_desc->buffer_field.buffer_obj, depth+1);
+ }
+ break;
+
+
+ case ACPI_TYPE_EVENT:
+
+ acpi_os_printf ("Event\n");
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ acpi_os_printf (
+ "Method(%X) @ %p:%X\n",
+ obj_desc->method.param_count,
+ obj_desc->method.aml_start, obj_desc->method.aml_length);
+ break;
+
+
+ case ACPI_TYPE_MUTEX:
+
+ acpi_os_printf ("Mutex\n");
+ break;
+
+
+ case ACPI_TYPE_DEVICE:
+
+ acpi_os_printf ("Device\n");
+ break;
+
+
+ case ACPI_TYPE_POWER:
+
+ acpi_os_printf ("Power\n");
+ break;
+
+
+ case ACPI_TYPE_PROCESSOR:
+
+ acpi_os_printf ("Processor\n");
+ break;
+
+
+ case ACPI_TYPE_THERMAL:
+
+ acpi_os_printf ("Thermal\n");
+ break;
+
+
+ default:
+ /* Unknown Type */
+
+ acpi_os_printf ("Unknown Type %X\n", ACPI_GET_OBJECT_TYPE (obj_desc));
+ break;
+ }
+
+ return;
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_dump_operands
+ *
+ * PARAMETERS: Operands - Operand list
+ * interpreter_mode - Load or Exec
+ * Ident - Identification
+ * num_levels - # of stack entries to dump above line
+ * Note - Output notation
+ * module_name - Caller's module name
+ * line_number - Caller's invocation line number
+ *
+ * DESCRIPTION: Dump the object stack
+ *
+ ****************************************************************************/
+
+void
+acpi_ex_dump_operands (
+ union acpi_operand_object **operands,
+ acpi_interpreter_mode interpreter_mode,
+ char *ident,
+ u32 num_levels,
+ char *note,
+ char *module_name,
+ u32 line_number)
+{
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_NAME ("ex_dump_operands");
+
+
+ if (!ident) {
+ ident = "?";
+ }
+
+ if (!note) {
+ note = "?";
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "************* Operand Stack Contents (Opcode [%s], %d Operands)\n",
+ ident, num_levels));
+
+ if (num_levels == 0) {
+ num_levels = 1;
+ }
+
+ /* Dump the operand stack starting at the top */
+
+ for (i = 0; num_levels > 0; i--, num_levels--) {
+ acpi_ex_dump_operand (operands[i], 0);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "************* Stack dump from %s(%d), %s\n",
+ module_name, line_number, note));
+ return;
+}
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_out*
+ *
+ * PARAMETERS: Title - Descriptive text
+ * Value - Value to be displayed
+ *
+ * DESCRIPTION: Object dump output formatting functions. These functions
+ * reduce the number of format strings required and keeps them
+ * all in one place for easy modification.
+ *
+ ****************************************************************************/
+
+void
+acpi_ex_out_string (
+ char *title,
+ char *value)
+{
+ acpi_os_printf ("%20s : %s\n", title, value);
+}
+
+void
+acpi_ex_out_pointer (
+ char *title,
+ void *value)
+{
+ acpi_os_printf ("%20s : %p\n", title, value);
+}
+
+void
+acpi_ex_out_integer (
+ char *title,
+ u32 value)
+{
+ acpi_os_printf ("%20s : %X\n", title, value);
+}
+
+void
+acpi_ex_out_address (
+ char *title,
+ acpi_physical_address value)
+{
+
+#if ACPI_MACHINE_WIDTH == 16
+ acpi_os_printf ("%20s : %p\n", title, value);
+#else
+ acpi_os_printf ("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64 (value));
+#endif
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_dump_node
+ *
+ * PARAMETERS: *Node - Descriptor to dump
+ * Flags - Force display
+ *
+ * DESCRIPTION: Dumps the members of the given.Node
+ *
+ ****************************************************************************/
+
+void
+acpi_ex_dump_node (
+ struct acpi_namespace_node *node,
+ u32 flags)
+{
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (!flags) {
+ if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
+ return;
+ }
+ }
+
+ acpi_os_printf ("%20s : %4.4s\n", "Name", acpi_ut_get_node_name (node));
+ acpi_ex_out_string ("Type", acpi_ut_get_type_name (node->type));
+ acpi_ex_out_integer ("Flags", node->flags);
+ acpi_ex_out_integer ("Owner Id", node->owner_id);
+ acpi_ex_out_integer ("Reference Count", node->reference_count);
+ acpi_ex_out_pointer ("Attached Object", acpi_ns_get_attached_object (node));
+ acpi_ex_out_pointer ("child_list", node->child);
+ acpi_ex_out_pointer ("next_peer", node->peer);
+ acpi_ex_out_pointer ("Parent", acpi_ns_get_parent_node (node));
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ex_dump_object_descriptor
+ *
+ * PARAMETERS: *Object - Descriptor to dump
+ * Flags - Force display
+ *
+ * DESCRIPTION: Dumps the members of the object descriptor given.
+ *
+ ****************************************************************************/
+
+void
+acpi_ex_dump_object_descriptor (
+ union acpi_operand_object *obj_desc,
+ u32 flags)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ex_dump_object_descriptor");
+
+
+ if (!flags) {
+ if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
+ return_VOID;
+ }
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) {
+ acpi_ex_dump_node ((struct acpi_namespace_node *) obj_desc, flags);
+ acpi_os_printf ("\nAttached Object (%p):\n",
+ ((struct acpi_namespace_node *) obj_desc)->object);
+ acpi_ex_dump_object_descriptor (
+ ((struct acpi_namespace_node *) obj_desc)->object, flags);
+ return_VOID;
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+ acpi_os_printf (
+ "ex_dump_object_descriptor: %p is not an ACPI operand object: [%s]\n",
+ obj_desc, acpi_ut_get_descriptor_name (obj_desc));
+ return_VOID;
+ }
+
+ /* Common Fields */
+
+ acpi_ex_out_string ("Type", acpi_ut_get_object_type_name (obj_desc));
+ acpi_ex_out_integer ("Reference Count", obj_desc->common.reference_count);
+ acpi_ex_out_integer ("Flags", obj_desc->common.flags);
+
+ /* Object-specific Fields */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_INTEGER:
+
+ acpi_os_printf ("%20s : %8.8X%8.8X\n", "Value",
+ ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ acpi_ex_out_integer ("Length", obj_desc->string.length);
+
+ acpi_os_printf ("%20s : %p ", "Pointer", obj_desc->string.pointer);
+ acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX);
+ acpi_os_printf ("\n");
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ acpi_ex_out_integer ("Length", obj_desc->buffer.length);
+ acpi_ex_out_pointer ("Pointer", obj_desc->buffer.pointer);
+ ACPI_DUMP_BUFFER (obj_desc->buffer.pointer, obj_desc->buffer.length);
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ acpi_ex_out_integer ("Flags", obj_desc->package.flags);
+ acpi_ex_out_integer ("Count", obj_desc->package.count);
+ acpi_ex_out_pointer ("Elements", obj_desc->package.elements);
+
+ /* Dump the package contents */
+
+ if (obj_desc->package.count > 0) {
+ acpi_os_printf ("\nPackage Contents:\n");
+ for (i = 0; i < obj_desc->package.count; i++) {
+ acpi_os_printf ("[%.3d] %p", i, obj_desc->package.elements[i]);
+ if (obj_desc->package.elements[i]) {
+ acpi_os_printf (" %s",
+ acpi_ut_get_object_type_name (obj_desc->package.elements[i]));
+ }
+ acpi_os_printf ("\n");
+ }
+ }
+ break;
+
+
+ case ACPI_TYPE_DEVICE:
+
+ acpi_ex_out_pointer ("Handler", obj_desc->device.handler);
+ acpi_ex_out_pointer ("system_notify", obj_desc->device.system_notify);
+ acpi_ex_out_pointer ("device_notify", obj_desc->device.device_notify);
+ break;
+
+
+ case ACPI_TYPE_EVENT:
+
+ acpi_ex_out_pointer ("Semaphore", obj_desc->event.semaphore);
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ acpi_ex_out_integer ("param_count", obj_desc->method.param_count);
+ acpi_ex_out_integer ("Concurrency", obj_desc->method.concurrency);
+ acpi_ex_out_pointer ("Semaphore", obj_desc->method.semaphore);
+ acpi_ex_out_integer ("owning_id", obj_desc->method.owning_id);
+ acpi_ex_out_integer ("aml_length", obj_desc->method.aml_length);
+ acpi_ex_out_pointer ("aml_start", obj_desc->method.aml_start);
+ break;
+
+
+ case ACPI_TYPE_MUTEX:
+
+ acpi_ex_out_integer ("sync_level", obj_desc->mutex.sync_level);
+ acpi_ex_out_pointer ("owner_thread", obj_desc->mutex.owner_thread);
+ acpi_ex_out_integer ("acquire_depth", obj_desc->mutex.acquisition_depth);
+ acpi_ex_out_pointer ("Semaphore", obj_desc->mutex.semaphore);
+ break;
+
+
+ case ACPI_TYPE_REGION:
+
+ acpi_ex_out_integer ("space_id", obj_desc->region.space_id);
+ acpi_ex_out_integer ("Flags", obj_desc->region.flags);
+ acpi_ex_out_address ("Address", obj_desc->region.address);
+ acpi_ex_out_integer ("Length", obj_desc->region.length);
+ acpi_ex_out_pointer ("Handler", obj_desc->region.handler);
+ acpi_ex_out_pointer ("Next", obj_desc->region.next);
+ break;
+
+
+ case ACPI_TYPE_POWER:
+
+ acpi_ex_out_integer ("system_level", obj_desc->power_resource.system_level);
+ acpi_ex_out_integer ("resource_order", obj_desc->power_resource.resource_order);
+ acpi_ex_out_pointer ("system_notify", obj_desc->power_resource.system_notify);
+ acpi_ex_out_pointer ("device_notify", obj_desc->power_resource.device_notify);
+ break;
+
+
+ case ACPI_TYPE_PROCESSOR:
+
+ acpi_ex_out_integer ("Processor ID", obj_desc->processor.proc_id);
+ acpi_ex_out_integer ("Length", obj_desc->processor.length);
+ acpi_ex_out_address ("Address", (acpi_physical_address) obj_desc->processor.address);
+ acpi_ex_out_pointer ("system_notify", obj_desc->processor.system_notify);
+ acpi_ex_out_pointer ("device_notify", obj_desc->processor.device_notify);
+ acpi_ex_out_pointer ("Handler", obj_desc->processor.handler);
+ break;
+
+
+ case ACPI_TYPE_THERMAL:
+
+ acpi_ex_out_pointer ("system_notify", obj_desc->thermal_zone.system_notify);
+ acpi_ex_out_pointer ("device_notify", obj_desc->thermal_zone.device_notify);
+ acpi_ex_out_pointer ("Handler", obj_desc->thermal_zone.handler);
+ break;
+
+
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ acpi_ex_out_integer ("field_flags", obj_desc->common_field.field_flags);
+ acpi_ex_out_integer ("access_byte_width",obj_desc->common_field.access_byte_width);
+ acpi_ex_out_integer ("bit_length", obj_desc->common_field.bit_length);
+ acpi_ex_out_integer ("fld_bit_offset", obj_desc->common_field.start_field_bit_offset);
+ acpi_ex_out_integer ("base_byte_offset", obj_desc->common_field.base_byte_offset);
+ acpi_ex_out_pointer ("parent_node", obj_desc->common_field.node);
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_BUFFER_FIELD:
+ acpi_ex_out_pointer ("buffer_obj", obj_desc->buffer_field.buffer_obj);
+ break;
+
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ acpi_ex_out_pointer ("region_obj", obj_desc->field.region_obj);
+ break;
+
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ acpi_ex_out_integer ("Value", obj_desc->bank_field.value);
+ acpi_ex_out_pointer ("region_obj", obj_desc->bank_field.region_obj);
+ acpi_ex_out_pointer ("bank_obj", obj_desc->bank_field.bank_obj);
+ break;
+
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ acpi_ex_out_integer ("Value", obj_desc->index_field.value);
+ acpi_ex_out_pointer ("Index", obj_desc->index_field.index_obj);
+ acpi_ex_out_pointer ("Data", obj_desc->index_field.data_obj);
+ break;
+
+ default:
+ /* All object types covered above */
+ break;
+ }
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ acpi_ex_out_integer ("target_type", obj_desc->reference.target_type);
+ acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name);
+ acpi_ex_out_integer ("Offset", obj_desc->reference.offset);
+ acpi_ex_out_pointer ("obj_desc", obj_desc->reference.object);
+ acpi_ex_out_pointer ("Node", obj_desc->reference.node);
+ acpi_ex_out_pointer ("Where", obj_desc->reference.where);
+ break;
+
+
+ case ACPI_TYPE_LOCAL_ADDRESS_HANDLER:
+
+ acpi_ex_out_integer ("space_id", obj_desc->address_space.space_id);
+ acpi_ex_out_pointer ("Next", obj_desc->address_space.next);
+ acpi_ex_out_pointer ("region_list", obj_desc->address_space.region_list);
+ acpi_ex_out_pointer ("Node", obj_desc->address_space.node);
+ acpi_ex_out_pointer ("Context", obj_desc->address_space.context);
+ break;
+
+
+ case ACPI_TYPE_LOCAL_NOTIFY:
+
+ acpi_ex_out_pointer ("Node", obj_desc->notify.node);
+ acpi_ex_out_pointer ("Context", obj_desc->notify.context);
+ break;
+
+
+ case ACPI_TYPE_LOCAL_ALIAS:
+ case ACPI_TYPE_LOCAL_METHOD_ALIAS:
+ case ACPI_TYPE_LOCAL_EXTRA:
+ case ACPI_TYPE_LOCAL_DATA:
+ default:
+
+ acpi_os_printf (
+ "ex_dump_object_descriptor: Display not implemented for object type %s\n",
+ acpi_ut_get_object_type_name (obj_desc));
+ break;
+ }
+
+ return_VOID;
+}
+
+#endif /* ACPI_FUTURE_USAGE */
+
+#endif
+
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
new file mode 100644
index 000000000000..be7f2124fa02
--- /dev/null
+++ b/drivers/acpi/executer/exfield.c
@@ -0,0 +1,367 @@
+/******************************************************************************
+ *
+ * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+#include <acpi/acinterp.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exfield")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_read_data_from_field
+ *
+ * PARAMETERS: walk_state - Current execution state
+ * obj_desc - The named field
+ * ret_buffer_desc - Where the return data object is stored
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read from a named field. Returns either an Integer or a
+ * Buffer, depending on the size of the field.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_read_data_from_field (
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **ret_buffer_desc)
+{
+ acpi_status status;
+ union acpi_operand_object *buffer_desc;
+ acpi_size length;
+ void *buffer;
+ u8 locked;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_read_data_from_field", obj_desc);
+
+
+ /* Parameter validation */
+
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) {
+ /*
+ * If the buffer_field arguments have not been previously evaluated,
+ * evaluate them now and save the results.
+ */
+ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
+ status = acpi_ds_get_buffer_field_arguments (obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ }
+ else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) &&
+ (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) {
+ /*
+ * This is an SMBus read. We must create a buffer to hold the data
+ * and directly access the region handler.
+ */
+ buffer_desc = acpi_ut_create_buffer_object (ACPI_SMBUS_BUFFER_SIZE);
+ if (!buffer_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Lock entire transaction if requested */
+
+ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags);
+
+ /*
+ * Perform the read.
+ * Note: Smbus protocol value is passed in upper 16-bits of Function
+ */
+ status = acpi_ex_access_region (obj_desc, 0,
+ ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer),
+ ACPI_READ | (obj_desc->field.attribute << 16));
+ acpi_ex_release_global_lock (locked);
+ goto exit;
+ }
+
+ /*
+ * Allocate a buffer for the contents of the field.
+ *
+ * If the field is larger than the size of an acpi_integer, create
+ * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
+ * the use of arithmetic operators on the returned value if the
+ * field size is equal or smaller than an Integer.
+ *
+ * Note: Field.length is in bits.
+ */
+ length = (acpi_size) ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->field.bit_length);
+ if (length > acpi_gbl_integer_byte_width) {
+ /* Field is too large for an Integer, create a Buffer instead */
+
+ buffer_desc = acpi_ut_create_buffer_object (length);
+ if (!buffer_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+ buffer = buffer_desc->buffer.pointer;
+ }
+ else {
+ /* Field will fit within an Integer (normal case) */
+
+ buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!buffer_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ length = acpi_gbl_integer_byte_width;
+ buffer_desc->integer.value = 0;
+ buffer = &buffer_desc->integer.value;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "field_read [TO]: Obj %p, Type %X, Buf %p, byte_len %X\n",
+ obj_desc, ACPI_GET_OBJECT_TYPE (obj_desc), buffer, (u32) length));
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "field_read [FROM]: bit_len %X, bit_off %X, byte_off %X\n",
+ obj_desc->common_field.bit_length,
+ obj_desc->common_field.start_field_bit_offset,
+ obj_desc->common_field.base_byte_offset));
+
+ /* Lock entire transaction if requested */
+
+ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags);
+
+ /* Read from the field */
+
+ status = acpi_ex_extract_from_field (obj_desc, buffer, (u32) length);
+ acpi_ex_release_global_lock (locked);
+
+
+exit:
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (buffer_desc);
+ }
+ else if (ret_buffer_desc) {
+ *ret_buffer_desc = buffer_desc;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_write_data_to_field
+ *
+ * PARAMETERS: source_desc - Contains data to write
+ * obj_desc - The named field
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write to a named field
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_write_data_to_field (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **result_desc)
+{
+ acpi_status status;
+ u32 length;
+ u32 required_length;
+ void *buffer;
+ void *new_buffer;
+ u8 locked;
+ union acpi_operand_object *buffer_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_write_data_to_field", obj_desc);
+
+
+ /* Parameter validation */
+
+ if (!source_desc || !obj_desc) {
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) {
+ /*
+ * If the buffer_field arguments have not been previously evaluated,
+ * evaluate them now and save the results.
+ */
+ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
+ status = acpi_ds_get_buffer_field_arguments (obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ }
+ else if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REGION_FIELD) &&
+ (obj_desc->field.region_obj->region.space_id == ACPI_ADR_SPACE_SMBUS)) {
+ /*
+ * This is an SMBus write. We will bypass the entire field mechanism
+ * and handoff the buffer directly to the handler.
+ *
+ * Source must be a buffer of sufficient size (ACPI_SMBUS_BUFFER_SIZE).
+ */
+ if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) {
+ ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n",
+ acpi_ut_get_object_type_name (source_desc)));
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) {
+ ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n",
+ ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length));
+ return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
+ }
+
+ buffer_desc = acpi_ut_create_buffer_object (ACPI_SMBUS_BUFFER_SIZE);
+ if (!buffer_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ buffer = buffer_desc->buffer.pointer;
+ ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE);
+
+ /* Lock entire transaction if requested */
+
+ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags);
+
+ /*
+ * Perform the write (returns status and perhaps data in the same buffer)
+ * Note: SMBus protocol type is passed in upper 16-bits of Function.
+ */
+ status = acpi_ex_access_region (obj_desc, 0,
+ (acpi_integer *) buffer,
+ ACPI_WRITE | (obj_desc->field.attribute << 16));
+ acpi_ex_release_global_lock (locked);
+
+ *result_desc = buffer_desc;
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Get a pointer to the data to be written
+ */
+ switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
+ case ACPI_TYPE_INTEGER:
+ buffer = &source_desc->integer.value;
+ length = sizeof (source_desc->integer.value);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ buffer = source_desc->buffer.pointer;
+ length = source_desc->buffer.length;
+ break;
+
+ case ACPI_TYPE_STRING:
+ buffer = source_desc->string.pointer;
+ length = source_desc->string.length;
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * We must have a buffer that is at least as long as the field
+ * we are writing to. This is because individual fields are
+ * indivisible and partial writes are not supported -- as per
+ * the ACPI specification.
+ */
+ new_buffer = NULL;
+ required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
+
+ if (length < required_length) {
+ /* We need to create a new buffer */
+
+ new_buffer = ACPI_MEM_CALLOCATE (required_length);
+ if (!new_buffer) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the original data to the new buffer, starting
+ * at Byte zero. All unused (upper) bytes of the
+ * buffer will be 0.
+ */
+ ACPI_MEMCPY ((char *) new_buffer, (char *) buffer, length);
+ buffer = new_buffer;
+ length = required_length;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n",
+ source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)),
+ ACPI_GET_OBJECT_TYPE (source_desc), buffer, length));
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n",
+ obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)),
+ ACPI_GET_OBJECT_TYPE (obj_desc),
+ obj_desc->common_field.bit_length,
+ obj_desc->common_field.start_field_bit_offset,
+ obj_desc->common_field.base_byte_offset));
+
+ /* Lock entire transaction if requested */
+
+ locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags);
+
+ /* Write to the field */
+
+ status = acpi_ex_insert_into_field (obj_desc, buffer, length);
+ acpi_ex_release_global_lock (locked);
+
+ /* Free temporary buffer if we used one */
+
+ if (new_buffer) {
+ ACPI_MEM_FREE (new_buffer);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
new file mode 100644
index 000000000000..9d0f9d2e9061
--- /dev/null
+++ b/drivers/acpi/executer/exfldio.c
@@ -0,0 +1,835 @@
+/******************************************************************************
+ *
+ * Module Name: exfldio - Aml Field I/O
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acevents.h>
+#include <acpi/acdispat.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exfldio")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_setup_region
+ *
+ * PARAMETERS: *obj_desc - Field to be read or written
+ * field_datum_byte_offset - Byte offset of this datum within the
+ * parent field
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Common processing for acpi_ex_extract_from_field and
+ * acpi_ex_insert_into_field. Initialize the Region if necessary and
+ * validate the request.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_setup_region (
+ union acpi_operand_object *obj_desc,
+ u32 field_datum_byte_offset)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *rgn_desc;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ex_setup_region", field_datum_byte_offset);
+
+
+ rgn_desc = obj_desc->common_field.region_obj;
+
+ /* We must have a valid region */
+
+ if (ACPI_GET_OBJECT_TYPE (rgn_desc) != ACPI_TYPE_REGION) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n",
+ ACPI_GET_OBJECT_TYPE (rgn_desc),
+ acpi_ut_get_object_type_name (rgn_desc)));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * If the Region Address and Length have not been previously evaluated,
+ * evaluate them now and save the results.
+ */
+ if (!(rgn_desc->common.flags & AOPOBJ_DATA_VALID)) {
+ status = acpi_ds_get_region_arguments (rgn_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ if (rgn_desc->region.space_id == ACPI_ADR_SPACE_SMBUS) {
+ /* SMBus has a non-linear address space */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+#ifdef ACPI_UNDER_DEVELOPMENT
+ /*
+ * If the Field access is any_acc, we can now compute the optimal
+ * access (because we know know the length of the parent region)
+ */
+ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+#endif
+
+ /*
+ * Validate the request. The entire request from the byte offset for a
+ * length of one field datum (access width) must fit within the region.
+ * (Region length is specified in bytes)
+ */
+ if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset
+ + field_datum_byte_offset
+ + obj_desc->common_field.access_byte_width)) {
+ if (acpi_gbl_enable_interpreter_slack) {
+ /*
+ * Slack mode only: We will go ahead and allow access to this
+ * field if it is within the region length rounded up to the next
+ * access width boundary.
+ */
+ if (ACPI_ROUND_UP (rgn_desc->region.length,
+ obj_desc->common_field.access_byte_width) >=
+ (obj_desc->common_field.base_byte_offset +
+ (acpi_native_uint) obj_desc->common_field.access_byte_width +
+ field_datum_byte_offset)) {
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ if (rgn_desc->region.length < obj_desc->common_field.access_byte_width) {
+ /*
+ * This is the case where the access_type (acc_word, etc.) is wider
+ * than the region itself. For example, a region of length one
+ * byte, and a field with Dword access specified.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
+ acpi_ut_get_node_name (obj_desc->common_field.node),
+ obj_desc->common_field.access_byte_width,
+ acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length));
+ }
+
+ /*
+ * Offset rounded up to next multiple of field width
+ * exceeds region length, indicate an error
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n",
+ acpi_ut_get_node_name (obj_desc->common_field.node),
+ obj_desc->common_field.base_byte_offset,
+ field_datum_byte_offset, obj_desc->common_field.access_byte_width,
+ acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length));
+
+ return_ACPI_STATUS (AE_AML_REGION_LIMIT);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_access_region
+ *
+ * PARAMETERS: *obj_desc - Field to be read
+ * field_datum_byte_offset - Byte offset of this datum within the
+ * parent field
+ * *Value - Where to store value (must at least
+ * the size of acpi_integer)
+ * Function - Read or Write flag plus other region-
+ * dependent flags
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read or Write a single field datum to an Operation Region.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_access_region (
+ union acpi_operand_object *obj_desc,
+ u32 field_datum_byte_offset,
+ acpi_integer *value,
+ u32 function)
+{
+ acpi_status status;
+ union acpi_operand_object *rgn_desc;
+ acpi_physical_address address;
+
+
+ ACPI_FUNCTION_TRACE ("ex_access_region");
+
+
+ /*
+ * Ensure that the region operands are fully evaluated and verify
+ * the validity of the request
+ */
+ status = acpi_ex_setup_region (obj_desc, field_datum_byte_offset);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * The physical address of this field datum is:
+ *
+ * 1) The base of the region, plus
+ * 2) The base offset of the field, plus
+ * 3) The current offset into the field
+ */
+ rgn_desc = obj_desc->common_field.region_obj;
+ address = rgn_desc->region.address
+ + obj_desc->common_field.base_byte_offset
+ + field_datum_byte_offset;
+
+ if ((function & ACPI_IO_MASK) == ACPI_READ) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
+ " Region [%s:%X], Width %X, byte_base %X, Offset %X at %8.8X%8.8X\n",
+ acpi_ut_get_region_name (rgn_desc->region.space_id),
+ rgn_desc->region.space_id,
+ obj_desc->common_field.access_byte_width,
+ obj_desc->common_field.base_byte_offset,
+ field_datum_byte_offset,
+ ACPI_FORMAT_UINT64 (address)));
+
+ /* Invoke the appropriate address_space/op_region handler */
+
+ status = acpi_ev_address_space_dispatch (rgn_desc, function,
+ address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value);
+
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_NOT_IMPLEMENTED) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Region %s(%X) not implemented\n",
+ acpi_ut_get_region_name (rgn_desc->region.space_id),
+ rgn_desc->region.space_id));
+ }
+ else if (status == AE_NOT_EXIST) {
+ ACPI_REPORT_ERROR ((
+ "Region %s(%X) has no handler\n",
+ acpi_ut_get_region_name (rgn_desc->region.space_id),
+ rgn_desc->region.space_id));
+ }
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_register_overflow
+ *
+ * PARAMETERS: *obj_desc - Register(Field) to be written
+ * Value - Value to be stored
+ *
+ * RETURN: TRUE if value overflows the field, FALSE otherwise
+ *
+ * DESCRIPTION: Check if a value is out of range of the field being written.
+ * Used to check if the values written to Index and Bank registers
+ * are out of range. Normally, the value is simply truncated
+ * to fit the field, but this case is most likely a serious
+ * coding error in the ASL.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ex_register_overflow (
+ union acpi_operand_object *obj_desc,
+ acpi_integer value)
+{
+
+ if (obj_desc->common_field.bit_length >= ACPI_INTEGER_BIT_SIZE) {
+ /*
+ * The field is large enough to hold the maximum integer, so we can
+ * never overflow it.
+ */
+ return (FALSE);
+ }
+
+ if (value >= ((acpi_integer) 1 << obj_desc->common_field.bit_length)) {
+ /*
+ * The Value is larger than the maximum value that can fit into
+ * the register.
+ */
+ return (TRUE);
+ }
+
+ /* The Value will fit into the field with no truncation */
+
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_field_datum_io
+ *
+ * PARAMETERS: *obj_desc - Field to be read
+ * field_datum_byte_offset - Byte offset of this datum within the
+ * parent field
+ * *Value - Where to store value (must be 64 bits)
+ * read_write - Read or Write flag
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read or Write a single datum of a field. The field_type is
+ * demultiplexed here to handle the different types of fields
+ * (buffer_field, region_field, index_field, bank_field)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_field_datum_io (
+ union acpi_operand_object *obj_desc,
+ u32 field_datum_byte_offset,
+ acpi_integer *value,
+ u32 read_write)
+{
+ acpi_status status;
+ acpi_integer local_value;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ex_field_datum_io", field_datum_byte_offset);
+
+
+ if (read_write == ACPI_READ) {
+ if (!value) {
+ local_value = 0;
+ value = &local_value; /* To support reads without saving return value */
+ }
+
+ /* Clear the entire return buffer first, [Very Important!] */
+
+ *value = 0;
+ }
+
+ /*
+ * The four types of fields are:
+ *
+ * buffer_field - Read/write from/to a Buffer
+ * region_field - Read/write from/to a Operation Region.
+ * bank_field - Write to a Bank Register, then read/write from/to an op_region
+ * index_field - Write to an Index Register, then read/write from/to a Data Register
+ */
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_BUFFER_FIELD:
+ /*
+ * If the buffer_field arguments have not been previously evaluated,
+ * evaluate them now and save the results.
+ */
+ if (!(obj_desc->common.flags & AOPOBJ_DATA_VALID)) {
+ status = acpi_ds_get_buffer_field_arguments (obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ if (read_write == ACPI_READ) {
+ /*
+ * Copy the data from the source buffer.
+ * Length is the field width in bytes.
+ */
+ ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer
+ + obj_desc->buffer_field.base_byte_offset
+ + field_datum_byte_offset,
+ obj_desc->common_field.access_byte_width);
+ }
+ else {
+ /*
+ * Copy the data to the target buffer.
+ * Length is the field width in bytes.
+ */
+ ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer
+ + obj_desc->buffer_field.base_byte_offset
+ + field_datum_byte_offset,
+ value, obj_desc->common_field.access_byte_width);
+ }
+
+ status = AE_OK;
+ break;
+
+
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ /* Ensure that the bank_value is not beyond the capacity of the register */
+
+ if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj,
+ (acpi_integer) obj_desc->bank_field.value)) {
+ return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
+ }
+
+ /*
+ * For bank_fields, we must write the bank_value to the bank_register
+ * (itself a region_field) before we can access the data.
+ */
+ status = acpi_ex_insert_into_field (obj_desc->bank_field.bank_obj,
+ &obj_desc->bank_field.value,
+ sizeof (obj_desc->bank_field.value));
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Now that the Bank has been selected, fall through to the
+ * region_field case and write the datum to the Operation Region
+ */
+
+ /*lint -fallthrough */
+
+
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ /*
+ * For simple region_fields, we just directly access the owning
+ * Operation Region.
+ */
+ status = acpi_ex_access_region (obj_desc, field_datum_byte_offset, value,
+ read_write);
+ break;
+
+
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+
+ /* Ensure that the index_value is not beyond the capacity of the register */
+
+ if (acpi_ex_register_overflow (obj_desc->index_field.index_obj,
+ (acpi_integer) obj_desc->index_field.value)) {
+ return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
+ }
+
+ /* Write the index value to the index_register (itself a region_field) */
+
+ field_datum_byte_offset += obj_desc->index_field.value;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Write to Index Register: Value %8.8X\n",
+ field_datum_byte_offset));
+
+ status = acpi_ex_insert_into_field (obj_desc->index_field.index_obj,
+ &field_datum_byte_offset,
+ sizeof (field_datum_byte_offset));
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "I/O to Data Register: value_ptr %p\n",
+ value));
+
+ if (read_write == ACPI_READ) {
+ /* Read the datum from the data_register */
+
+ status = acpi_ex_extract_from_field (obj_desc->index_field.data_obj,
+ value, sizeof (acpi_integer));
+ }
+ else {
+ /* Write the datum to the data_register */
+
+ status = acpi_ex_insert_into_field (obj_desc->index_field.data_obj,
+ value, sizeof (acpi_integer));
+ }
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n",
+ ACPI_GET_OBJECT_TYPE (obj_desc)));
+ status = AE_AML_INTERNAL;
+ break;
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ if (read_write == ACPI_READ) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n",
+ ACPI_FORMAT_UINT64 (*value),
+ obj_desc->common_field.access_byte_width));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n",
+ ACPI_FORMAT_UINT64 (*value),
+ obj_desc->common_field.access_byte_width));
+ }
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_write_with_update_rule
+ *
+ * PARAMETERS: *obj_desc - Field to be set
+ * Value - Value to store
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Apply the field update rule to a field write
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_write_with_update_rule (
+ union acpi_operand_object *obj_desc,
+ acpi_integer mask,
+ acpi_integer field_value,
+ u32 field_datum_byte_offset)
+{
+ acpi_status status = AE_OK;
+ acpi_integer merged_value;
+ acpi_integer current_value;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ex_write_with_update_rule", mask);
+
+
+ /* Start with the new bits */
+
+ merged_value = field_value;
+
+ /* If the mask is all ones, we don't need to worry about the update rule */
+
+ if (mask != ACPI_INTEGER_MAX) {
+ /* Decode the update rule */
+
+ switch (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK) {
+ case AML_FIELD_UPDATE_PRESERVE:
+ /*
+ * Check if update rule needs to be applied (not if mask is all
+ * ones) The left shift drops the bits we want to ignore.
+ */
+ if ((~mask << (ACPI_MUL_8 (sizeof (mask)) -
+ ACPI_MUL_8 (obj_desc->common_field.access_byte_width))) != 0) {
+ /*
+ * Read the current contents of the byte/word/dword containing
+ * the field, and merge with the new field value.
+ */
+ status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
+ &current_value, ACPI_READ);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ merged_value |= (current_value & ~mask);
+ }
+ break;
+
+ case AML_FIELD_UPDATE_WRITE_AS_ONES:
+
+ /* Set positions outside the field to all ones */
+
+ merged_value |= ~mask;
+ break;
+
+ case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
+
+ /* Set positions outside the field to all zeros */
+
+ merged_value &= mask;
+ break;
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "write_with_update_rule: Unknown update_rule setting: %X\n",
+ (obj_desc->common_field.field_flags & AML_FIELD_UPDATE_RULE_MASK)));
+ return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Mask %8.8X%8.8X, datum_offset %X, Width %X, Value %8.8X%8.8X, merged_value %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (mask),
+ field_datum_byte_offset,
+ obj_desc->common_field.access_byte_width,
+ ACPI_FORMAT_UINT64 (field_value),
+ ACPI_FORMAT_UINT64 (merged_value)));
+
+ /* Write the merged value */
+
+ status = acpi_ex_field_datum_io (obj_desc, field_datum_byte_offset,
+ &merged_value, ACPI_WRITE);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_extract_from_field
+ *
+ * PARAMETERS: obj_desc - Field to be read
+ * Buffer - Where to store the field data
+ * buffer_length - Length of Buffer
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve the current value of the given field
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_extract_from_field (
+ union acpi_operand_object *obj_desc,
+ void *buffer,
+ u32 buffer_length)
+{
+ acpi_status status;
+ acpi_integer raw_datum;
+ acpi_integer merged_datum;
+ u32 field_offset = 0;
+ u32 buffer_offset = 0;
+ u32 buffer_tail_bits;
+ u32 datum_count;
+ u32 field_datum_count;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ex_extract_from_field");
+
+
+ /* Validate target buffer and clear it */
+
+ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES (
+ obj_desc->common_field.bit_length)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Field size %X (bits) is too large for buffer (%X)\n",
+ obj_desc->common_field.bit_length, buffer_length));
+
+ return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
+ }
+ ACPI_MEMSET (buffer, 0, buffer_length);
+
+ /* Compute the number of datums (access width data items) */
+
+ datum_count = ACPI_ROUND_UP_TO (
+ obj_desc->common_field.bit_length,
+ obj_desc->common_field.access_bit_width);
+ field_datum_count = ACPI_ROUND_UP_TO (
+ obj_desc->common_field.bit_length +
+ obj_desc->common_field.start_field_bit_offset,
+ obj_desc->common_field.access_bit_width);
+
+ /* Priming read from the field */
+
+ status = acpi_ex_field_datum_io (obj_desc, field_offset, &raw_datum, ACPI_READ);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;
+
+ /* Read the rest of the field */
+
+ for (i = 1; i < field_datum_count; i++) {
+ /* Get next input datum from the field */
+
+ field_offset += obj_desc->common_field.access_byte_width;
+ status = acpi_ex_field_datum_io (obj_desc, field_offset,
+ &raw_datum, ACPI_READ);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Merge with previous datum if necessary */
+
+ merged_datum |= raw_datum <<
+ (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);
+
+ if (i == datum_count) {
+ break;
+ }
+
+ /* Write merged datum to target buffer */
+
+ ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
+ ACPI_MIN(obj_desc->common_field.access_byte_width,
+ buffer_length - buffer_offset));
+
+ buffer_offset += obj_desc->common_field.access_byte_width;
+ merged_datum = raw_datum >> obj_desc->common_field.start_field_bit_offset;
+ }
+
+ /* Mask off any extra bits in the last datum */
+
+ buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width;
+ if (buffer_tail_bits) {
+ merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
+ }
+
+ /* Write the last datum to the buffer */
+
+ ACPI_MEMCPY (((char *) buffer) + buffer_offset, &merged_datum,
+ ACPI_MIN(obj_desc->common_field.access_byte_width,
+ buffer_length - buffer_offset));
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_insert_into_field
+ *
+ * PARAMETERS: obj_desc - Field to be written
+ * Buffer - Data to be written
+ * buffer_length - Length of Buffer
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the Buffer contents into the given field
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_insert_into_field (
+ union acpi_operand_object *obj_desc,
+ void *buffer,
+ u32 buffer_length)
+{
+ acpi_status status;
+ acpi_integer mask;
+ acpi_integer merged_datum;
+ acpi_integer raw_datum = 0;
+ u32 field_offset = 0;
+ u32 buffer_offset = 0;
+ u32 buffer_tail_bits;
+ u32 datum_count;
+ u32 field_datum_count;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ex_insert_into_field");
+
+
+ /* Validate input buffer */
+
+ if (buffer_length < ACPI_ROUND_BITS_UP_TO_BYTES (
+ obj_desc->common_field.bit_length)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Field size %X (bits) is too large for buffer (%X)\n",
+ obj_desc->common_field.bit_length, buffer_length));
+
+ return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
+ }
+
+ /* Compute the number of datums (access width data items) */
+
+ mask = ACPI_MASK_BITS_BELOW (obj_desc->common_field.start_field_bit_offset);
+ datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length,
+ obj_desc->common_field.access_bit_width);
+ field_datum_count = ACPI_ROUND_UP_TO (obj_desc->common_field.bit_length +
+ obj_desc->common_field.start_field_bit_offset,
+ obj_desc->common_field.access_bit_width);
+
+ /* Get initial Datum from the input buffer */
+
+ ACPI_MEMCPY (&raw_datum, buffer,
+ ACPI_MIN(obj_desc->common_field.access_byte_width,
+ buffer_length - buffer_offset));
+
+ merged_datum = raw_datum << obj_desc->common_field.start_field_bit_offset;
+
+ /* Write the entire field */
+
+ for (i = 1; i < field_datum_count; i++) {
+ /* Write merged datum to the target field */
+
+ merged_datum &= mask;
+ status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Start new output datum by merging with previous input datum */
+
+ field_offset += obj_desc->common_field.access_byte_width;
+ merged_datum = raw_datum >>
+ (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);
+ mask = ACPI_INTEGER_MAX;
+
+ if (i == datum_count) {
+ break;
+ }
+
+ /* Get the next input datum from the buffer */
+
+ buffer_offset += obj_desc->common_field.access_byte_width;
+ ACPI_MEMCPY (&raw_datum, ((char *) buffer) + buffer_offset,
+ ACPI_MIN(obj_desc->common_field.access_byte_width,
+ buffer_length - buffer_offset));
+ merged_datum |= raw_datum << obj_desc->common_field.start_field_bit_offset;
+ }
+
+ /* Mask off any extra bits in the last datum */
+
+ buffer_tail_bits = (obj_desc->common_field.bit_length +
+ obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width;
+ if (buffer_tail_bits) {
+ mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
+ }
+
+ /* Write the last datum to the field */
+
+ merged_datum &= mask;
+ status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset);
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
new file mode 100644
index 000000000000..b542dcd58c07
--- /dev/null
+++ b/drivers/acpi/executer/exmisc.c
@@ -0,0 +1,738 @@
+
+/******************************************************************************
+ *
+ * Module Name: exmisc - ACPI AML (p-code) execution - specific opcodes
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exmisc")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_get_object_reference
+ *
+ * PARAMETERS: obj_desc - Create a reference to this object
+ * return_desc - Where to store the reference
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Obtain and return a "reference" to the target object
+ * Common code for the ref_of_op and the cond_ref_of_op.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_get_object_reference (
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object **return_desc,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *reference_obj;
+ union acpi_operand_object *referenced_obj;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_get_object_reference", obj_desc);
+
+
+ *return_desc = NULL;
+
+ switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
+ case ACPI_DESC_TYPE_OPERAND:
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_LOCAL_REFERENCE) {
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * Must be a reference to a Local or Arg
+ */
+ switch (obj_desc->reference.opcode) {
+ case AML_LOCAL_OP:
+ case AML_ARG_OP:
+ case AML_DEBUG_OP:
+
+ /* The referenced object is the pseudo-node for the local/arg */
+
+ referenced_obj = obj_desc->reference.object;
+ break;
+
+ default:
+
+ ACPI_REPORT_ERROR (("Unknown Reference opcode in get_reference %X\n",
+ obj_desc->reference.opcode));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+ break;
+
+
+ case ACPI_DESC_TYPE_NAMED:
+
+ /*
+ * A named reference that has already been resolved to a Node
+ */
+ referenced_obj = obj_desc;
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("Invalid descriptor type in get_reference: %X\n",
+ ACPI_GET_DESCRIPTOR_TYPE (obj_desc)));
+ return_ACPI_STATUS (AE_TYPE);
+ }
+
+
+ /* Create a new reference object */
+
+ reference_obj = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_REFERENCE);
+ if (!reference_obj) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ reference_obj->reference.opcode = AML_REF_OF_OP;
+ reference_obj->reference.object = referenced_obj;
+ *return_desc = reference_obj;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p Type [%s], returning Reference %p\n",
+ obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc));
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_concat_template
+ *
+ * PARAMETERS: Operand0 - First source object
+ * Operand1 - Second source object
+ * actual_return_desc - Where to place the return object
+ * walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Concatenate two resource templates
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_concat_template (
+ union acpi_operand_object *operand0,
+ union acpi_operand_object *operand1,
+ union acpi_operand_object **actual_return_desc,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *return_desc;
+ u8 *new_buf;
+ u8 *end_tag1;
+ u8 *end_tag2;
+ acpi_size length1;
+ acpi_size length2;
+
+
+ ACPI_FUNCTION_TRACE ("ex_concat_template");
+
+
+ /* Find the end_tags in each resource template */
+
+ end_tag1 = acpi_ut_get_resource_end_tag (operand0);
+ end_tag2 = acpi_ut_get_resource_end_tag (operand1);
+ if (!end_tag1 || !end_tag2) {
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Compute the length of each part */
+
+ length1 = ACPI_PTR_DIFF (end_tag1, operand0->buffer.pointer);
+ length2 = ACPI_PTR_DIFF (end_tag2, operand1->buffer.pointer) +
+ 2; /* Size of END_TAG */
+
+ /* Create a new buffer object for the result */
+
+ return_desc = acpi_ut_create_buffer_object (length1 + length2);
+ if (!return_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Copy the templates to the new descriptor */
+
+ new_buf = return_desc->buffer.pointer;
+ ACPI_MEMCPY (new_buf, operand0->buffer.pointer, length1);
+ ACPI_MEMCPY (new_buf + length1, operand1->buffer.pointer, length2);
+
+ /* Compute the new checksum */
+
+ new_buf[return_desc->buffer.length - 1] =
+ acpi_ut_generate_checksum (return_desc->buffer.pointer,
+ (return_desc->buffer.length - 1));
+
+ /* Return the completed template descriptor */
+
+ *actual_return_desc = return_desc;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_do_concatenate
+ *
+ * PARAMETERS: Operand0 - First source object
+ * Operand1 - Second source object
+ * actual_return_desc - Where to place the return object
+ * walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Concatenate two objects OF THE SAME TYPE.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_do_concatenate (
+ union acpi_operand_object *operand0,
+ union acpi_operand_object *operand1,
+ union acpi_operand_object **actual_return_desc,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *local_operand1 = operand1;
+ union acpi_operand_object *return_desc;
+ char *new_buf;
+ acpi_status status;
+ acpi_size new_length;
+
+
+ ACPI_FUNCTION_TRACE ("ex_do_concatenate");
+
+
+ /*
+ * Convert the second operand if necessary. The first operand
+ * determines the type of the second operand, (See the Data Types
+ * section of the ACPI specification.) Both object types are
+ * guaranteed to be either Integer/String/Buffer by the operand
+ * resolution mechanism.
+ */
+ switch (ACPI_GET_OBJECT_TYPE (operand0)) {
+ case ACPI_TYPE_INTEGER:
+ status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16);
+ break;
+
+ case ACPI_TYPE_STRING:
+ status = acpi_ex_convert_to_string (operand1, &local_operand1,
+ ACPI_IMPLICIT_CONVERT_HEX);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ status = acpi_ex_convert_to_buffer (operand1, &local_operand1);
+ break;
+
+ default:
+ ACPI_REPORT_ERROR (("Concat - invalid obj type: %X\n",
+ ACPI_GET_OBJECT_TYPE (operand0)));
+ status = AE_AML_INTERNAL;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * Both operands are now known to be the same object type
+ * (Both are Integer, String, or Buffer), and we can now perform the
+ * concatenation.
+ */
+
+ /*
+ * There are three cases to handle:
+ *
+ * 1) Two Integers concatenated to produce a new Buffer
+ * 2) Two Strings concatenated to produce a new String
+ * 3) Two Buffers concatenated to produce a new Buffer
+ */
+ switch (ACPI_GET_OBJECT_TYPE (operand0)) {
+ case ACPI_TYPE_INTEGER:
+
+ /* Result of two Integers is a Buffer */
+ /* Need enough buffer space for two integers */
+
+ return_desc = acpi_ut_create_buffer_object (
+ ACPI_MUL_2 (acpi_gbl_integer_byte_width));
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ new_buf = (char *) return_desc->buffer.pointer;
+
+ /* Copy the first integer, LSB first */
+
+ ACPI_MEMCPY (new_buf,
+ &operand0->integer.value,
+ acpi_gbl_integer_byte_width);
+
+ /* Copy the second integer (LSB first) after the first */
+
+ ACPI_MEMCPY (new_buf + acpi_gbl_integer_byte_width,
+ &local_operand1->integer.value,
+ acpi_gbl_integer_byte_width);
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ /* Result of two Strings is a String */
+
+ new_length = (acpi_size) operand0->string.length +
+ (acpi_size) local_operand1->string.length;
+ if (new_length > ACPI_MAX_STRING_CONVERSION) {
+ status = AE_AML_STRING_LIMIT;
+ goto cleanup;
+ }
+
+ return_desc = acpi_ut_create_string_object (new_length);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ new_buf = return_desc->string.pointer;
+
+ /* Concatenate the strings */
+
+ ACPI_STRCPY (new_buf,
+ operand0->string.pointer);
+ ACPI_STRCPY (new_buf + operand0->string.length,
+ local_operand1->string.pointer);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ /* Result of two Buffers is a Buffer */
+
+ return_desc = acpi_ut_create_buffer_object (
+ (acpi_size) operand0->buffer.length +
+ (acpi_size) local_operand1->buffer.length);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ new_buf = (char *) return_desc->buffer.pointer;
+
+ /* Concatenate the buffers */
+
+ ACPI_MEMCPY (new_buf,
+ operand0->buffer.pointer,
+ operand0->buffer.length);
+ ACPI_MEMCPY (new_buf + operand0->buffer.length,
+ local_operand1->buffer.pointer,
+ local_operand1->buffer.length);
+ break;
+
+ default:
+
+ /* Invalid object type, should not happen here */
+
+ ACPI_REPORT_ERROR (("Concatenate - Invalid object type: %X\n",
+ ACPI_GET_OBJECT_TYPE (operand0)));
+ status =AE_AML_INTERNAL;
+ goto cleanup;
+ }
+
+ *actual_return_desc = return_desc;
+
+cleanup:
+ if (local_operand1 != operand1) {
+ acpi_ut_remove_reference (local_operand1);
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_do_math_op
+ *
+ * PARAMETERS: Opcode - AML opcode
+ * Integer0 - Integer operand #0
+ * Integer1 - Integer operand #1
+ *
+ * RETURN: Integer result of the operation
+ *
+ * DESCRIPTION: Execute a math AML opcode. The purpose of having all of the
+ * math functions here is to prevent a lot of pointer dereferencing
+ * to obtain the operands.
+ *
+ ******************************************************************************/
+
+acpi_integer
+acpi_ex_do_math_op (
+ u16 opcode,
+ acpi_integer integer0,
+ acpi_integer integer1)
+{
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ switch (opcode) {
+ case AML_ADD_OP: /* Add (Integer0, Integer1, Result) */
+
+ return (integer0 + integer1);
+
+
+ case AML_BIT_AND_OP: /* And (Integer0, Integer1, Result) */
+
+ return (integer0 & integer1);
+
+
+ case AML_BIT_NAND_OP: /* NAnd (Integer0, Integer1, Result) */
+
+ return (~(integer0 & integer1));
+
+
+ case AML_BIT_OR_OP: /* Or (Integer0, Integer1, Result) */
+
+ return (integer0 | integer1);
+
+
+ case AML_BIT_NOR_OP: /* NOr (Integer0, Integer1, Result) */
+
+ return (~(integer0 | integer1));
+
+
+ case AML_BIT_XOR_OP: /* XOr (Integer0, Integer1, Result) */
+
+ return (integer0 ^ integer1);
+
+
+ case AML_MULTIPLY_OP: /* Multiply (Integer0, Integer1, Result) */
+
+ return (integer0 * integer1);
+
+
+ case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */
+
+ return (integer0 << integer1);
+
+
+ case AML_SHIFT_RIGHT_OP: /* shift_right (Operand, shift_count, Result) */
+
+ return (integer0 >> integer1);
+
+
+ case AML_SUBTRACT_OP: /* Subtract (Integer0, Integer1, Result) */
+
+ return (integer0 - integer1);
+
+ default:
+
+ return (0);
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_do_logical_numeric_op
+ *
+ * PARAMETERS: Opcode - AML opcode
+ * Integer0 - Integer operand #0
+ * Integer1 - Integer operand #1
+ * logical_result - TRUE/FALSE result of the operation
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a logical "Numeric" AML opcode. For these Numeric
+ * operators (LAnd and LOr), both operands must be integers.
+ *
+ * Note: cleanest machine code seems to be produced by the code
+ * below, rather than using statements of the form:
+ * Result = (Integer0 && Integer1);
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_do_logical_numeric_op (
+ u16 opcode,
+ acpi_integer integer0,
+ acpi_integer integer1,
+ u8 *logical_result)
+{
+ acpi_status status = AE_OK;
+ u8 local_result = FALSE;
+
+
+ ACPI_FUNCTION_TRACE ("ex_do_logical_numeric_op");
+
+
+ switch (opcode) {
+ case AML_LAND_OP: /* LAnd (Integer0, Integer1) */
+
+ if (integer0 && integer1) {
+ local_result = TRUE;
+ }
+ break;
+
+ case AML_LOR_OP: /* LOr (Integer0, Integer1) */
+
+ if (integer0 || integer1) {
+ local_result = TRUE;
+ }
+ break;
+
+ default:
+ status = AE_AML_INTERNAL;
+ break;
+ }
+
+ /* Return the logical result and status */
+
+ *logical_result = local_result;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_do_logical_op
+ *
+ * PARAMETERS: Opcode - AML opcode
+ * Operand0 - operand #0
+ * Operand1 - operand #1
+ * logical_result - TRUE/FALSE result of the operation
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a logical AML opcode. The purpose of having all of the
+ * functions here is to prevent a lot of pointer dereferencing
+ * to obtain the operands and to simplify the generation of the
+ * logical value. For the Numeric operators (LAnd and LOr), both
+ * operands must be integers. For the other logical operators,
+ * operands can be any combination of Integer/String/Buffer. The
+ * first operand determines the type to which the second operand
+ * will be converted.
+ *
+ * Note: cleanest machine code seems to be produced by the code
+ * below, rather than using statements of the form:
+ * Result = (Operand0 == Operand1);
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_do_logical_op (
+ u16 opcode,
+ union acpi_operand_object *operand0,
+ union acpi_operand_object *operand1,
+ u8 *logical_result)
+{
+ union acpi_operand_object *local_operand1 = operand1;
+ acpi_integer integer0;
+ acpi_integer integer1;
+ u32 length0;
+ u32 length1;
+ acpi_status status = AE_OK;
+ u8 local_result = FALSE;
+ int compare;
+
+
+ ACPI_FUNCTION_TRACE ("ex_do_logical_op");
+
+
+ /*
+ * Convert the second operand if necessary. The first operand
+ * determines the type of the second operand, (See the Data Types
+ * section of the ACPI 3.0+ specification.) Both object types are
+ * guaranteed to be either Integer/String/Buffer by the operand
+ * resolution mechanism.
+ */
+ switch (ACPI_GET_OBJECT_TYPE (operand0)) {
+ case ACPI_TYPE_INTEGER:
+ status = acpi_ex_convert_to_integer (operand1, &local_operand1, 16);
+ break;
+
+ case ACPI_TYPE_STRING:
+ status = acpi_ex_convert_to_string (operand1, &local_operand1,
+ ACPI_IMPLICIT_CONVERT_HEX);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ status = acpi_ex_convert_to_buffer (operand1, &local_operand1);
+ break;
+
+ default:
+ status = AE_AML_INTERNAL;
+ break;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * Two cases: 1) Both Integers, 2) Both Strings or Buffers
+ */
+ if (ACPI_GET_OBJECT_TYPE (operand0) == ACPI_TYPE_INTEGER) {
+ /*
+ * 1) Both operands are of type integer
+ * Note: local_operand1 may have changed above
+ */
+ integer0 = operand0->integer.value;
+ integer1 = local_operand1->integer.value;
+
+ switch (opcode) {
+ case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */
+
+ if (integer0 == integer1) {
+ local_result = TRUE;
+ }
+ break;
+
+ case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */
+
+ if (integer0 > integer1) {
+ local_result = TRUE;
+ }
+ break;
+
+ case AML_LLESS_OP: /* LLess (Operand0, Operand1) */
+
+ if (integer0 < integer1) {
+ local_result = TRUE;
+ }
+ break;
+
+ default:
+ status = AE_AML_INTERNAL;
+ break;
+ }
+ }
+ else {
+ /*
+ * 2) Both operands are Strings or both are Buffers
+ * Note: Code below takes advantage of common Buffer/String
+ * object fields. local_operand1 may have changed above. Use
+ * memcmp to handle nulls in buffers.
+ */
+ length0 = operand0->buffer.length;
+ length1 = local_operand1->buffer.length;
+
+ /* Lexicographic compare: compare the data bytes */
+
+ compare = ACPI_MEMCMP ((const char * ) operand0->buffer.pointer,
+ (const char * ) local_operand1->buffer.pointer,
+ (length0 > length1) ? length1 : length0);
+
+ switch (opcode) {
+ case AML_LEQUAL_OP: /* LEqual (Operand0, Operand1) */
+
+ /* Length and all bytes must be equal */
+
+ if ((length0 == length1) &&
+ (compare == 0)) {
+ /* Length and all bytes match ==> TRUE */
+
+ local_result = TRUE;
+ }
+ break;
+
+ case AML_LGREATER_OP: /* LGreater (Operand0, Operand1) */
+
+ if (compare > 0) {
+ local_result = TRUE;
+ goto cleanup; /* TRUE */
+ }
+ if (compare < 0) {
+ goto cleanup; /* FALSE */
+ }
+
+ /* Bytes match (to shortest length), compare lengths */
+
+ if (length0 > length1) {
+ local_result = TRUE;
+ }
+ break;
+
+ case AML_LLESS_OP: /* LLess (Operand0, Operand1) */
+
+ if (compare > 0) {
+ goto cleanup; /* FALSE */
+ }
+ if (compare < 0) {
+ local_result = TRUE;
+ goto cleanup; /* TRUE */
+ }
+
+ /* Bytes match (to shortest length), compare lengths */
+
+ if (length0 < length1) {
+ local_result = TRUE;
+ }
+ break;
+
+ default:
+ status = AE_AML_INTERNAL;
+ break;
+ }
+ }
+
+cleanup:
+
+ /* New object was created if implicit conversion performed - delete */
+
+ if (local_operand1 != operand1) {
+ acpi_ut_remove_reference (local_operand1);
+ }
+
+ /* Return the logical result and status */
+
+ *logical_result = local_result;
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
new file mode 100644
index 000000000000..68c4bb1970a5
--- /dev/null
+++ b/drivers/acpi/executer/exmutex.c
@@ -0,0 +1,363 @@
+
+/******************************************************************************
+ *
+ * Module Name: exmutex - ASL Mutex Acquire/Release functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exmutex")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_unlink_mutex
+ *
+ * PARAMETERS: obj_desc - The mutex to be unlinked
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove a mutex from the "acquired_mutex" list
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_unlink_mutex (
+ union acpi_operand_object *obj_desc)
+{
+ struct acpi_thread_state *thread = obj_desc->mutex.owner_thread;
+
+
+ if (!thread) {
+ return;
+ }
+
+ /* Doubly linked list */
+
+ if (obj_desc->mutex.next) {
+ (obj_desc->mutex.next)->mutex.prev = obj_desc->mutex.prev;
+ }
+
+ if (obj_desc->mutex.prev) {
+ (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
+ }
+ else {
+ thread->acquired_mutex_list = obj_desc->mutex.next;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_link_mutex
+ *
+ * PARAMETERS: obj_desc - The mutex to be linked
+ * list_head - head of the "acquired_mutex" list
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_link_mutex (
+ union acpi_operand_object *obj_desc,
+ struct acpi_thread_state *thread)
+{
+ union acpi_operand_object *list_head;
+
+
+ list_head = thread->acquired_mutex_list;
+
+ /* This object will be the first object in the list */
+
+ obj_desc->mutex.prev = NULL;
+ obj_desc->mutex.next = list_head;
+
+ /* Update old first object to point back to this object */
+
+ if (list_head) {
+ list_head->mutex.prev = obj_desc;
+ }
+
+ /* Update list head */
+
+ thread->acquired_mutex_list = obj_desc;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_acquire_mutex
+ *
+ * PARAMETERS: time_desc - The 'time to delay' object descriptor
+ * obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire an AML mutex
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_acquire_mutex (
+ union acpi_operand_object *time_desc,
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_acquire_mutex", obj_desc);
+
+
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Sanity check -- we must have a valid thread ID */
+
+ if (!walk_state->thread) {
+ ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n",
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /*
+ * Current Sync must be less than or equal to the sync level of the
+ * mutex. This mechanism provides some deadlock prevention
+ */
+ if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
+ ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], incorrect sync_level\n",
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
+ return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
+ }
+
+ /* Support for multiple acquires by the owning thread */
+
+ if (obj_desc->mutex.owner_thread) {
+ /* Special case for Global Lock, allow all threads */
+
+ if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) ||
+ (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) {
+ /*
+ * The mutex is already owned by this thread,
+ * just increment the acquisition depth
+ */
+ obj_desc->mutex.acquisition_depth++;
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ /* Acquire the mutex, wait if necessary */
+
+ status = acpi_ex_system_acquire_mutex (time_desc, obj_desc);
+ if (ACPI_FAILURE (status)) {
+ /* Includes failure from a timeout on time_desc */
+
+ return_ACPI_STATUS (status);
+ }
+
+ /* Have the mutex: update mutex and walk info and save the sync_level */
+
+ obj_desc->mutex.owner_thread = walk_state->thread;
+ obj_desc->mutex.acquisition_depth = 1;
+ obj_desc->mutex.original_sync_level = walk_state->thread->current_sync_level;
+
+ walk_state->thread->current_sync_level = obj_desc->mutex.sync_level;
+
+ /* Link the mutex to the current thread for force-unlock at method exit */
+
+ acpi_ex_link_mutex (obj_desc, walk_state->thread);
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_release_mutex
+ *
+ * PARAMETERS: obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release a previously acquired Mutex.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_release_mutex (
+ union acpi_operand_object *obj_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ex_release_mutex");
+
+
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* The mutex must have been previously acquired in order to release it */
+
+ if (!obj_desc->mutex.owner_thread) {
+ ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], not acquired\n",
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
+ return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
+ }
+
+ /* Sanity check -- we must have a valid thread ID */
+
+ if (!walk_state->thread) {
+ ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], null thread info\n",
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /*
+ * The Mutex is owned, but this thread must be the owner.
+ * Special case for Global Lock, any thread can release
+ */
+ if ((obj_desc->mutex.owner_thread->thread_id != walk_state->thread->thread_id) &&
+ (obj_desc->mutex.semaphore != acpi_gbl_global_lock_semaphore)) {
+ ACPI_REPORT_ERROR ((
+ "Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n",
+ walk_state->thread->thread_id,
+ acpi_ut_get_node_name (obj_desc->mutex.node),
+ obj_desc->mutex.owner_thread->thread_id));
+ return_ACPI_STATUS (AE_AML_NOT_OWNER);
+ }
+
+ /*
+ * The sync level of the mutex must be less than or
+ * equal to the current sync level
+ */
+ if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
+ ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], incorrect sync_level\n",
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
+ return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
+ }
+
+ /* Match multiple Acquires with multiple Releases */
+
+ obj_desc->mutex.acquisition_depth--;
+ if (obj_desc->mutex.acquisition_depth != 0) {
+ /* Just decrement the depth and return */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Unlink the mutex from the owner's list */
+
+ acpi_ex_unlink_mutex (obj_desc);
+
+ /* Release the mutex */
+
+ status = acpi_ex_system_release_mutex (obj_desc);
+
+ /* Update the mutex and walk state, restore sync_level before acquire */
+
+ obj_desc->mutex.owner_thread = NULL;
+ walk_state->thread->current_sync_level = obj_desc->mutex.original_sync_level;
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_release_all_mutexes
+ *
+ * PARAMETERS: mutex_list - Head of the mutex list
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release all mutexes in the list
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_release_all_mutexes (
+ struct acpi_thread_state *thread)
+{
+ union acpi_operand_object *next = thread->acquired_mutex_list;
+ union acpi_operand_object *this;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Traverse the list of owned mutexes, releasing each one */
+
+ while (next) {
+ this = next;
+ next = this->mutex.next;
+
+ this->mutex.acquisition_depth = 1;
+ this->mutex.prev = NULL;
+ this->mutex.next = NULL;
+
+ /* Release the mutex */
+
+ status = acpi_ex_system_release_mutex (this);
+ if (ACPI_FAILURE (status)) {
+ continue;
+ }
+
+ /* Mark mutex unowned */
+
+ this->mutex.owner_thread = NULL;
+
+ /* Update Thread sync_level (Last mutex is the important one) */
+
+ thread->current_sync_level = this->mutex.original_sync_level;
+ }
+}
+
+
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
new file mode 100644
index 000000000000..7911c533c265
--- /dev/null
+++ b/drivers/acpi/executer/exnames.c
@@ -0,0 +1,427 @@
+
+/******************************************************************************
+ *
+ * Module Name: exnames - interpreter/scanner name load/execute
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exnames")
+
+
+/* AML Package Length encodings */
+
+#define ACPI_AML_PACKAGE_TYPE1 0x40
+#define ACPI_AML_PACKAGE_TYPE2 0x4000
+#define ACPI_AML_PACKAGE_TYPE3 0x400000
+#define ACPI_AML_PACKAGE_TYPE4 0x40000000
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_allocate_name_string
+ *
+ * PARAMETERS: prefix_count - Count of parent levels. Special cases:
+ * (-1) = root, 0 = none
+ * num_name_segs - count of 4-character name segments
+ *
+ * RETURN: A pointer to the allocated string segment. This segment must
+ * be deleted by the caller.
+ *
+ * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name
+ * string is long enough, and set up prefix if any.
+ *
+ ******************************************************************************/
+
+char *
+acpi_ex_allocate_name_string (
+ u32 prefix_count,
+ u32 num_name_segs)
+{
+ char *temp_ptr;
+ char *name_string;
+ u32 size_needed;
+
+ ACPI_FUNCTION_TRACE ("ex_allocate_name_string");
+
+
+ /*
+ * Allow room for all \ and ^ prefixes, all segments, and a multi_name_prefix.
+ * Also, one byte for the null terminator.
+ * This may actually be somewhat longer than needed.
+ */
+ if (prefix_count == ACPI_UINT32_MAX) {
+ /* Special case for root */
+
+ size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
+ }
+ else {
+ size_needed = prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
+ }
+
+ /*
+ * Allocate a buffer for the name.
+ * This buffer must be deleted by the caller!
+ */
+ name_string = ACPI_MEM_ALLOCATE (size_needed);
+ if (!name_string) {
+ ACPI_REPORT_ERROR (("ex_allocate_name_string: Could not allocate size %d\n", size_needed));
+ return_PTR (NULL);
+ }
+
+ temp_ptr = name_string;
+
+ /* Set up Root or Parent prefixes if needed */
+
+ if (prefix_count == ACPI_UINT32_MAX) {
+ *temp_ptr++ = AML_ROOT_PREFIX;
+ }
+ else {
+ while (prefix_count--) {
+ *temp_ptr++ = AML_PARENT_PREFIX;
+ }
+ }
+
+
+ /* Set up Dual or Multi prefixes if needed */
+
+ if (num_name_segs > 2) {
+ /* Set up multi prefixes */
+
+ *temp_ptr++ = AML_MULTI_NAME_PREFIX_OP;
+ *temp_ptr++ = (char) num_name_segs;
+ }
+ else if (2 == num_name_segs) {
+ /* Set up dual prefixes */
+
+ *temp_ptr++ = AML_DUAL_NAME_PREFIX;
+ }
+
+ /*
+ * Terminate string following prefixes. acpi_ex_name_segment() will
+ * append the segment(s)
+ */
+ *temp_ptr = 0;
+
+ return_PTR (name_string);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_name_segment
+ *
+ * PARAMETERS: interpreter_mode - Current running mode (load1/Load2/Exec)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a name segment (4 bytes)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_name_segment (
+ u8 **in_aml_address,
+ char *name_string)
+{
+ char *aml_address = (void *) *in_aml_address;
+ acpi_status status = AE_OK;
+ u32 index;
+ char char_buf[5];
+
+
+ ACPI_FUNCTION_TRACE ("ex_name_segment");
+
+
+ /*
+ * If first character is a digit, then we know that we aren't looking at a
+ * valid name segment
+ */
+ char_buf[0] = *aml_address;
+
+ if ('0' <= char_buf[0] && char_buf[0] <= '9') {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "leading digit: %c\n", char_buf[0]));
+ return_ACPI_STATUS (AE_CTRL_PENDING);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Bytes from stream:\n"));
+
+ for (index = 0;
+ (index < ACPI_NAME_SIZE) && (acpi_ut_valid_acpi_character (*aml_address));
+ index++) {
+ char_buf[index] = *aml_address++;
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "%c\n", char_buf[index]));
+ }
+
+
+ /* Valid name segment */
+
+ if (index == 4) {
+ /* Found 4 valid characters */
+
+ char_buf[4] = '\0';
+
+ if (name_string) {
+ ACPI_STRCAT (name_string, char_buf);
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Appended to - %s \n", name_string));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "No Name string - %s \n", char_buf));
+ }
+ }
+ else if (index == 0) {
+ /*
+ * First character was not a valid name character,
+ * so we are looking at something other than a name.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Leading character is not alpha: %02Xh (not a name)\n",
+ char_buf[0]));
+ status = AE_CTRL_PENDING;
+ }
+ else {
+ /* Segment started with one or more valid characters, but fewer than 4 */
+
+ status = AE_AML_BAD_NAME;
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad character %02x in name, at %p\n",
+ *aml_address, aml_address));
+ }
+
+ *in_aml_address = (u8 *) aml_address;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_get_name_string
+ *
+ * PARAMETERS: data_type - Data type to be associated with this name
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get a name, including any prefixes.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_get_name_string (
+ acpi_object_type data_type,
+ u8 *in_aml_address,
+ char **out_name_string,
+ u32 *out_name_length)
+{
+ acpi_status status = AE_OK;
+ u8 *aml_address = in_aml_address;
+ char *name_string = NULL;
+ u32 num_segments;
+ u32 prefix_count = 0;
+ u8 has_prefix = FALSE;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_get_name_string", aml_address);
+
+
+ if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type ||
+ ACPI_TYPE_LOCAL_BANK_FIELD == data_type ||
+ ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) {
+ /* Disallow prefixes for types associated with field_unit names */
+
+ name_string = acpi_ex_allocate_name_string (0, 1);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ }
+ else {
+ status = acpi_ex_name_segment (&aml_address, name_string);
+ }
+ }
+ else {
+ /*
+ * data_type is not a field name.
+ * Examine first character of name for root or parent prefix operators
+ */
+ switch (*aml_address) {
+ case AML_ROOT_PREFIX:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n", aml_address));
+
+ /*
+ * Remember that we have a root_prefix --
+ * see comment in acpi_ex_allocate_name_string()
+ */
+ aml_address++;
+ prefix_count = ACPI_UINT32_MAX;
+ has_prefix = TRUE;
+ break;
+
+
+ case AML_PARENT_PREFIX:
+
+ /* Increment past possibly multiple parent prefixes */
+
+ do {
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n", aml_address));
+
+ aml_address++;
+ prefix_count++;
+
+ } while (*aml_address == AML_PARENT_PREFIX);
+
+ has_prefix = TRUE;
+ break;
+
+
+ default:
+
+ /* Not a prefix character */
+
+ break;
+ }
+
+
+ /* Examine first character of name for name segment prefix operator */
+
+ switch (*aml_address) {
+ case AML_DUAL_NAME_PREFIX:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n", aml_address));
+
+ aml_address++;
+ name_string = acpi_ex_allocate_name_string (prefix_count, 2);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ /* Indicate that we processed a prefix */
+
+ has_prefix = TRUE;
+
+ status = acpi_ex_name_segment (&aml_address, name_string);
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ex_name_segment (&aml_address, name_string);
+ }
+ break;
+
+
+ case AML_MULTI_NAME_PREFIX_OP:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n", aml_address));
+
+ /* Fetch count of segments remaining in name path */
+
+ aml_address++;
+ num_segments = *aml_address;
+
+ name_string = acpi_ex_allocate_name_string (prefix_count, num_segments);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ /* Indicate that we processed a prefix */
+
+ aml_address++;
+ has_prefix = TRUE;
+
+ while (num_segments &&
+ (status = acpi_ex_name_segment (&aml_address, name_string)) == AE_OK) {
+ num_segments--;
+ }
+
+ break;
+
+
+ case 0:
+
+ /* null_name valid as of 8-12-98 ASL/AML Grammar Update */
+
+ if (prefix_count == ACPI_UINT32_MAX) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "name_seg is \"\\\" followed by NULL\n"));
+ }
+
+ /* Consume the NULL byte */
+
+ aml_address++;
+ name_string = acpi_ex_allocate_name_string (prefix_count, 0);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ break;
+
+
+ default:
+
+ /* Name segment string */
+
+ name_string = acpi_ex_allocate_name_string (prefix_count, 1);
+ if (!name_string) {
+ status = AE_NO_MEMORY;
+ break;
+ }
+
+ status = acpi_ex_name_segment (&aml_address, name_string);
+ break;
+ }
+ }
+
+ if (AE_CTRL_PENDING == status && has_prefix) {
+ /* Ran out of segments after processing a prefix */
+
+ ACPI_REPORT_ERROR (
+ ("ex_do_name: Malformed Name at %p\n", name_string));
+ status = AE_AML_BAD_NAME;
+ }
+
+ *out_name_string = name_string;
+ *out_name_length = (u32) (aml_address - in_aml_address);
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
new file mode 100644
index 000000000000..8482aefaf38b
--- /dev/null
+++ b/drivers/acpi/executer/exoparg1.c
@@ -0,0 +1,1013 @@
+
+/******************************************************************************
+ *
+ * Module Name: exoparg1 - AML execution - opcodes with 1 argument
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exoparg1")
+
+
+/*!
+ * Naming convention for AML interpreter execution routines.
+ *
+ * The routines that begin execution of AML opcodes are named with a common
+ * convention based upon the number of arguments, the number of target operands,
+ * and whether or not a value is returned:
+ *
+ * AcpiExOpcode_xA_yT_zR
+ *
+ * Where:
+ *
+ * xA - ARGUMENTS: The number of arguments (input operands) that are
+ * required for this opcode type (0 through 6 args).
+ * yT - TARGETS: The number of targets (output operands) that are required
+ * for this opcode type (0, 1, or 2 targets).
+ * zR - RETURN VALUE: Indicates whether this opcode type returns a value
+ * as the function return (0 or 1).
+ *
+ * The AcpiExOpcode* functions are called via the Dispatcher component with
+ * fully resolved operands.
+!*/
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_0A_0T_1R
+ *
+ * PARAMETERS: walk_state - Current state (contains AML opcode)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute operator with no operands, one return value
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_0A_0T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *return_desc = NULL;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /* Examine the AML opcode */
+
+ switch (walk_state->opcode) {
+ case AML_TIMER_OP: /* Timer () */
+
+ /* Create a return object of type Integer */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ return_desc->integer.value = acpi_os_get_timer ();
+ break;
+
+ default: /* Unknown opcode */
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_0A_0T_1R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+cleanup:
+
+ if (!walk_state->result_obj) {
+ walk_state->result_obj = return_desc;
+ }
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_1A_0T_0R
+ *
+ * PARAMETERS: walk_state - Current state (contains AML opcode)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Type 1 monadic operator with numeric operand on
+ * object stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_1A_0T_0R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /* Examine the AML opcode */
+
+ switch (walk_state->opcode) {
+ case AML_RELEASE_OP: /* Release (mutex_object) */
+
+ status = acpi_ex_release_mutex (operand[0], walk_state);
+ break;
+
+
+ case AML_RESET_OP: /* Reset (event_object) */
+
+ status = acpi_ex_system_reset_event (operand[0]);
+ break;
+
+
+ case AML_SIGNAL_OP: /* Signal (event_object) */
+
+ status = acpi_ex_system_signal_event (operand[0]);
+ break;
+
+
+ case AML_SLEEP_OP: /* Sleep (msec_time) */
+
+ status = acpi_ex_system_do_suspend (operand[0]->integer.value);
+ break;
+
+
+ case AML_STALL_OP: /* Stall (usec_time) */
+
+ status = acpi_ex_system_do_stall ((u32) operand[0]->integer.value);
+ break;
+
+
+ case AML_UNLOAD_OP: /* Unload (Handle) */
+
+ status = acpi_ex_unload_table (operand[0]);
+ break;
+
+
+ default: /* Unknown opcode */
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_0T_0R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_1A_1T_0R
+ *
+ * PARAMETERS: walk_state - Current state (contains AML opcode)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute opcode with one argument, one target, and no
+ * return value.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_1A_1T_0R (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /* Examine the AML opcode */
+
+ switch (walk_state->opcode) {
+ case AML_LOAD_OP:
+
+ status = acpi_ex_load_op (operand[0], operand[1], walk_state);
+ break;
+
+ default: /* Unknown opcode */
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_1T_0R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+cleanup:
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_1A_1T_1R
+ *
+ * PARAMETERS: walk_state - Current state (contains AML opcode)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute opcode with one argument, one target, and a
+ * return value.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_1A_1T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *return_desc = NULL;
+ union acpi_operand_object *return_desc2 = NULL;
+ u32 temp32;
+ u32 i;
+ acpi_integer power_of_ten;
+ acpi_integer digit;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /* Examine the AML opcode */
+
+ switch (walk_state->opcode) {
+ case AML_BIT_NOT_OP:
+ case AML_FIND_SET_LEFT_BIT_OP:
+ case AML_FIND_SET_RIGHT_BIT_OP:
+ case AML_FROM_BCD_OP:
+ case AML_TO_BCD_OP:
+ case AML_COND_REF_OF_OP:
+
+ /* Create a return object of type Integer for these opcodes */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ switch (walk_state->opcode) {
+ case AML_BIT_NOT_OP: /* Not (Operand, Result) */
+
+ return_desc->integer.value = ~operand[0]->integer.value;
+ break;
+
+
+ case AML_FIND_SET_LEFT_BIT_OP: /* find_set_left_bit (Operand, Result) */
+
+ return_desc->integer.value = operand[0]->integer.value;
+
+ /*
+ * Acpi specification describes Integer type as a little
+ * endian unsigned value, so this boundary condition is valid.
+ */
+ for (temp32 = 0; return_desc->integer.value &&
+ temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) {
+ return_desc->integer.value >>= 1;
+ }
+
+ return_desc->integer.value = temp32;
+ break;
+
+
+ case AML_FIND_SET_RIGHT_BIT_OP: /* find_set_right_bit (Operand, Result) */
+
+ return_desc->integer.value = operand[0]->integer.value;
+
+ /*
+ * The Acpi specification describes Integer type as a little
+ * endian unsigned value, so this boundary condition is valid.
+ */
+ for (temp32 = 0; return_desc->integer.value &&
+ temp32 < ACPI_INTEGER_BIT_SIZE; ++temp32) {
+ return_desc->integer.value <<= 1;
+ }
+
+ /* Since the bit position is one-based, subtract from 33 (65) */
+
+ return_desc->integer.value = temp32 == 0 ? 0 :
+ (ACPI_INTEGER_BIT_SIZE + 1) - temp32;
+ break;
+
+
+ case AML_FROM_BCD_OP: /* from_bcd (BCDValue, Result) */
+
+ /*
+ * The 64-bit ACPI integer can hold 16 4-bit BCD characters
+ * (if table is 32-bit, integer can hold 8 BCD characters)
+ * Convert each 4-bit BCD value
+ */
+ power_of_ten = 1;
+ return_desc->integer.value = 0;
+ digit = operand[0]->integer.value;
+
+ /* Convert each BCD digit (each is one nybble wide) */
+
+ for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) {
+ /* Get the least significant 4-bit BCD digit */
+
+ temp32 = ((u32) digit) & 0xF;
+
+ /* Check the range of the digit */
+
+ if (temp32 > 9) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "BCD digit too large (not decimal): 0x%X\n",
+ temp32));
+
+ status = AE_AML_NUMERIC_OVERFLOW;
+ goto cleanup;
+ }
+
+ /* Sum the digit into the result with the current power of 10 */
+
+ return_desc->integer.value += (((acpi_integer) temp32) *
+ power_of_ten);
+
+ /* Shift to next BCD digit */
+
+ digit >>= 4;
+
+ /* Next power of 10 */
+
+ power_of_ten *= 10;
+ }
+ break;
+
+
+ case AML_TO_BCD_OP: /* to_bcd (Operand, Result) */
+
+ return_desc->integer.value = 0;
+ digit = operand[0]->integer.value;
+
+ /* Each BCD digit is one nybble wide */
+
+ for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) {
+ (void) acpi_ut_short_divide (digit, 10, &digit, &temp32);
+
+ /* Insert the BCD digit that resides in the remainder from above */
+
+ return_desc->integer.value |= (((acpi_integer) temp32) <<
+ ACPI_MUL_4 (i));
+ }
+
+ /* Overflow if there is any data left in Digit */
+
+ if (digit > 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Integer too large to convert to BCD: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (operand[0]->integer.value)));
+ status = AE_AML_NUMERIC_OVERFLOW;
+ goto cleanup;
+ }
+ break;
+
+
+ case AML_COND_REF_OF_OP: /* cond_ref_of (source_object, Result) */
+
+ /*
+ * This op is a little strange because the internal return value is
+ * different than the return value stored in the result descriptor
+ * (There are really two return values)
+ */
+ if ((struct acpi_namespace_node *) operand[0] == acpi_gbl_root_node) {
+ /*
+ * This means that the object does not exist in the namespace,
+ * return FALSE
+ */
+ return_desc->integer.value = 0;
+ goto cleanup;
+ }
+
+ /* Get the object reference, store it, and remove our reference */
+
+ status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_ex_store (return_desc2, operand[1], walk_state);
+ acpi_ut_remove_reference (return_desc2);
+
+ /* The object exists in the namespace, return TRUE */
+
+ return_desc->integer.value = ACPI_INTEGER_MAX;
+ goto cleanup;
+
+
+ default:
+ /* No other opcodes get here */
+ break;
+ }
+ break;
+
+
+ case AML_STORE_OP: /* Store (Source, Target) */
+
+ /*
+ * A store operand is typically a number, string, buffer or lvalue
+ * Be careful about deleting the source object,
+ * since the object itself may have been stored.
+ */
+ status = acpi_ex_store (operand[0], operand[1], walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* It is possible that the Store already produced a return object */
+
+ if (!walk_state->result_obj) {
+ /*
+ * Normally, we would remove a reference on the Operand[0] parameter;
+ * But since it is being used as the internal return object
+ * (meaning we would normally increment it), the two cancel out,
+ * and we simply don't do anything.
+ */
+ walk_state->result_obj = operand[0];
+ walk_state->operands[0] = NULL; /* Prevent deletion */
+ }
+ return_ACPI_STATUS (status);
+
+
+ /*
+ * ACPI 2.0 Opcodes
+ */
+ case AML_COPY_OP: /* Copy (Source, Target) */
+
+ status = acpi_ut_copy_iobject_to_iobject (operand[0], &return_desc,
+ walk_state);
+ break;
+
+
+ case AML_TO_DECSTRING_OP: /* to_decimal_string (Data, Result) */
+
+ status = acpi_ex_convert_to_string (operand[0], &return_desc,
+ ACPI_EXPLICIT_CONVERT_DECIMAL);
+ if (return_desc == operand[0]) {
+ /* No conversion performed, add ref to handle return value */
+ acpi_ut_add_reference (return_desc);
+ }
+ break;
+
+
+ case AML_TO_HEXSTRING_OP: /* to_hex_string (Data, Result) */
+
+ status = acpi_ex_convert_to_string (operand[0], &return_desc,
+ ACPI_EXPLICIT_CONVERT_HEX);
+ if (return_desc == operand[0]) {
+ /* No conversion performed, add ref to handle return value */
+ acpi_ut_add_reference (return_desc);
+ }
+ break;
+
+
+ case AML_TO_BUFFER_OP: /* to_buffer (Data, Result) */
+
+ status = acpi_ex_convert_to_buffer (operand[0], &return_desc);
+ if (return_desc == operand[0]) {
+ /* No conversion performed, add ref to handle return value */
+ acpi_ut_add_reference (return_desc);
+ }
+ break;
+
+
+ case AML_TO_INTEGER_OP: /* to_integer (Data, Result) */
+
+ status = acpi_ex_convert_to_integer (operand[0], &return_desc,
+ ACPI_ANY_BASE);
+ if (return_desc == operand[0]) {
+ /* No conversion performed, add ref to handle return value */
+ acpi_ut_add_reference (return_desc);
+ }
+ break;
+
+
+ case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */
+ case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */
+
+ /*
+ * These are two obsolete opcodes
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "%s is obsolete and not implemented\n",
+ acpi_ps_get_opcode_name (walk_state->opcode)));
+ status = AE_SUPPORT;
+ goto cleanup;
+
+
+ default: /* Unknown opcode */
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_1T_1R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Store the return value computed above into the target object
+ */
+ status = acpi_ex_store (return_desc, operand[1], walk_state);
+ }
+
+
+cleanup:
+
+ if (!walk_state->result_obj) {
+ walk_state->result_obj = return_desc;
+ }
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_1A_0T_1R
+ *
+ * PARAMETERS: walk_state - Current state (contains AML opcode)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute opcode with one argument, no target, and a return value
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_1A_0T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *temp_desc;
+ union acpi_operand_object *return_desc = NULL;
+ acpi_status status = AE_OK;
+ u32 type;
+ acpi_integer value;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /* Examine the AML opcode */
+
+ switch (walk_state->opcode) {
+ case AML_LNOT_OP: /* LNot (Operand) */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Set result to ONES (TRUE) if Value == 0. Note:
+ * return_desc->Integer.Value is initially == 0 (FALSE) from above.
+ */
+ if (!operand[0]->integer.value) {
+ return_desc->integer.value = ACPI_INTEGER_MAX;
+ }
+ break;
+
+
+ case AML_DECREMENT_OP: /* Decrement (Operand) */
+ case AML_INCREMENT_OP: /* Increment (Operand) */
+
+ /*
+ * Create a new integer. Can't just get the base integer and
+ * increment it because it may be an Arg or Field.
+ */
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Since we are expecting a Reference operand, it can be either a
+ * NS Node or an internal object.
+ */
+ temp_desc = operand[0];
+ if (ACPI_GET_DESCRIPTOR_TYPE (temp_desc) == ACPI_DESC_TYPE_OPERAND) {
+ /* Internal reference object - prevent deletion */
+
+ acpi_ut_add_reference (temp_desc);
+ }
+
+ /*
+ * Convert the Reference operand to an Integer (This removes a
+ * reference on the Operand[0] object)
+ *
+ * NOTE: We use LNOT_OP here in order to force resolution of the
+ * reference operand to an actual integer.
+ */
+ status = acpi_ex_resolve_operands (AML_LNOT_OP, &temp_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%s: bad operand(s) %s\n",
+ acpi_ps_get_opcode_name (walk_state->opcode),
+ acpi_format_exception(status)));
+
+ goto cleanup;
+ }
+
+ /*
+ * temp_desc is now guaranteed to be an Integer object --
+ * Perform the actual increment or decrement
+ */
+ if (walk_state->opcode == AML_INCREMENT_OP) {
+ return_desc->integer.value = temp_desc->integer.value +1;
+ }
+ else {
+ return_desc->integer.value = temp_desc->integer.value -1;
+ }
+
+ /* Finished with this Integer object */
+
+ acpi_ut_remove_reference (temp_desc);
+
+ /*
+ * Store the result back (indirectly) through the original
+ * Reference object
+ */
+ status = acpi_ex_store (return_desc, operand[0], walk_state);
+ break;
+
+
+ case AML_TYPE_OP: /* object_type (source_object) */
+
+ /*
+ * Note: The operand is not resolved at this point because we want to
+ * get the associated object, not its value. For example, we don't want
+ * to resolve a field_unit to its value, we want the actual field_unit
+ * object.
+ */
+
+ /* Get the type of the base object */
+
+ status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, NULL);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ /* Allocate a descriptor to hold the type. */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ return_desc->integer.value = type;
+ break;
+
+
+ case AML_SIZE_OF_OP: /* size_of (source_object) */
+
+ /*
+ * Note: The operand is not resolved at this point because we want to
+ * get the associated object, not its value.
+ */
+
+ /* Get the base object */
+
+ status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * The type of the base object must be integer, buffer, string, or
+ * package. All others are not supported.
+ *
+ * NOTE: Integer is not specifically supported by the ACPI spec,
+ * but is supported implicitly via implicit operand conversion.
+ * rather than bother with conversion, we just use the byte width
+ * global (4 or 8 bytes).
+ */
+ switch (type) {
+ case ACPI_TYPE_INTEGER:
+ value = acpi_gbl_integer_byte_width;
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ value = temp_desc->buffer.length;
+ break;
+
+ case ACPI_TYPE_STRING:
+ value = temp_desc->string.length;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ value = temp_desc->package.count;
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "size_of - Operand is not Buf/Int/Str/Pkg - found type %s\n",
+ acpi_ut_get_type_name (type)));
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+
+ /*
+ * Now that we have the size of the object, create a result
+ * object to hold the value
+ */
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ return_desc->integer.value = value;
+ break;
+
+
+ case AML_REF_OF_OP: /* ref_of (source_object) */
+
+ status = acpi_ex_get_object_reference (operand[0], &return_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ break;
+
+
+ case AML_DEREF_OF_OP: /* deref_of (obj_reference | String) */
+
+ /* Check for a method local or argument, or standalone String */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) != ACPI_DESC_TYPE_NAMED) {
+ switch (ACPI_GET_OBJECT_TYPE (operand[0])) {
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ /*
+ * This is a deref_of (local_x | arg_x)
+ *
+ * Must resolve/dereference the local/arg reference first
+ */
+ switch (operand[0]->reference.opcode) {
+ case AML_LOCAL_OP:
+ case AML_ARG_OP:
+
+ /* Set Operand[0] to the value of the local/arg */
+
+ status = acpi_ds_method_data_get_value (operand[0]->reference.opcode,
+ operand[0]->reference.offset, walk_state, &temp_desc);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /*
+ * Delete our reference to the input object and
+ * point to the object just retrieved
+ */
+ acpi_ut_remove_reference (operand[0]);
+ operand[0] = temp_desc;
+ break;
+
+ case AML_REF_OF_OP:
+
+ /* Get the object to which the reference refers */
+
+ temp_desc = operand[0]->reference.object;
+ acpi_ut_remove_reference (operand[0]);
+ operand[0] = temp_desc;
+ break;
+
+ default:
+
+ /* Must be an Index op - handled below */
+ break;
+ }
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ /*
+ * This is a deref_of (String). The string is a reference to a named ACPI object.
+ *
+ * 1) Find the owning Node
+ * 2) Dereference the node to an actual object. Could be a Field, so we nee
+ * to resolve the node to a value.
+ */
+ status = acpi_ns_get_node_by_path (operand[0]->string.pointer,
+ walk_state->scope_info->scope.node, ACPI_NS_SEARCH_PARENT,
+ ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc));
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_ex_resolve_node_to_value (
+ ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc), walk_state);
+ goto cleanup;
+
+
+ default:
+
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ }
+
+ /* Operand[0] may have changed from the code above */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (operand[0]) == ACPI_DESC_TYPE_NAMED) {
+ /*
+ * This is a deref_of (object_reference)
+ * Get the actual object from the Node (This is the dereference).
+ * -- This case may only happen when a local_x or arg_x is dereferenced above.
+ */
+ return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) operand[0]);
+ }
+ else {
+ /*
+ * This must be a reference object produced by either the Index() or
+ * ref_of() operator
+ */
+ switch (operand[0]->reference.opcode) {
+ case AML_INDEX_OP:
+
+ /*
+ * The target type for the Index operator must be
+ * either a Buffer or a Package
+ */
+ switch (operand[0]->reference.target_type) {
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ temp_desc = operand[0]->reference.object;
+
+ /*
+ * Create a new object that contains one element of the
+ * buffer -- the element pointed to by the index.
+ *
+ * NOTE: index into a buffer is NOT a pointer to a
+ * sub-buffer of the main buffer, it is only a pointer to a
+ * single element (byte) of the buffer!
+ */
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Since we are returning the value of the buffer at the
+ * indexed location, we don't need to add an additional
+ * reference to the buffer itself.
+ */
+ return_desc->integer.value =
+ temp_desc->buffer.pointer[operand[0]->reference.offset];
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * Return the referenced element of the package. We must add
+ * another reference to the referenced object, however.
+ */
+ return_desc = *(operand[0]->reference.where);
+ if (!return_desc) {
+ /*
+ * We can't return a NULL dereferenced value. This is
+ * an uninitialized package element and is thus a
+ * severe error.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "NULL package element obj %p\n",
+ operand[0]));
+ status = AE_AML_UNINITIALIZED_ELEMENT;
+ goto cleanup;
+ }
+
+ acpi_ut_add_reference (return_desc);
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown Index target_type %X in obj %p\n",
+ operand[0]->reference.target_type, operand[0]));
+ status = AE_AML_OPERAND_TYPE;
+ goto cleanup;
+ }
+ break;
+
+
+ case AML_REF_OF_OP:
+
+ return_desc = operand[0]->reference.object;
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == ACPI_DESC_TYPE_NAMED) {
+
+ return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) return_desc);
+ }
+
+ /* Add another reference to the object! */
+
+ acpi_ut_add_reference (return_desc);
+ break;
+
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown opcode in ref(%p) - %X\n",
+ operand[0], operand[0]->reference.opcode));
+
+ status = AE_TYPE;
+ goto cleanup;
+ }
+ }
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_1A_0T_1R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+cleanup:
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ }
+
+ walk_state->result_obj = return_desc;
+ return_ACPI_STATUS (status);
+}
+
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
new file mode 100644
index 000000000000..8be4d80ceed5
--- /dev/null
+++ b/drivers/acpi/executer/exoparg2.c
@@ -0,0 +1,608 @@
+/******************************************************************************
+ *
+ * Module Name: exoparg2 - AML execution - opcodes with 2 arguments
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/acinterp.h>
+#include <acpi/acevents.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exoparg2")
+
+
+/*!
+ * Naming convention for AML interpreter execution routines.
+ *
+ * The routines that begin execution of AML opcodes are named with a common
+ * convention based upon the number of arguments, the number of target operands,
+ * and whether or not a value is returned:
+ *
+ * AcpiExOpcode_xA_yT_zR
+ *
+ * Where:
+ *
+ * xA - ARGUMENTS: The number of arguments (input operands) that are
+ * required for this opcode type (1 through 6 args).
+ * yT - TARGETS: The number of targets (output operands) that are required
+ * for this opcode type (0, 1, or 2 targets).
+ * zR - RETURN VALUE: Indicates whether this opcode type returns a value
+ * as the function return (0 or 1).
+ *
+ * The AcpiExOpcode* functions are called via the Dispatcher component with
+ * fully resolved operands.
+!*/
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_2A_0T_0R
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute opcode with two arguments, no target, and no return
+ * value.
+ *
+ * ALLOCATION: Deletes both operands
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_2A_0T_0R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ struct acpi_namespace_node *node;
+ u32 value;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_0T_0R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /* Examine the opcode */
+
+ switch (walk_state->opcode) {
+ case AML_NOTIFY_OP: /* Notify (notify_object, notify_value) */
+
+ /* The first operand is a namespace node */
+
+ node = (struct acpi_namespace_node *) operand[0];
+
+ /* Second value is the notify value */
+
+ value = (u32) operand[1]->integer.value;
+
+ /* Notifies allowed on this object? */
+
+ if (!acpi_ev_is_notify_object (node)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unexpected notify object type [%s]\n",
+ acpi_ut_get_type_name (node->type)));
+
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+#ifdef ACPI_GPE_NOTIFY_CHECK
+ /*
+ * GPE method wake/notify check. Here, we want to ensure that we
+ * don't receive any "device_wake" Notifies from a GPE _Lxx or _Exx
+ * GPE method during system runtime. If we do, the GPE is marked
+ * as "wake-only" and disabled.
+ *
+ * 1) Is the Notify() value == device_wake?
+ * 2) Is this a GPE deferred method? (An _Lxx or _Exx method)
+ * 3) Did the original GPE happen at system runtime?
+ * (versus during wake)
+ *
+ * If all three cases are true, this is a wake-only GPE that should
+ * be disabled at runtime.
+ */
+ if (value == 2) /* device_wake */ {
+ status = acpi_ev_check_for_wake_only_gpe (walk_state->gpe_event_info);
+ if (ACPI_FAILURE (status)) {
+ /* AE_WAKE_ONLY_GPE only error, means ignore this notify */
+
+ return_ACPI_STATUS (AE_OK)
+ }
+ }
+#endif
+
+ /*
+ * Dispatch the notify to the appropriate handler
+ * NOTE: the request is queued for execution after this method
+ * completes. The notify handlers are NOT invoked synchronously
+ * from this thread -- because handlers may in turn run other
+ * control methods.
+ */
+ status = acpi_ev_queue_notify_request (node, value);
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_0T_0R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_2A_2T_1R
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a dyadic operator (2 operands) with 2 output targets
+ * and one implicit return value.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_2A_2T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *return_desc1 = NULL;
+ union acpi_operand_object *return_desc2 = NULL;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_2T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /*
+ * Execute the opcode
+ */
+ switch (walk_state->opcode) {
+ case AML_DIVIDE_OP: /* Divide (Dividend, Divisor, remainder_result quotient_result) */
+
+ return_desc1 = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc1) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ return_desc2 = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc2) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Quotient to return_desc1, remainder to return_desc2 */
+
+ status = acpi_ut_divide (operand[0]->integer.value,
+ operand[1]->integer.value,
+ &return_desc1->integer.value,
+ &return_desc2->integer.value);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_2T_1R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+ /* Store the results to the target reference operands */
+
+ status = acpi_ex_store (return_desc2, operand[2], walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_ex_store (return_desc1, operand[3], walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Return the remainder */
+
+ walk_state->result_obj = return_desc1;
+
+
+cleanup:
+ /*
+ * Since the remainder is not returned indirectly, remove a reference to
+ * it. Only the quotient is returned indirectly.
+ */
+ acpi_ut_remove_reference (return_desc2);
+
+ if (ACPI_FAILURE (status)) {
+ /* Delete the return object */
+
+ acpi_ut_remove_reference (return_desc1);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_2A_1T_1R
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute opcode with two arguments, one target, and a return
+ * value.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_2A_1T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *return_desc = NULL;
+ u32 index;
+ acpi_status status = AE_OK;
+ acpi_size length;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_1T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /*
+ * Execute the opcode
+ */
+ if (walk_state->op_info->flags & AML_MATH) {
+ /* All simple math opcodes (add, etc.) */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ return_desc->integer.value = acpi_ex_do_math_op (walk_state->opcode,
+ operand[0]->integer.value,
+ operand[1]->integer.value);
+ goto store_result_to_target;
+ }
+
+
+ switch (walk_state->opcode) {
+ case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* return_desc will contain the remainder */
+
+ status = acpi_ut_divide (operand[0]->integer.value,
+ operand[1]->integer.value,
+ NULL,
+ &return_desc->integer.value);
+ break;
+
+
+ case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */
+
+ status = acpi_ex_do_concatenate (operand[0], operand[1],
+ &return_desc, walk_state);
+ break;
+
+
+ case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */
+
+ /*
+ * Input object is guaranteed to be a buffer at this point (it may have
+ * been converted.) Copy the raw buffer data to a new object of type String.
+ */
+
+ /*
+ * Get the length of the new string. It is the smallest of:
+ * 1) Length of the input buffer
+ * 2) Max length as specified in the to_string operator
+ * 3) Length of input buffer up to a zero byte (null terminator)
+ *
+ * NOTE: A length of zero is ok, and will create a zero-length, null
+ * terminated string.
+ */
+ length = 0;
+ while ((length < operand[0]->buffer.length) &&
+ (length < operand[1]->integer.value) &&
+ (operand[0]->buffer.pointer[length])) {
+ length++;
+ if (length > ACPI_MAX_STRING_CONVERSION) {
+ status = AE_AML_STRING_LIMIT;
+ goto cleanup;
+ }
+ }
+
+ /* Allocate a new string object */
+
+ return_desc = acpi_ut_create_string_object (length);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Copy the raw buffer data with no transform. NULL terminated already. */
+
+ ACPI_MEMCPY (return_desc->string.pointer,
+ operand[0]->buffer.pointer, length);
+ break;
+
+
+ case AML_CONCAT_RES_OP: /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */
+
+ status = acpi_ex_concat_template (operand[0], operand[1],
+ &return_desc, walk_state);
+ break;
+
+
+ case AML_INDEX_OP: /* Index (Source Index Result) */
+
+ /* Create the internal return object */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_REFERENCE);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ index = (u32) operand[1]->integer.value;
+
+ /*
+ * At this point, the Source operand is a Package, Buffer, or String
+ */
+ if (ACPI_GET_OBJECT_TYPE (operand[0]) == ACPI_TYPE_PACKAGE) {
+ /* Object to be indexed is a Package */
+
+ if (index >= operand[0]->package.count) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Index value (%X) beyond package end (%X)\n",
+ index, operand[0]->package.count));
+ status = AE_AML_PACKAGE_LIMIT;
+ goto cleanup;
+ }
+
+ return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
+ return_desc->reference.object = operand[0];
+ return_desc->reference.where = &operand[0]->package.elements [index];
+ }
+ else {
+ /* Object to be indexed is a Buffer/String */
+
+ if (index >= operand[0]->buffer.length) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Index value (%X) beyond end of buffer (%X)\n",
+ index, operand[0]->buffer.length));
+ status = AE_AML_BUFFER_LIMIT;
+ goto cleanup;
+ }
+
+ return_desc->reference.target_type = ACPI_TYPE_BUFFER_FIELD;
+ return_desc->reference.object = operand[0];
+ }
+
+ /*
+ * Add a reference to the target package/buffer/string for the life
+ * of the index.
+ */
+ acpi_ut_add_reference (operand[0]);
+
+ /* Complete the Index reference object */
+
+ return_desc->reference.opcode = AML_INDEX_OP;
+ return_desc->reference.offset = index;
+
+ /* Store the reference to the Target */
+
+ status = acpi_ex_store (return_desc, operand[2], walk_state);
+
+ /* Return the reference */
+
+ walk_state->result_obj = return_desc;
+ goto cleanup;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_1T_1R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ break;
+ }
+
+
+store_result_to_target:
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Store the result of the operation (which is now in return_desc) into
+ * the Target descriptor.
+ */
+ status = acpi_ex_store (return_desc, operand[2], walk_state);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ if (!walk_state->result_obj) {
+ walk_state->result_obj = return_desc;
+ }
+ }
+
+
+cleanup:
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_2A_0T_1R
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute opcode with 2 arguments, no target, and a return value
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_2A_0T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *return_desc = NULL;
+ acpi_status status = AE_OK;
+ u8 logical_result = FALSE;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_2A_0T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ /* Create the internal return object */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /*
+ * Execute the Opcode
+ */
+ if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) /* logical_op (Operand0, Operand1) */ {
+ status = acpi_ex_do_logical_numeric_op (walk_state->opcode,
+ operand[0]->integer.value, operand[1]->integer.value,
+ &logical_result);
+ goto store_logical_result;
+ }
+ else if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ {
+ status = acpi_ex_do_logical_op (walk_state->opcode, operand[0],
+ operand[1], &logical_result);
+ goto store_logical_result;
+ }
+
+
+ switch (walk_state->opcode) {
+ case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */
+
+ status = acpi_ex_acquire_mutex (operand[1], operand[0], walk_state);
+ if (status == AE_TIME) {
+ logical_result = TRUE; /* TRUE = Acquire timed out */
+ status = AE_OK;
+ }
+ break;
+
+
+ case AML_WAIT_OP: /* Wait (event_object, Timeout) */
+
+ status = acpi_ex_system_wait_event (operand[1], operand[0]);
+ if (status == AE_TIME) {
+ logical_result = TRUE; /* TRUE, Wait timed out */
+ status = AE_OK;
+ }
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_2A_0T_1R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+store_logical_result:
+ /*
+ * Set return value to according to logical_result. logical TRUE (all ones)
+ * Default is FALSE (zero)
+ */
+ if (logical_result) {
+ return_desc->integer.value = ACPI_INTEGER_MAX;
+ }
+
+ walk_state->result_obj = return_desc;
+
+
+cleanup:
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
new file mode 100644
index 000000000000..29d0b167745d
--- /dev/null
+++ b/drivers/acpi/executer/exoparg3.c
@@ -0,0 +1,256 @@
+
+/******************************************************************************
+ *
+ * Module Name: exoparg3 - AML execution - opcodes with 3 arguments
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exoparg3")
+
+
+/*!
+ * Naming convention for AML interpreter execution routines.
+ *
+ * The routines that begin execution of AML opcodes are named with a common
+ * convention based upon the number of arguments, the number of target operands,
+ * and whether or not a value is returned:
+ *
+ * AcpiExOpcode_xA_yT_zR
+ *
+ * Where:
+ *
+ * xA - ARGUMENTS: The number of arguments (input operands) that are
+ * required for this opcode type (1 through 6 args).
+ * yT - TARGETS: The number of targets (output operands) that are required
+ * for this opcode type (0, 1, or 2 targets).
+ * zR - RETURN VALUE: Indicates whether this opcode type returns a value
+ * as the function return (0 or 1).
+ *
+ * The AcpiExOpcode* functions are called via the Dispatcher component with
+ * fully resolved operands.
+!*/
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_3A_0T_0R
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Triadic operator (3 operands)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_3A_0T_0R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ struct acpi_signal_fatal_info *fatal;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ switch (walk_state->opcode) {
+ case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
+ (u32) operand[0]->integer.value,
+ (u32) operand[1]->integer.value,
+ (u32) operand[2]->integer.value));
+
+ fatal = ACPI_MEM_ALLOCATE (sizeof (struct acpi_signal_fatal_info));
+ if (fatal) {
+ fatal->type = (u32) operand[0]->integer.value;
+ fatal->code = (u32) operand[1]->integer.value;
+ fatal->argument = (u32) operand[2]->integer.value;
+ }
+
+ /*
+ * Always signal the OS!
+ */
+ status = acpi_os_signal (ACPI_SIGNAL_FATAL, fatal);
+
+ /* Might return while OS is shutting down, just continue */
+
+ ACPI_MEM_FREE (fatal);
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+cleanup:
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_3A_1T_1R
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute Triadic operator (3 operands)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_3A_1T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *return_desc = NULL;
+ char *buffer;
+ acpi_status status = AE_OK;
+ acpi_native_uint index;
+ acpi_size length;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ switch (walk_state->opcode) {
+ case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */
+
+ /*
+ * Create the return object. The Source operand is guaranteed to be
+ * either a String or a Buffer, so just use its type.
+ */
+ return_desc = acpi_ut_create_internal_object (ACPI_GET_OBJECT_TYPE (operand[0]));
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Get the Integer values from the objects */
+
+ index = (acpi_native_uint) operand[1]->integer.value;
+ length = (acpi_size) operand[2]->integer.value;
+
+ /*
+ * If the index is beyond the length of the String/Buffer, or if the
+ * requested length is zero, return a zero-length String/Buffer
+ */
+ if ((index < operand[0]->string.length) &&
+ (length > 0)) {
+ /* Truncate request if larger than the actual String/Buffer */
+
+ if ((index + length) >
+ operand[0]->string.length) {
+ length = (acpi_size) operand[0]->string.length - index;
+ }
+
+ /* Allocate a new buffer for the String/Buffer */
+
+ buffer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1);
+ if (!buffer) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Copy the portion requested */
+
+ ACPI_MEMCPY (buffer, operand[0]->string.pointer + index,
+ length);
+
+ /* Set the length of the new String/Buffer */
+
+ return_desc->string.pointer = buffer;
+ return_desc->string.length = (u32) length;
+ }
+
+ /* Mark buffer initialized */
+
+ return_desc->buffer.flags |= AOPOBJ_DATA_VALID;
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+ /* Store the result in the target */
+
+ status = acpi_ex_store (return_desc, operand[3], walk_state);
+
+cleanup:
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ }
+
+ /* Set the return object and exit */
+
+ if (!walk_state->result_obj) {
+ walk_state->result_obj = return_desc;
+ }
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
new file mode 100644
index 000000000000..d32624331626
--- /dev/null
+++ b/drivers/acpi/executer/exoparg6.c
@@ -0,0 +1,336 @@
+
+/******************************************************************************
+ *
+ * Module Name: exoparg6 - AML execution - opcodes with 6 arguments
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exoparg6")
+
+
+/*!
+ * Naming convention for AML interpreter execution routines.
+ *
+ * The routines that begin execution of AML opcodes are named with a common
+ * convention based upon the number of arguments, the number of target operands,
+ * and whether or not a value is returned:
+ *
+ * AcpiExOpcode_xA_yT_zR
+ *
+ * Where:
+ *
+ * xA - ARGUMENTS: The number of arguments (input operands) that are
+ * required for this opcode type (1 through 6 args).
+ * yT - TARGETS: The number of targets (output operands) that are required
+ * for this opcode type (0, 1, or 2 targets).
+ * zR - RETURN VALUE: Indicates whether this opcode type returns a value
+ * as the function return (0 or 1).
+ *
+ * The AcpiExOpcode* functions are called via the Dispatcher component with
+ * fully resolved operands.
+!*/
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_do_match
+ *
+ * PARAMETERS: match_op - The AML match operand
+ * package_obj - Object from the target package
+ * match_obj - Object to be matched
+ *
+ * RETURN: TRUE if the match is successful, FALSE otherwise
+ *
+ * DESCRIPTION: Implements the low-level match for the ASL Match operator.
+ * Package elements will be implicitly converted to the type of
+ * the match object (Integer/Buffer/String).
+ *
+ ******************************************************************************/
+
+u8
+acpi_ex_do_match (
+ u32 match_op,
+ union acpi_operand_object *package_obj,
+ union acpi_operand_object *match_obj)
+{
+ u8 logical_result = TRUE;
+ acpi_status status;
+
+
+ /*
+ * Note: Since the package_obj/match_obj ordering is opposite to that of
+ * the standard logical operators, we have to reverse them when we call
+ * do_logical_op in order to make the implicit conversion rules work
+ * correctly. However, this means we have to flip the entire equation
+ * also. A bit ugly perhaps, but overall, better than fussing the
+ * parameters around at runtime, over and over again.
+ *
+ * Below, P[i] refers to the package element, M refers to the Match object.
+ */
+ switch (match_op) {
+ case MATCH_MTR:
+
+ /* Always true */
+
+ break;
+
+ case MATCH_MEQ:
+
+ /*
+ * True if equal: (P[i] == M)
+ * Change to: (M == P[i])
+ */
+ status = acpi_ex_do_logical_op (AML_LEQUAL_OP, match_obj, package_obj,
+ &logical_result);
+ if (ACPI_FAILURE (status)) {
+ return (FALSE);
+ }
+ break;
+
+ case MATCH_MLE:
+
+ /*
+ * True if less than or equal: (P[i] <= M) (P[i] not_greater than M)
+ * Change to: (M >= P[i]) (M not_less than P[i])
+ */
+ status = acpi_ex_do_logical_op (AML_LLESS_OP, match_obj, package_obj,
+ &logical_result);
+ if (ACPI_FAILURE (status)) {
+ return (FALSE);
+ }
+ logical_result = (u8) !logical_result;
+ break;
+
+ case MATCH_MLT:
+
+ /*
+ * True if less than: (P[i] < M)
+ * Change to: (M > P[i])
+ */
+ status = acpi_ex_do_logical_op (AML_LGREATER_OP, match_obj, package_obj,
+ &logical_result);
+ if (ACPI_FAILURE (status)) {
+ return (FALSE);
+ }
+ break;
+
+ case MATCH_MGE:
+
+ /*
+ * True if greater than or equal: (P[i] >= M) (P[i] not_less than M)
+ * Change to: (M <= P[i]) (M not_greater than P[i])
+ */
+ status = acpi_ex_do_logical_op (AML_LGREATER_OP, match_obj, package_obj,
+ &logical_result);
+ if (ACPI_FAILURE (status)) {
+ return (FALSE);
+ }
+ logical_result = (u8)!logical_result;
+ break;
+
+ case MATCH_MGT:
+
+ /*
+ * True if greater than: (P[i] > M)
+ * Change to: (M < P[i])
+ */
+ status = acpi_ex_do_logical_op (AML_LLESS_OP, match_obj, package_obj,
+ &logical_result);
+ if (ACPI_FAILURE (status)) {
+ return (FALSE);
+ }
+ break;
+
+ default:
+
+ /* Undefined */
+
+ return (FALSE);
+ }
+
+ return logical_result;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_opcode_6A_0T_1R
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute opcode with 6 arguments, no target, and a return value
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_opcode_6A_0T_1R (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object **operand = &walk_state->operands[0];
+ union acpi_operand_object *return_desc = NULL;
+ acpi_status status = AE_OK;
+ u32 index;
+ union acpi_operand_object *this_element;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+
+
+ switch (walk_state->opcode) {
+ case AML_MATCH_OP:
+ /*
+ * Match (search_pkg[0], match_op1[1], match_obj1[2],
+ * match_op2[3], match_obj2[4], start_index[5])
+ */
+
+ /* Validate both Match Term Operators (MTR, MEQ, etc.) */
+
+ if ((operand[1]->integer.value > MAX_MATCH_OPERATOR) ||
+ (operand[3]->integer.value > MAX_MATCH_OPERATOR)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Match operator out of range\n"));
+ status = AE_AML_OPERAND_VALUE;
+ goto cleanup;
+ }
+
+ /* Get the package start_index, validate against the package length */
+
+ index = (u32) operand[5]->integer.value;
+ if (index >= (u32) operand[0]->package.count) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n"));
+ status = AE_AML_PACKAGE_LIMIT;
+ goto cleanup;
+ }
+
+ /* Create an integer for the return value */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+
+ }
+
+ /* Default return value if no match found */
+
+ return_desc->integer.value = ACPI_INTEGER_MAX;
+
+ /*
+ * Examine each element until a match is found. Both match conditions
+ * must be satisfied for a match to occur. Within the loop,
+ * "continue" signifies that the current element does not match
+ * and the next should be examined.
+ *
+ * Upon finding a match, the loop will terminate via "break" at
+ * the bottom. If it terminates "normally", match_value will be
+ * ACPI_INTEGER_MAX (Ones) (its initial value) indicating that no
+ * match was found.
+ */
+ for ( ; index < operand[0]->package.count; index++) {
+ /* Get the current package element */
+
+ this_element = operand[0]->package.elements[index];
+
+ /* Treat any uninitialized (NULL) elements as non-matching */
+
+ if (!this_element) {
+ continue;
+ }
+
+ /*
+ * Both match conditions must be satisfied. Execution of a continue
+ * (proceed to next iteration of enclosing for loop) signifies a
+ * non-match.
+ */
+ if (!acpi_ex_do_match ((u32) operand[1]->integer.value,
+ this_element, operand[2])) {
+ continue;
+ }
+
+ if (!acpi_ex_do_match ((u32) operand[3]->integer.value,
+ this_element, operand[4])) {
+ continue;
+ }
+
+ /* Match found: Index is the return value */
+
+ return_desc->integer.value = index;
+ break;
+ }
+ break;
+
+
+ case AML_LOAD_TABLE_OP:
+
+ status = acpi_ex_load_table_op (walk_state, &return_desc);
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n",
+ walk_state->opcode));
+ status = AE_AML_BAD_OPCODE;
+ goto cleanup;
+ }
+
+
+ walk_state->result_obj = return_desc;
+
+
+cleanup:
+
+ /* Delete return object on error */
+
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (return_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
new file mode 100644
index 000000000000..264ef3bba31b
--- /dev/null
+++ b/drivers/acpi/executer/exprep.c
@@ -0,0 +1,530 @@
+
+/******************************************************************************
+ *
+ * Module Name: exprep - ACPI AML (p-code) execution - field prep utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exprep")
+
+
+#ifdef ACPI_UNDER_DEVELOPMENT
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_generate_access
+ *
+ * PARAMETERS: field_bit_offset - Start of field within parent region/buffer
+ * field_bit_length - Length of field in bits
+ * region_length - Length of parent in bytes
+ *
+ * RETURN: Field granularity (8, 16, 32 or 64) and
+ * byte_alignment (1, 2, 3, or 4)
+ *
+ * DESCRIPTION: Generate an optimal access width for fields defined with the
+ * any_acc keyword.
+ *
+ * NOTE: Need to have the region_length in order to check for boundary
+ * conditions (end-of-region). However, the region_length is a deferred
+ * operation. Therefore, to complete this implementation, the generation
+ * of this access width must be deferred until the region length has
+ * been evaluated.
+ *
+ ******************************************************************************/
+
+static u32
+acpi_ex_generate_access (
+ u32 field_bit_offset,
+ u32 field_bit_length,
+ u32 region_length)
+{
+ u32 field_byte_length;
+ u32 field_byte_offset;
+ u32 field_byte_end_offset;
+ u32 access_byte_width;
+ u32 field_start_offset;
+ u32 field_end_offset;
+ u32 minimum_access_width = 0xFFFFFFFF;
+ u32 minimum_accesses = 0xFFFFFFFF;
+ u32 accesses;
+
+
+ ACPI_FUNCTION_TRACE ("ex_generate_access");
+
+
+ /* Round Field start offset and length to "minimal" byte boundaries */
+
+ field_byte_offset = ACPI_DIV_8 (ACPI_ROUND_DOWN (field_bit_offset, 8));
+ field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + field_bit_offset, 8));
+ field_byte_length = field_byte_end_offset - field_byte_offset;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Bit length %d, Bit offset %d\n",
+ field_bit_length, field_bit_offset));
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Byte Length %d, Byte Offset %d, End Offset %d\n",
+ field_byte_length, field_byte_offset, field_byte_end_offset));
+
+ /*
+ * Iterative search for the maximum access width that is both aligned
+ * and does not go beyond the end of the region
+ *
+ * Start at byte_acc and work upwards to qword_acc max. (1,2,4,8 bytes)
+ */
+ for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) {
+ /*
+ * 1) Round end offset up to next access boundary and make sure that this
+ * does not go beyond the end of the parent region.
+ * 2) When the Access width is greater than the field_byte_length, we are done.
+ * (This does not optimize for the perfectly aligned case yet).
+ */
+ if (ACPI_ROUND_UP (field_byte_end_offset, access_byte_width) <= region_length) {
+ field_start_offset = ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) /
+ access_byte_width;
+ field_end_offset = ACPI_ROUND_UP ((field_byte_length + field_byte_offset),
+ access_byte_width) / access_byte_width;
+ accesses = field_end_offset - field_start_offset;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "access_width %d end is within region\n", access_byte_width));
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Field Start %d, Field End %d -- requires %d accesses\n",
+ field_start_offset, field_end_offset, accesses));
+
+ /* Single access is optimal */
+
+ if (accesses <= 1) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Entire field can be accessed with one operation of size %d\n",
+ access_byte_width));
+ return_VALUE (access_byte_width);
+ }
+
+ /*
+ * Fits in the region, but requires more than one read/write.
+ * try the next wider access on next iteration
+ */
+ if (accesses < minimum_accesses) {
+ minimum_accesses = accesses;
+ minimum_access_width = access_byte_width;
+ }
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "access_width %d end is NOT within region\n", access_byte_width));
+ if (access_byte_width == 1) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Field goes beyond end-of-region!\n"));
+ return_VALUE (0); /* Field does not fit in the region at all */
+ }
+
+ /* This width goes beyond the end-of-region, back off to previous access */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Backing off to previous optimal access width of %d\n",
+ minimum_access_width));
+ return_VALUE (minimum_access_width);
+ }
+ }
+
+ /* Could not read/write field with one operation, just use max access width */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Cannot access field in one operation, using width 8\n"));
+ return_VALUE (8);
+}
+#endif /* ACPI_UNDER_DEVELOPMENT */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_decode_field_access
+ *
+ * PARAMETERS: Access - Encoded field access bits
+ * Length - Field length.
+ *
+ * RETURN: Field granularity (8, 16, 32 or 64) and
+ * byte_alignment (1, 2, 3, or 4)
+ *
+ * DESCRIPTION: Decode the access_type bits of a field definition.
+ *
+ ******************************************************************************/
+
+static u32
+acpi_ex_decode_field_access (
+ union acpi_operand_object *obj_desc,
+ u8 field_flags,
+ u32 *return_byte_alignment)
+{
+ u32 access;
+ u32 byte_alignment;
+ u32 bit_length;
+
+
+ ACPI_FUNCTION_TRACE ("ex_decode_field_access");
+
+
+ access = (field_flags & AML_FIELD_ACCESS_TYPE_MASK);
+
+ switch (access) {
+ case AML_FIELD_ACCESS_ANY:
+
+#ifdef ACPI_UNDER_DEVELOPMENT
+ byte_alignment = acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset,
+ obj_desc->common_field.bit_length,
+ 0xFFFFFFFF /* Temp until we pass region_length as param */);
+ bit_length = byte_alignment * 8;
+#endif
+
+ byte_alignment = 1;
+ bit_length = 8;
+ break;
+
+ case AML_FIELD_ACCESS_BYTE:
+ case AML_FIELD_ACCESS_BUFFER: /* ACPI 2.0 (SMBus Buffer) */
+ byte_alignment = 1;
+ bit_length = 8;
+ break;
+
+ case AML_FIELD_ACCESS_WORD:
+ byte_alignment = 2;
+ bit_length = 16;
+ break;
+
+ case AML_FIELD_ACCESS_DWORD:
+ byte_alignment = 4;
+ bit_length = 32;
+ break;
+
+ case AML_FIELD_ACCESS_QWORD: /* ACPI 2.0 */
+ byte_alignment = 8;
+ bit_length = 64;
+ break;
+
+ default:
+ /* Invalid field access type */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown field access type %X\n",
+ access));
+ return_VALUE (0);
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_BUFFER_FIELD) {
+ /*
+ * buffer_field access can be on any byte boundary, so the
+ * byte_alignment is always 1 byte -- regardless of any byte_alignment
+ * implied by the field access type.
+ */
+ byte_alignment = 1;
+ }
+
+ *return_byte_alignment = byte_alignment;
+ return_VALUE (bit_length);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_prep_common_field_object
+ *
+ * PARAMETERS: obj_desc - The field object
+ * field_flags - Access, lock_rule, and update_rule.
+ * The format of a field_flag is described
+ * in the ACPI specification
+ * field_bit_position - Field start position
+ * field_bit_length - Field length in number of bits
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize the areas of the field object that are common
+ * to the various types of fields. Note: This is very "sensitive"
+ * code because we are solving the general case for field
+ * alignment.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_prep_common_field_object (
+ union acpi_operand_object *obj_desc,
+ u8 field_flags,
+ u8 field_attribute,
+ u32 field_bit_position,
+ u32 field_bit_length)
+{
+ u32 access_bit_width;
+ u32 byte_alignment;
+ u32 nearest_byte_address;
+
+
+ ACPI_FUNCTION_TRACE ("ex_prep_common_field_object");
+
+
+ /*
+ * Note: the structure being initialized is the
+ * ACPI_COMMON_FIELD_INFO; No structure fields outside of the common
+ * area are initialized by this procedure.
+ */
+ obj_desc->common_field.field_flags = field_flags;
+ obj_desc->common_field.attribute = field_attribute;
+ obj_desc->common_field.bit_length = field_bit_length;
+
+ /*
+ * Decode the access type so we can compute offsets. The access type gives
+ * two pieces of information - the width of each field access and the
+ * necessary byte_alignment (address granularity) of the access.
+ *
+ * For any_acc, the access_bit_width is the largest width that is both
+ * necessary and possible in an attempt to access the whole field in one
+ * I/O operation. However, for any_acc, the byte_alignment is always one
+ * byte.
+ *
+ * For all Buffer Fields, the byte_alignment is always one byte.
+ *
+ * For all other access types (Byte, Word, Dword, Qword), the Bitwidth is
+ * the same (equivalent) as the byte_alignment.
+ */
+ access_bit_width = acpi_ex_decode_field_access (obj_desc, field_flags,
+ &byte_alignment);
+ if (!access_bit_width) {
+ return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
+ }
+
+ /* Setup width (access granularity) fields */
+
+ obj_desc->common_field.access_byte_width = (u8)
+ ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */
+
+ obj_desc->common_field.access_bit_width = (u8) access_bit_width;
+
+ /*
+ * base_byte_offset is the address of the start of the field within the
+ * region. It is the byte address of the first *datum* (field-width data
+ * unit) of the field. (i.e., the first datum that contains at least the
+ * first *bit* of the field.)
+ *
+ * Note: byte_alignment is always either equal to the access_bit_width or 8
+ * (Byte access), and it defines the addressing granularity of the parent
+ * region or buffer.
+ */
+ nearest_byte_address =
+ ACPI_ROUND_BITS_DOWN_TO_BYTES (field_bit_position);
+ obj_desc->common_field.base_byte_offset = (u32)
+ ACPI_ROUND_DOWN (nearest_byte_address, byte_alignment);
+
+ /*
+ * start_field_bit_offset is the offset of the first bit of the field within
+ * a field datum.
+ */
+ obj_desc->common_field.start_field_bit_offset = (u8)
+ (field_bit_position - ACPI_MUL_8 (obj_desc->common_field.base_byte_offset));
+
+ /*
+ * Does the entire field fit within a single field access element? (datum)
+ * (i.e., without crossing a datum boundary)
+ */
+ if ((obj_desc->common_field.start_field_bit_offset + field_bit_length) <=
+ (u16) access_bit_width) {
+ obj_desc->common.flags |= AOPOBJ_SINGLE_DATUM;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_prep_field_value
+ *
+ * PARAMETERS: Node - Owning Node
+ * region_node - Region in which field is being defined
+ * field_flags - Access, lock_rule, and update_rule.
+ * field_bit_position - Field start position
+ * field_bit_length - Field length in number of bits
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Construct an union acpi_operand_object of type def_field and
+ * connect it to the parent Node.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_prep_field_value (
+ struct acpi_create_field_info *info)
+{
+ union acpi_operand_object *obj_desc;
+ u32 type;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ex_prep_field_value");
+
+
+ /* Parameter validation */
+
+ if (info->field_type != ACPI_TYPE_LOCAL_INDEX_FIELD) {
+ if (!info->region_node) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null region_node\n"));
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ type = acpi_ns_get_type (info->region_node);
+ if (type != ACPI_TYPE_REGION) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed Region, found type %X (%s)\n",
+ type, acpi_ut_get_type_name (type)));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ }
+
+ /* Allocate a new field object */
+
+ obj_desc = acpi_ut_create_internal_object (info->field_type);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Initialize areas of the object that are common to all fields */
+
+ obj_desc->common_field.node = info->field_node;
+ status = acpi_ex_prep_common_field_object (obj_desc, info->field_flags,
+ info->attribute, info->field_bit_position, info->field_bit_length);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_delete_object_desc (obj_desc);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Initialize areas of the object that are specific to the field type */
+
+ switch (info->field_type) {
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+ obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node);
+
+ /* An additional reference for the container */
+
+ acpi_ut_add_reference (obj_desc->field.region_obj);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "region_field: bit_off %X, Off %X, Gran %X, Region %p\n",
+ obj_desc->field.start_field_bit_offset, obj_desc->field.base_byte_offset,
+ obj_desc->field.access_byte_width, obj_desc->field.region_obj));
+ break;
+
+
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ obj_desc->bank_field.value = info->bank_value;
+ obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node);
+ obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (info->register_node);
+
+ /* An additional reference for the attached objects */
+
+ acpi_ut_add_reference (obj_desc->bank_field.region_obj);
+ acpi_ut_add_reference (obj_desc->bank_field.bank_obj);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Bank Field: bit_off %X, Off %X, Gran %X, Region %p, bank_reg %p\n",
+ obj_desc->bank_field.start_field_bit_offset,
+ obj_desc->bank_field.base_byte_offset,
+ obj_desc->field.access_byte_width,
+ obj_desc->bank_field.region_obj,
+ obj_desc->bank_field.bank_obj));
+ break;
+
+
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node);
+ obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node);
+ obj_desc->index_field.value = (u32)
+ (info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width));
+
+ if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) {
+ ACPI_REPORT_ERROR (("Null Index Object during field prep\n"));
+ acpi_ut_delete_object_desc (obj_desc);
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /* An additional reference for the attached objects */
+
+ acpi_ut_add_reference (obj_desc->index_field.data_obj);
+ acpi_ut_add_reference (obj_desc->index_field.index_obj);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "index_field: bit_off %X, Off %X, Value %X, Gran %X, Index %p, Data %p\n",
+ obj_desc->index_field.start_field_bit_offset,
+ obj_desc->index_field.base_byte_offset,
+ obj_desc->index_field.value,
+ obj_desc->field.access_byte_width,
+ obj_desc->index_field.index_obj,
+ obj_desc->index_field.data_obj));
+ break;
+
+ default:
+ /* No other types should get here */
+ break;
+ }
+
+ /*
+ * Store the constructed descriptor (obj_desc) into the parent Node,
+ * preserving the current type of that named_obj.
+ */
+ status = acpi_ns_attach_object (info->field_node, obj_desc,
+ acpi_ns_get_type (info->field_node));
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Set named_obj %p [%4.4s], obj_desc %p\n",
+ info->field_node, acpi_ut_get_node_name (info->field_node), obj_desc));
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
new file mode 100644
index 000000000000..7cfd0684c70b
--- /dev/null
+++ b/drivers/acpi/executer/exregion.c
@@ -0,0 +1,528 @@
+
+/******************************************************************************
+ *
+ * Module Name: exregion - ACPI default op_region (address space) handlers
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exregion")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_memory_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * handler_context - Pointer to Handler's context
+ * region_context - Pointer to context specific to the
+ * accessed region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the System Memory address space (Op Region)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_memory_space_handler (
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ acpi_status status = AE_OK;
+ void *logical_addr_ptr = NULL;
+ struct acpi_mem_space_context *mem_info = region_context;
+ u32 length;
+ acpi_size window_size;
+#ifndef ACPI_MISALIGNED_TRANSFERS
+ u32 remainder;
+#endif
+
+ ACPI_FUNCTION_TRACE ("ex_system_memory_space_handler");
+
+
+ /* Validate and translate the bit width */
+
+ switch (bit_width) {
+ case 8:
+ length = 1;
+ break;
+
+ case 16:
+ length = 2;
+ break;
+
+ case 32:
+ length = 4;
+ break;
+
+ case 64:
+ length = 8;
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid system_memory width %d\n",
+ bit_width));
+ return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
+ }
+
+
+#ifndef ACPI_MISALIGNED_TRANSFERS
+ /*
+ * Hardware does not support non-aligned data transfers, we must verify
+ * the request.
+ */
+ (void) acpi_ut_short_divide ((acpi_integer) address, length, NULL, &remainder);
+ if (remainder != 0) {
+ return_ACPI_STATUS (AE_AML_ALIGNMENT);
+ }
+#endif
+
+ /*
+ * Does the request fit into the cached memory mapping?
+ * Is 1) Address below the current mapping? OR
+ * 2) Address beyond the current mapping?
+ */
+ if ((address < mem_info->mapped_physical_address) ||
+ (((acpi_integer) address + length) >
+ ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) {
+ /*
+ * The request cannot be resolved by the current memory mapping;
+ * Delete the existing mapping and create a new one.
+ */
+ if (mem_info->mapped_length) {
+ /* Valid mapping, delete it */
+
+ acpi_os_unmap_memory (mem_info->mapped_logical_address,
+ mem_info->mapped_length);
+ }
+
+ /*
+ * Don't attempt to map memory beyond the end of the region, and
+ * constrain the maximum mapping size to something reasonable.
+ */
+ window_size = (acpi_size) ((mem_info->address + mem_info->length) - address);
+ if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) {
+ window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE;
+ }
+
+ /* Create a new mapping starting at the address given */
+
+ status = acpi_os_map_memory (address, window_size,
+ (void **) &mem_info->mapped_logical_address);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n",
+ ACPI_FORMAT_UINT64 (address), (u32) window_size));
+ mem_info->mapped_length = 0;
+ return_ACPI_STATUS (status);
+ }
+
+ /* Save the physical address and mapping size */
+
+ mem_info->mapped_physical_address = address;
+ mem_info->mapped_length = window_size;
+ }
+
+ /*
+ * Generate a logical pointer corresponding to the address we want to
+ * access
+ */
+ logical_addr_ptr = mem_info->mapped_logical_address +
+ ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width,
+ ACPI_FORMAT_UINT64 (address)));
+
+ /*
+ * Perform the memory read or write
+ *
+ * Note: For machines that do not support non-aligned transfers, the target
+ * address was checked for alignment above. We do not attempt to break the
+ * transfer up into smaller (byte-size) chunks because the AML specifically
+ * asked for a transfer width that the hardware may require.
+ */
+ switch (function) {
+ case ACPI_READ:
+
+ *value = 0;
+ switch (bit_width) {
+ case 8:
+ *value = (acpi_integer) *((u8 *) logical_addr_ptr);
+ break;
+
+ case 16:
+ *value = (acpi_integer) *((u16 *) logical_addr_ptr);
+ break;
+
+ case 32:
+ *value = (acpi_integer) *((u32 *) logical_addr_ptr);
+ break;
+
+#if ACPI_MACHINE_WIDTH != 16
+ case 64:
+ *value = (acpi_integer) *((u64 *) logical_addr_ptr);
+ break;
+#endif
+ default:
+ /* bit_width was already validated */
+ break;
+ }
+ break;
+
+ case ACPI_WRITE:
+
+ switch (bit_width) {
+ case 8:
+ *(u8 *) logical_addr_ptr = (u8) *value;
+ break;
+
+ case 16:
+ *(u16 *) logical_addr_ptr = (u16) *value;
+ break;
+
+ case 32:
+ *(u32 *) logical_addr_ptr = (u32) *value;
+ break;
+
+#if ACPI_MACHINE_WIDTH != 16
+ case 64:
+ *(u64 *) logical_addr_ptr = (u64) *value;
+ break;
+#endif
+
+ default:
+ /* bit_width was already validated */
+ break;
+ }
+ break;
+
+ default:
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_io_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * handler_context - Pointer to Handler's context
+ * region_context - Pointer to context specific to the
+ * accessed region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the System IO address space (Op Region)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_io_space_handler (
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ acpi_status status = AE_OK;
+ u32 value32;
+
+
+ ACPI_FUNCTION_TRACE ("ex_system_io_space_handler");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "system_iO %d (%d width) Address=%8.8X%8.8X\n", function, bit_width,
+ ACPI_FORMAT_UINT64 (address)));
+
+ /* Decode the function parameter */
+
+ switch (function) {
+ case ACPI_READ:
+
+ status = acpi_os_read_port ((acpi_io_address) address, &value32, bit_width);
+ *value = value32;
+ break;
+
+ case ACPI_WRITE:
+
+ status = acpi_os_write_port ((acpi_io_address) address, (u32) *value, bit_width);
+ break;
+
+ default:
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_pci_config_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * handler_context - Pointer to Handler's context
+ * region_context - Pointer to context specific to the
+ * accessed region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the PCI Config address space (Op Region)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_pci_config_space_handler (
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ acpi_status status = AE_OK;
+ struct acpi_pci_id *pci_id;
+ u16 pci_register;
+
+
+ ACPI_FUNCTION_TRACE ("ex_pci_config_space_handler");
+
+
+ /*
+ * The arguments to acpi_os(Read|Write)pci_configuration are:
+ *
+ * pci_segment is the PCI bus segment range 0-31
+ * pci_bus is the PCI bus number range 0-255
+ * pci_device is the PCI device number range 0-31
+ * pci_function is the PCI device function number
+ * pci_register is the Config space register range 0-255 bytes
+ *
+ * Value - input value for write, output address for read
+ *
+ */
+ pci_id = (struct acpi_pci_id *) region_context;
+ pci_register = (u16) (u32) address;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "pci_config %d (%d) Seg(%04x) Bus(%04x) Dev(%04x) Func(%04x) Reg(%04x)\n",
+ function, bit_width, pci_id->segment, pci_id->bus, pci_id->device,
+ pci_id->function, pci_register));
+
+ switch (function) {
+ case ACPI_READ:
+
+ *value = 0;
+ status = acpi_os_read_pci_configuration (pci_id, pci_register, value, bit_width);
+ break;
+
+ case ACPI_WRITE:
+
+ status = acpi_os_write_pci_configuration (pci_id, pci_register, *value, bit_width);
+ break;
+
+ default:
+
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_cmos_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * handler_context - Pointer to Handler's context
+ * region_context - Pointer to context specific to the
+ * accessed region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the CMOS address space (Op Region)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_cmos_space_handler (
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_cmos_space_handler");
+
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_pci_bar_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * handler_context - Pointer to Handler's context
+ * region_context - Pointer to context specific to the
+ * accessed region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the PCI bar_target address space (Op Region)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_pci_bar_space_handler (
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_pci_bar_space_handler");
+
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_data_table_space_handler
+ *
+ * PARAMETERS: Function - Read or Write operation
+ * Address - Where in the space to read or write
+ * bit_width - Field width in bits (8, 16, or 32)
+ * Value - Pointer to in or out value
+ * handler_context - Pointer to Handler's context
+ * region_context - Pointer to context specific to the
+ * accessed region
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Handler for the Data Table address space (Op Region)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_data_table_space_handler (
+ u32 function,
+ acpi_physical_address address,
+ u32 bit_width,
+ acpi_integer *value,
+ void *handler_context,
+ void *region_context)
+{
+ acpi_status status = AE_OK;
+ u32 byte_width = ACPI_DIV_8 (bit_width);
+ u32 i;
+ char *logical_addr_ptr;
+
+
+ ACPI_FUNCTION_TRACE ("ex_data_table_space_handler");
+
+
+ logical_addr_ptr = ACPI_PHYSADDR_TO_PTR (address);
+
+
+ /* Perform the memory read or write */
+
+ switch (function) {
+ case ACPI_READ:
+
+ for (i = 0; i < byte_width; i++) {
+ ((char *) value) [i] = logical_addr_ptr[i];
+ }
+ break;
+
+ case ACPI_WRITE:
+ default:
+
+ return_ACPI_STATUS (AE_SUPPORT);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
new file mode 100644
index 000000000000..7936329a0e35
--- /dev/null
+++ b/drivers/acpi/executer/exresnte.c
@@ -0,0 +1,289 @@
+
+/******************************************************************************
+ *
+ * Module Name: exresnte - AML Interpreter object resolution
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exresnte")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_resolve_node_to_value
+ *
+ * PARAMETERS: object_ptr - Pointer to a location that contains
+ * a pointer to a NS node, and will receive a
+ * pointer to the resolved object.
+ * walk_state - Current state. Valid only if executing AML
+ * code. NULL if simply resolving an object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Resolve a Namespace node to a valued object
+ *
+ * Note: for some of the data types, the pointer attached to the Node
+ * can be either a pointer to an actual internal object or a pointer into the
+ * AML stream itself. These types are currently:
+ *
+ * ACPI_TYPE_INTEGER
+ * ACPI_TYPE_STRING
+ * ACPI_TYPE_BUFFER
+ * ACPI_TYPE_MUTEX
+ * ACPI_TYPE_PACKAGE
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_resolve_node_to_value (
+ struct acpi_namespace_node **object_ptr,
+ struct acpi_walk_state *walk_state)
+
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *source_desc;
+ union acpi_operand_object *obj_desc = NULL;
+ struct acpi_namespace_node *node;
+ acpi_object_type entry_type;
+
+
+ ACPI_FUNCTION_TRACE ("ex_resolve_node_to_value");
+
+
+ /*
+ * The stack pointer points to a struct acpi_namespace_node (Node). Get the
+ * object that is attached to the Node.
+ */
+ node = *object_ptr;
+ source_desc = acpi_ns_get_attached_object (node);
+ entry_type = acpi_ns_get_type ((acpi_handle) node);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Entry=%p source_desc=%p [%s]\n",
+ node, source_desc, acpi_ut_get_type_name (entry_type)));
+
+ if ((entry_type == ACPI_TYPE_LOCAL_ALIAS) ||
+ (entry_type == ACPI_TYPE_LOCAL_METHOD_ALIAS)) {
+ /* There is always exactly one level of indirection */
+
+ node = ACPI_CAST_PTR (struct acpi_namespace_node, node->object);
+ source_desc = acpi_ns_get_attached_object (node);
+ entry_type = acpi_ns_get_type ((acpi_handle) node);
+ *object_ptr = node;
+ }
+
+ /*
+ * Several object types require no further processing:
+ * 1) Devices rarely have an attached object, return the Node
+ * 2) Method locals and arguments have a pseudo-Node
+ */
+ if (entry_type == ACPI_TYPE_DEVICE ||
+ (node->flags & (ANOBJ_METHOD_ARG | ANOBJ_METHOD_LOCAL))) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ if (!source_desc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No object attached to node %p\n",
+ node));
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ /*
+ * Action is based on the type of the Node, which indicates the type
+ * of the attached object or pointer
+ */
+ switch (entry_type) {
+ case ACPI_TYPE_PACKAGE:
+
+ if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_PACKAGE) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Package, type %s\n",
+ acpi_ut_get_object_type_name (source_desc)));
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ status = acpi_ds_get_package_arguments (source_desc);
+ if (ACPI_SUCCESS (status)) {
+ /* Return an additional reference to the object */
+
+ obj_desc = source_desc;
+ acpi_ut_add_reference (obj_desc);
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Buffer, type %s\n",
+ acpi_ut_get_object_type_name (source_desc)));
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ status = acpi_ds_get_buffer_arguments (source_desc);
+ if (ACPI_SUCCESS (status)) {
+ /* Return an additional reference to the object */
+
+ obj_desc = source_desc;
+ acpi_ut_add_reference (obj_desc);
+ }
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a String, type %s\n",
+ acpi_ut_get_object_type_name (source_desc)));
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Return an additional reference to the object */
+
+ obj_desc = source_desc;
+ acpi_ut_add_reference (obj_desc);
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+
+ if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Object not a Integer, type %s\n",
+ acpi_ut_get_object_type_name (source_desc)));
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Return an additional reference to the object */
+
+ obj_desc = source_desc;
+ acpi_ut_add_reference (obj_desc);
+ break;
+
+
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read Node=%p source_desc=%p Type=%X\n",
+ node, source_desc, entry_type));
+
+ status = acpi_ex_read_data_from_field (walk_state, source_desc, &obj_desc);
+ break;
+
+ /*
+ * For these objects, just return the object attached to the Node
+ */
+ case ACPI_TYPE_MUTEX:
+ case ACPI_TYPE_METHOD:
+ case ACPI_TYPE_POWER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_THERMAL:
+ case ACPI_TYPE_EVENT:
+ case ACPI_TYPE_REGION:
+
+ /* Return an additional reference to the object */
+
+ obj_desc = source_desc;
+ acpi_ut_add_reference (obj_desc);
+ break;
+
+
+ /* TYPE_ANY is untyped, and thus there is no object associated with it */
+
+ case ACPI_TYPE_ANY:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Untyped entry %p, no attached object!\n",
+ node));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */
+
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ switch (source_desc->reference.opcode) {
+ case AML_LOAD_OP:
+
+ /* This is a ddb_handle */
+ /* Return an additional reference to the object */
+
+ obj_desc = source_desc;
+ acpi_ut_add_reference (obj_desc);
+ break;
+
+ default:
+ /* No named references are allowed here */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X (%s)\n",
+ source_desc->reference.opcode,
+ acpi_ps_get_opcode_name (source_desc->reference.opcode)));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ break;
+
+
+ /* Default case is for unknown types */
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Node %p - Unknown object type %X\n",
+ node, entry_type));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+
+ } /* switch (entry_type) */
+
+
+ /* Put the object descriptor on the stack */
+
+ *object_ptr = (void *) obj_desc;
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
new file mode 100644
index 000000000000..7be604911156
--- /dev/null
+++ b/drivers/acpi/executer/exresolv.c
@@ -0,0 +1,546 @@
+
+/******************************************************************************
+ *
+ * Module Name: exresolv - AML Interpreter object resolution
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exresolv")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_resolve_to_value
+ *
+ * PARAMETERS: **stack_ptr - Points to entry on obj_stack, which can
+ * be either an (union acpi_operand_object *)
+ * or an acpi_handle.
+ * walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert Reference objects to values
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_resolve_to_value (
+ union acpi_operand_object **stack_ptr,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_resolve_to_value", stack_ptr);
+
+
+ if (!stack_ptr || !*stack_ptr) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n"));
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ /*
+ * The entity pointed to by the stack_ptr can be either
+ * 1) A valid union acpi_operand_object, or
+ * 2) A struct acpi_namespace_node (named_obj)
+ */
+ if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_OPERAND) {
+ status = acpi_ex_resolve_object_to_value (stack_ptr, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Object on the stack may have changed if acpi_ex_resolve_object_to_value()
+ * was called (i.e., we can't use an _else_ here.)
+ */
+ if (ACPI_GET_DESCRIPTOR_TYPE (*stack_ptr) == ACPI_DESC_TYPE_NAMED) {
+ status = acpi_ex_resolve_node_to_value (
+ ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, stack_ptr),
+ walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Resolved object %p\n", *stack_ptr));
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_resolve_object_to_value
+ *
+ * PARAMETERS: stack_ptr - Pointer to a stack location that contains a
+ * ptr to an internal object.
+ * walk_state - Current method state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve the value from an internal object. The Reference type
+ * uses the associated AML opcode to determine the value.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_resolve_object_to_value (
+ union acpi_operand_object **stack_ptr,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *stack_desc;
+ void *temp_node;
+ union acpi_operand_object *obj_desc;
+ u16 opcode;
+
+
+ ACPI_FUNCTION_TRACE ("ex_resolve_object_to_value");
+
+
+ stack_desc = *stack_ptr;
+
+ /* This is an union acpi_operand_object */
+
+ switch (ACPI_GET_OBJECT_TYPE (stack_desc)) {
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ opcode = stack_desc->reference.opcode;
+
+ switch (opcode) {
+ case AML_NAME_OP:
+
+ /*
+ * Convert indirect name ptr to a direct name ptr.
+ * Then, acpi_ex_resolve_node_to_value can be used to get the value
+ */
+ temp_node = stack_desc->reference.object;
+
+ /* Delete the Reference Object */
+
+ acpi_ut_remove_reference (stack_desc);
+
+ /* Put direct name pointer onto stack and exit */
+
+ (*stack_ptr) = temp_node;
+ break;
+
+
+ case AML_LOCAL_OP:
+ case AML_ARG_OP:
+
+ /*
+ * Get the local from the method's state info
+ * Note: this increments the local's object reference count
+ */
+ status = acpi_ds_method_data_get_value (opcode,
+ stack_desc->reference.offset, walk_state, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Arg/Local %X] value_obj is %p\n",
+ stack_desc->reference.offset, obj_desc));
+
+ /*
+ * Now we can delete the original Reference Object and
+ * replace it with the resolved value
+ */
+ acpi_ut_remove_reference (stack_desc);
+ *stack_ptr = obj_desc;
+ break;
+
+
+ case AML_INDEX_OP:
+
+ switch (stack_desc->reference.target_type) {
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ /* Just return - leave the Reference on the stack */
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ obj_desc = *stack_desc->reference.where;
+ if (obj_desc) {
+ /*
+ * Valid obj descriptor, copy pointer to return value
+ * (i.e., dereference the package index)
+ * Delete the ref object, increment the returned object
+ */
+ acpi_ut_remove_reference (stack_desc);
+ acpi_ut_add_reference (obj_desc);
+ *stack_ptr = obj_desc;
+ }
+ else {
+ /*
+ * A NULL object descriptor means an unitialized element of
+ * the package, can't dereference it
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Attempt to deref an Index to NULL pkg element Idx=%p\n",
+ stack_desc));
+ status = AE_AML_UNINITIALIZED_ELEMENT;
+ }
+ break;
+
+
+ default:
+
+ /* Invalid reference object */
+
+ ACPI_REPORT_ERROR ((
+ "During resolve, Unknown target_type %X in Index/Reference obj %p\n",
+ stack_desc->reference.target_type, stack_desc));
+ status = AE_AML_INTERNAL;
+ break;
+ }
+ break;
+
+
+ case AML_REF_OF_OP:
+ case AML_DEBUG_OP:
+ case AML_LOAD_OP:
+
+ /* Just leave the object as-is */
+
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n",
+ opcode, acpi_ps_get_opcode_name (opcode), stack_desc));
+ status = AE_AML_INTERNAL;
+ break;
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ status = acpi_ds_get_buffer_arguments (stack_desc);
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ status = acpi_ds_get_package_arguments (stack_desc);
+ break;
+
+
+ /*
+ * These cases may never happen here, but just in case..
+ */
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read source_desc=%p Type=%X\n",
+ stack_desc, ACPI_GET_OBJECT_TYPE (stack_desc)));
+
+ status = acpi_ex_read_data_from_field (walk_state, stack_desc, &obj_desc);
+ *stack_ptr = (void *) obj_desc;
+ break;
+
+ default:
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_resolve_multiple
+ *
+ * PARAMETERS: walk_state - Current state (contains AML opcode)
+ * Operand - Starting point for resolution
+ * return_type - Where the object type is returned
+ * return_desc - Where the resolved object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return the base object and type. Traverse a reference list if
+ * necessary to get to the base object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_resolve_multiple (
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object *operand,
+ acpi_object_type *return_type,
+ union acpi_operand_object **return_desc)
+{
+ union acpi_operand_object *obj_desc = (void *) operand;
+ struct acpi_namespace_node *node;
+ acpi_object_type type;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple");
+
+
+ /*
+ * Operand can be either a namespace node or an operand descriptor
+ */
+ switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
+ case ACPI_DESC_TYPE_OPERAND:
+ type = obj_desc->common.type;
+ break;
+
+ case ACPI_DESC_TYPE_NAMED:
+ type = ((struct acpi_namespace_node *) obj_desc)->type;
+ obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc);
+
+ /* If we had an Alias node, use the attached object for type info */
+
+ if (type == ACPI_TYPE_LOCAL_ALIAS) {
+ type = ((struct acpi_namespace_node *) obj_desc)->type;
+ obj_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) obj_desc);
+ }
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+
+ /*
+ * If type is anything other than a reference, we are done
+ */
+ if (type != ACPI_TYPE_LOCAL_REFERENCE) {
+ goto exit;
+ }
+
+ /*
+ * For reference objects created via the ref_of or Index operators,
+ * we need to get to the base object (as per the ACPI specification
+ * of the object_type and size_of operators). This means traversing
+ * the list of possibly many nested references.
+ */
+ while (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
+ switch (obj_desc->reference.opcode) {
+ case AML_REF_OF_OP:
+
+ /* Dereference the reference pointer */
+
+ node = obj_desc->reference.object;
+
+ /* All "References" point to a NS node */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
+ node, acpi_ut_get_descriptor_name (node)));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /* Get the attached object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ /* No object, use the NS node type */
+
+ type = acpi_ns_get_type (node);
+ goto exit;
+ }
+
+ /* Check for circular references */
+
+ if (obj_desc == operand) {
+ return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
+ }
+ break;
+
+
+ case AML_INDEX_OP:
+
+ /* Get the type of this reference (index into another object) */
+
+ type = obj_desc->reference.target_type;
+ if (type != ACPI_TYPE_PACKAGE) {
+ goto exit;
+ }
+
+ /*
+ * The main object is a package, we want to get the type
+ * of the individual package element that is referenced by
+ * the index.
+ *
+ * This could of course in turn be another reference object.
+ */
+ obj_desc = *(obj_desc->reference.where);
+ if (!obj_desc) {
+ /* NULL package elements are allowed */
+
+ type = 0; /* Uninitialized */
+ goto exit;
+ }
+ break;
+
+
+ case AML_INT_NAMEPATH_OP:
+
+ /* Dereference the reference pointer */
+
+ node = obj_desc->reference.node;
+
+ /* All "References" point to a NS node */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
+ node, acpi_ut_get_descriptor_name (node)));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /* Get the attached object */
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ /* No object, use the NS node type */
+
+ type = acpi_ns_get_type (node);
+ goto exit;
+ }
+
+ /* Check for circular references */
+
+ if (obj_desc == operand) {
+ return_ACPI_STATUS (AE_AML_CIRCULAR_REFERENCE);
+ }
+ break;
+
+
+ case AML_LOCAL_OP:
+ case AML_ARG_OP:
+
+ if (return_desc) {
+ status = acpi_ds_method_data_get_value (obj_desc->reference.opcode,
+ obj_desc->reference.offset, walk_state, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ acpi_ut_remove_reference (obj_desc);
+ }
+ else {
+ status = acpi_ds_method_data_get_node (obj_desc->reference.opcode,
+ obj_desc->reference.offset, walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ type = ACPI_TYPE_ANY;
+ goto exit;
+ }
+ }
+ break;
+
+
+ case AML_DEBUG_OP:
+
+ /* The Debug Object is of type "debug_object" */
+
+ type = ACPI_TYPE_DEBUG_OBJECT;
+ goto exit;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n",
+ obj_desc->reference.opcode));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+ }
+
+ /*
+ * Now we are guaranteed to have an object that has not been created
+ * via the ref_of or Index operators.
+ */
+ type = ACPI_GET_OBJECT_TYPE (obj_desc);
+
+
+exit:
+ /* Convert internal types to external types */
+
+ switch (type) {
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ type = ACPI_TYPE_FIELD_UNIT;
+ break;
+
+ case ACPI_TYPE_LOCAL_SCOPE:
+
+ /* Per ACPI Specification, Scope is untyped */
+
+ type = ACPI_TYPE_ANY;
+ break;
+
+ default:
+ /* No change to Type required */
+ break;
+ }
+
+ *return_type = type;
+ if (return_desc) {
+ *return_desc = obj_desc;
+ }
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
new file mode 100644
index 000000000000..c92890220c32
--- /dev/null
+++ b/drivers/acpi/executer/exresop.c
@@ -0,0 +1,661 @@
+
+/******************************************************************************
+ *
+ * Module Name: exresop - AML Interpreter operand/object resolution
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+#include <acpi/acparser.h>
+#include <acpi/acinterp.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exresop")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_check_object_type
+ *
+ * PARAMETERS: type_needed Object type needed
+ * this_type Actual object type
+ * Object Object pointer
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check required type against actual type
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_check_object_type (
+ acpi_object_type type_needed,
+ acpi_object_type this_type,
+ void *object)
+{
+ ACPI_FUNCTION_NAME ("ex_check_object_type");
+
+
+ if (type_needed == ACPI_TYPE_ANY) {
+ /* All types OK, so we don't perform any typechecks */
+
+ return (AE_OK);
+ }
+
+ if (type_needed == ACPI_TYPE_LOCAL_REFERENCE) {
+ /*
+ * Allow the AML "Constant" opcodes (Zero, One, etc.) to be reference
+ * objects and thus allow them to be targets. (As per the ACPI
+ * specification, a store to a constant is a noop.)
+ */
+ if ((this_type == ACPI_TYPE_INTEGER) &&
+ (((union acpi_operand_object *) object)->common.flags & AOPOBJ_AML_CONSTANT)) {
+ return (AE_OK);
+ }
+ }
+
+ if (type_needed != this_type) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [%s], found [%s] %p\n",
+ acpi_ut_get_type_name (type_needed),
+ acpi_ut_get_type_name (this_type), object));
+
+ return (AE_AML_OPERAND_TYPE);
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_resolve_operands
+ *
+ * PARAMETERS: Opcode - Opcode being interpreted
+ * stack_ptr - Pointer to the operand stack to be
+ * resolved
+ * walk_state - Current state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert multiple input operands to the types required by the
+ * target operator.
+ *
+ * Each 5-bit group in arg_types represents one required
+ * operand and indicates the required Type. The corresponding operand
+ * will be converted to the required type if possible, otherwise we
+ * abort with an exception.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_resolve_operands (
+ u16 opcode,
+ union acpi_operand_object **stack_ptr,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status = AE_OK;
+ u8 object_type;
+ void *temp_node;
+ u32 arg_types;
+ const struct acpi_opcode_info *op_info;
+ u32 this_arg_type;
+ acpi_object_type type_needed;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ex_resolve_operands", opcode);
+
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (op_info->class == AML_CLASS_UNKNOWN) {
+ return_ACPI_STATUS (AE_AML_BAD_OPCODE);
+ }
+
+ arg_types = op_info->runtime_args;
+ if (arg_types == ARGI_INVALID_OPCODE) {
+ ACPI_REPORT_ERROR (("resolve_operands: %X is not a valid AML opcode\n",
+ opcode));
+
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] required_operand_types=%8.8X \n",
+ opcode, op_info->name, arg_types));
+
+ /*
+ * Normal exit is with (arg_types == 0) at end of argument list.
+ * Function will return an exception from within the loop upon
+ * finding an entry which is not (or cannot be converted
+ * to) the required type; if stack underflows; or upon
+ * finding a NULL stack entry (which should not happen).
+ */
+ while (GET_CURRENT_ARG_TYPE (arg_types)) {
+ if (!stack_ptr || !*stack_ptr) {
+ ACPI_REPORT_ERROR (("resolve_operands: Null stack entry at %p\n",
+ stack_ptr));
+
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /* Extract useful items */
+
+ obj_desc = *stack_ptr;
+
+ /* Decode the descriptor type */
+
+ switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
+ case ACPI_DESC_TYPE_NAMED:
+
+ /* Node */
+
+ object_type = ((struct acpi_namespace_node *) obj_desc)->type;
+ break;
+
+
+ case ACPI_DESC_TYPE_OPERAND:
+
+ /* ACPI internal object */
+
+ object_type = ACPI_GET_OBJECT_TYPE (obj_desc);
+
+ /* Check for bad acpi_object_type */
+
+ if (!acpi_ut_valid_object_type (object_type)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad operand object type [%X]\n",
+ object_type));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
+ /*
+ * Decode the Reference
+ */
+ op_info = acpi_ps_get_opcode_info (opcode);
+ if (op_info->class == AML_CLASS_UNKNOWN) {
+ return_ACPI_STATUS (AE_AML_BAD_OPCODE);
+ }
+
+ switch (obj_desc->reference.opcode) {
+ case AML_DEBUG_OP:
+ case AML_NAME_OP:
+ case AML_INDEX_OP:
+ case AML_REF_OF_OP:
+ case AML_ARG_OP:
+ case AML_LOCAL_OP:
+ case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
+
+ ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Operand is a Reference, ref_opcode [%s]\n",
+ (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name)));
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Operand is a Reference, Unknown Reference Opcode %X [%s]\n",
+ obj_desc->reference.opcode,
+ (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ }
+ break;
+
+
+ default:
+
+ /* Invalid descriptor */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid descriptor %p [%s]\n",
+ obj_desc, acpi_ut_get_descriptor_name (obj_desc)));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+
+ /*
+ * Get one argument type, point to the next
+ */
+ this_arg_type = GET_CURRENT_ARG_TYPE (arg_types);
+ INCREMENT_ARG_LIST (arg_types);
+
+ /*
+ * Handle cases where the object does not need to be
+ * resolved to a value
+ */
+ switch (this_arg_type) {
+ case ARGI_REF_OR_STRING: /* Can be a String or Reference */
+
+ if ((ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) &&
+ (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_STRING)) {
+ /*
+ * String found - the string references a named object and must be
+ * resolved to a node
+ */
+ goto next_operand;
+ }
+
+ /* Else not a string - fall through to the normal Reference case below */
+ /*lint -fallthrough */
+
+ case ARGI_REFERENCE: /* References: */
+ case ARGI_INTEGER_REF:
+ case ARGI_OBJECT_REF:
+ case ARGI_DEVICE_REF:
+ case ARGI_TARGETREF: /* Allows implicit conversion rules before store */
+ case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
+ case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */
+
+ /* Need an operand of type ACPI_TYPE_LOCAL_REFERENCE */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) /* Node (name) ptr OK as-is */ {
+ goto next_operand;
+ }
+
+ status = acpi_ex_check_object_type (ACPI_TYPE_LOCAL_REFERENCE,
+ object_type, obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (AML_NAME_OP == obj_desc->reference.opcode) {
+ /*
+ * Convert an indirect name ptr to direct name ptr and put
+ * it on the stack
+ */
+ temp_node = obj_desc->reference.object;
+ acpi_ut_remove_reference (obj_desc);
+ (*stack_ptr) = temp_node;
+ }
+ goto next_operand;
+
+
+ case ARGI_DATAREFOBJ: /* Store operator only */
+
+ /*
+ * We don't want to resolve index_op reference objects during
+ * a store because this would be an implicit de_ref_of operation.
+ * Instead, we just want to store the reference object.
+ * -- All others must be resolved below.
+ */
+ if ((opcode == AML_STORE_OP) &&
+ (ACPI_GET_OBJECT_TYPE (*stack_ptr) == ACPI_TYPE_LOCAL_REFERENCE) &&
+ ((*stack_ptr)->reference.opcode == AML_INDEX_OP)) {
+ goto next_operand;
+ }
+ break;
+
+ default:
+ /* All cases covered above */
+ break;
+ }
+
+
+ /*
+ * Resolve this object to a value
+ */
+ status = acpi_ex_resolve_to_value (stack_ptr, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the resolved object */
+
+ obj_desc = *stack_ptr;
+
+ /*
+ * Check the resulting object (value) type
+ */
+ switch (this_arg_type) {
+ /*
+ * For the simple cases, only one type of resolved object
+ * is allowed
+ */
+ case ARGI_MUTEX:
+
+ /* Need an operand of type ACPI_TYPE_MUTEX */
+
+ type_needed = ACPI_TYPE_MUTEX;
+ break;
+
+ case ARGI_EVENT:
+
+ /* Need an operand of type ACPI_TYPE_EVENT */
+
+ type_needed = ACPI_TYPE_EVENT;
+ break;
+
+ case ARGI_PACKAGE: /* Package */
+
+ /* Need an operand of type ACPI_TYPE_PACKAGE */
+
+ type_needed = ACPI_TYPE_PACKAGE;
+ break;
+
+ case ARGI_ANYTYPE:
+
+ /* Any operand type will do */
+
+ type_needed = ACPI_TYPE_ANY;
+ break;
+
+ case ARGI_DDBHANDLE:
+
+ /* Need an operand of type ACPI_TYPE_DDB_HANDLE */
+
+ type_needed = ACPI_TYPE_LOCAL_REFERENCE;
+ break;
+
+
+ /*
+ * The more complex cases allow multiple resolved object types
+ */
+ case ARGI_INTEGER: /* Number */
+
+ /*
+ * Need an operand of type ACPI_TYPE_INTEGER,
+ * But we can implicitly convert from a STRING or BUFFER
+ * Aka - "Implicit Source Operand Conversion"
+ */
+ status = acpi_ex_convert_to_integer (obj_desc, stack_ptr, 16);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_TYPE) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Integer/String/Buffer], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ return_ACPI_STATUS (status);
+ }
+ goto next_operand;
+
+
+ case ARGI_BUFFER:
+
+ /*
+ * Need an operand of type ACPI_TYPE_BUFFER,
+ * But we can implicitly convert from a STRING or INTEGER
+ * Aka - "Implicit Source Operand Conversion"
+ */
+ status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_TYPE) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Integer/String/Buffer], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ return_ACPI_STATUS (status);
+ }
+ goto next_operand;
+
+
+ case ARGI_STRING:
+
+ /*
+ * Need an operand of type ACPI_TYPE_STRING,
+ * But we can implicitly convert from a BUFFER or INTEGER
+ * Aka - "Implicit Source Operand Conversion"
+ */
+ status = acpi_ex_convert_to_string (obj_desc, stack_ptr,
+ ACPI_IMPLICIT_CONVERT_HEX);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_TYPE) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Integer/String/Buffer], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ return_ACPI_STATUS (status);
+ }
+ goto next_operand;
+
+
+ case ARGI_COMPUTEDATA:
+
+ /* Need an operand of type INTEGER, STRING or BUFFER */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /* Valid operand */
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Integer/String/Buffer], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ goto next_operand;
+
+
+ case ARGI_BUFFER_OR_STRING:
+
+ /* Need an operand of type STRING or BUFFER */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /* Valid operand */
+ break;
+
+ case ACPI_TYPE_INTEGER:
+
+ /* Highest priority conversion is to type Buffer */
+
+ status = acpi_ex_convert_to_buffer (obj_desc, stack_ptr);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Integer/String/Buffer], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ goto next_operand;
+
+
+ case ARGI_DATAOBJECT:
+ /*
+ * ARGI_DATAOBJECT is only used by the size_of operator.
+ * Need a buffer, string, package, or ref_of reference.
+ *
+ * The only reference allowed here is a direct reference to
+ * a namespace node.
+ */
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_PACKAGE:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ /* Valid operand */
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Buffer/String/Package/Reference], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ goto next_operand;
+
+
+ case ARGI_COMPLEXOBJ:
+
+ /* Need a buffer or package or (ACPI 2.0) String */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_PACKAGE:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /* Valid operand */
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Buffer/String/Package], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ goto next_operand;
+
+
+ case ARGI_REGION_OR_FIELD:
+
+ /* Need an operand of type ACPI_TYPE_REGION or a FIELD in a region */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_REGION:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ /* Valid operand */
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed [Region/region_field], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ goto next_operand;
+
+
+ case ARGI_DATAREFOBJ:
+
+ /* Used by the Store() operator only */
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_PACKAGE:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ case ACPI_TYPE_DDB_HANDLE:
+
+ /* Valid operand */
+ break;
+
+ default:
+
+ if (acpi_gbl_enable_interpreter_slack) {
+ /*
+ * Enable original behavior of Store(), allowing any and all
+ * objects as the source operand. The ACPI spec does not
+ * allow this, however.
+ */
+ break;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p\n",
+ acpi_ut_get_object_type_name (obj_desc), obj_desc));
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+ goto next_operand;
+
+
+ default:
+
+ /* Unknown type */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Internal - Unknown ARGI (required operand) type %X\n",
+ this_arg_type));
+
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Make sure that the original object was resolved to the
+ * required object type (Simple cases only).
+ */
+ status = acpi_ex_check_object_type (type_needed,
+ ACPI_GET_OBJECT_TYPE (*stack_ptr), *stack_ptr);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+next_operand:
+ /*
+ * If more operands needed, decrement stack_ptr to point
+ * to next operand on stack
+ */
+ if (GET_CURRENT_ARG_TYPE (arg_types)) {
+ stack_ptr--;
+ }
+
+ } /* while (*Types) */
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
new file mode 100644
index 000000000000..e0fc6aba1253
--- /dev/null
+++ b/drivers/acpi/executer/exstore.c
@@ -0,0 +1,536 @@
+
+/******************************************************************************
+ *
+ * Module Name: exstore - AML Interpreter object store support
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exstore")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_store
+ *
+ * PARAMETERS: *source_desc - Value to be stored
+ * *dest_desc - Where to store it. Must be an NS node
+ * or an union acpi_operand_object of type
+ * Reference;
+ * walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the value described by source_desc into the location
+ * described by dest_desc. Called by various interpreter
+ * functions to store the result of an operation into
+ * the destination operand -- not just simply the actual "Store"
+ * ASL operator.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_store (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *dest_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *ref_desc = dest_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_store", dest_desc);
+
+
+ /* Validate parameters */
+
+ if (!source_desc || !dest_desc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null parameter\n"));
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
+
+ /* dest_desc can be either a namespace node or an ACPI object */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (dest_desc) == ACPI_DESC_TYPE_NAMED) {
+ /*
+ * Dest is a namespace node,
+ * Storing an object into a Named node.
+ */
+ status = acpi_ex_store_object_to_node (source_desc,
+ (struct acpi_namespace_node *) dest_desc, walk_state,
+ ACPI_IMPLICIT_CONVERSION);
+
+ return_ACPI_STATUS (status);
+ }
+
+ /* Destination object must be a Reference or a Constant object */
+
+ switch (ACPI_GET_OBJECT_TYPE (dest_desc)) {
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ break;
+
+ case ACPI_TYPE_INTEGER:
+
+ /* Allow stores to Constants -- a Noop as per ACPI spec */
+
+ if (dest_desc->common.flags & AOPOBJ_AML_CONSTANT) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*lint -fallthrough */
+
+ default:
+
+ /* Destination is not a Reference object */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Target is not a Reference or Constant object - %s [%p]\n",
+ acpi_ut_get_object_type_name (dest_desc), dest_desc));
+
+ ACPI_DUMP_STACK_ENTRY (source_desc);
+ ACPI_DUMP_STACK_ENTRY (dest_desc);
+ ACPI_DUMP_OPERANDS (&dest_desc, ACPI_IMODE_EXECUTE, "ex_store",
+ 2, "Target is not a Reference or Constant object");
+
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * Examine the Reference opcode. These cases are handled:
+ *
+ * 1) Store to Name (Change the object associated with a name)
+ * 2) Store to an indexed area of a Buffer or Package
+ * 3) Store to a Method Local or Arg
+ * 4) Store to the debug object
+ */
+ switch (ref_desc->reference.opcode) {
+ case AML_NAME_OP:
+ case AML_REF_OF_OP:
+
+ /* Storing an object into a Name "container" */
+
+ status = acpi_ex_store_object_to_node (source_desc, ref_desc->reference.object,
+ walk_state, ACPI_IMPLICIT_CONVERSION);
+ break;
+
+
+ case AML_INDEX_OP:
+
+ /* Storing to an Index (pointer into a packager or buffer) */
+
+ status = acpi_ex_store_object_to_index (source_desc, ref_desc, walk_state);
+ break;
+
+
+ case AML_LOCAL_OP:
+ case AML_ARG_OP:
+
+ /* Store to a method local/arg */
+
+ status = acpi_ds_store_object_to_local (ref_desc->reference.opcode,
+ ref_desc->reference.offset, source_desc, walk_state);
+ break;
+
+
+ case AML_DEBUG_OP:
+
+ /*
+ * Storing to the Debug object causes the value stored to be
+ * displayed and otherwise has no effect -- see ACPI Specification
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "**** Write to Debug Object: Object %p %s ****:\n\n",
+ source_desc, acpi_ut_get_object_type_name (source_desc)));
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ",
+ acpi_ut_get_object_type_name (source_desc)));
+
+ if (!acpi_ut_valid_internal_object (source_desc)) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT,
+ "%p, Invalid Internal Object!\n", source_desc));
+ break;
+ }
+
+ switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
+ case ACPI_TYPE_INTEGER:
+
+ if (acpi_gbl_integer_byte_width == 4) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n",
+ (u32) source_desc->integer.value));
+ }
+ else {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (source_desc->integer.value)));
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]",
+ (u32) source_desc->buffer.length));
+ ACPI_DUMP_BUFFER (source_desc->buffer.pointer,
+ (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32);
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n",
+ source_desc->string.length, source_desc->string.pointer));
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] Elements Ptr - %p\n",
+ source_desc->package.count, source_desc->package.elements));
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n",
+ source_desc));
+ break;
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n"));
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("ex_store: Unknown Reference opcode %X\n",
+ ref_desc->reference.opcode));
+ ACPI_DUMP_ENTRY (ref_desc, ACPI_LV_ERROR);
+
+ status = AE_AML_INTERNAL;
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_store_object_to_index
+ *
+ * PARAMETERS: *source_desc - Value to be stored
+ * *dest_desc - Named object to receive the value
+ * walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the object to indexed Buffer or Package element
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_store_object_to_index (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *index_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *new_desc;
+ u8 value = 0;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ex_store_object_to_index");
+
+
+ /*
+ * Destination must be a reference pointer, and
+ * must point to either a buffer or a package
+ */
+ switch (index_desc->reference.target_type) {
+ case ACPI_TYPE_PACKAGE:
+ /*
+ * Storing to a package element. Copy the object and replace
+ * any existing object with the new object. No implicit
+ * conversion is performed.
+ *
+ * The object at *(index_desc->Reference.Where) is the
+ * element within the package that is to be modified.
+ * The parent package object is at index_desc->Reference.Object
+ */
+ obj_desc = *(index_desc->reference.where);
+
+ status = acpi_ut_copy_iobject_to_iobject (source_desc, &new_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (obj_desc) {
+ /* Decrement reference count by the ref count of the parent package */
+
+ for (i = 0; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) {
+ acpi_ut_remove_reference (obj_desc);
+ }
+ }
+
+ *(index_desc->reference.where) = new_desc;
+
+ /* Increment reference count by the ref count of the parent package -1 */
+
+ for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) {
+ acpi_ut_add_reference (new_desc);
+ }
+
+ break;
+
+
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ /*
+ * Store into a Buffer or String (not actually a real buffer_field)
+ * at a location defined by an Index.
+ *
+ * The first 8-bit element of the source object is written to the
+ * 8-bit Buffer location defined by the Index destination object,
+ * according to the ACPI 2.0 specification.
+ */
+
+ /*
+ * Make sure the target is a Buffer or String. An error should
+ * not happen here, since the reference_object was constructed
+ * by the INDEX_OP code.
+ */
+ obj_desc = index_desc->reference.object;
+ if ((ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_BUFFER) &&
+ (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_STRING)) {
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /*
+ * The assignment of the individual elements will be slightly
+ * different for each source type.
+ */
+ switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
+ case ACPI_TYPE_INTEGER:
+
+ /* Use the least-significant byte of the integer */
+
+ value = (u8) (source_desc->integer.value);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ case ACPI_TYPE_STRING:
+
+ /* Note: Takes advantage of common string/buffer fields */
+
+ value = source_desc->buffer.pointer[0];
+ break;
+
+ default:
+
+ /* All other types are invalid */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Source must be Integer/Buffer/String type, not %s\n",
+ acpi_ut_get_object_type_name (source_desc)));
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Store the source value into the target buffer byte */
+
+ obj_desc->buffer.pointer[index_desc->reference.offset] = value;
+ break;
+
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Target is not a Package or buffer_field\n"));
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_store_object_to_node
+ *
+ * PARAMETERS: source_desc - Value to be stored
+ * Node - Named object to receive the value
+ * walk_state - Current walk state
+ * implicit_conversion - Perform implicit conversion (yes/no)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Store the object to the named object.
+ *
+ * The Assignment of an object to a named object is handled here
+ * The value passed in will replace the current value (if any)
+ * with the input value.
+ *
+ * When storing into an object the data is converted to the
+ * target object type then stored in the object. This means
+ * that the target object type (for an initialized target) will
+ * not be changed by a store operation.
+ *
+ * Assumes parameters are already validated.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_store_object_to_node (
+ union acpi_operand_object *source_desc,
+ struct acpi_namespace_node *node,
+ struct acpi_walk_state *walk_state,
+ u8 implicit_conversion)
+{
+ acpi_status status = AE_OK;
+ union acpi_operand_object *target_desc;
+ union acpi_operand_object *new_desc;
+ acpi_object_type target_type;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_node", source_desc);
+
+
+ /*
+ * Get current type of the node, and object attached to Node
+ */
+ target_type = acpi_ns_get_type (node);
+ target_desc = acpi_ns_get_attached_object (node);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Storing %p(%s) into node %p(%s)\n",
+ source_desc, acpi_ut_get_object_type_name (source_desc),
+ node, acpi_ut_get_type_name (target_type)));
+
+ /*
+ * Resolve the source object to an actual value
+ * (If it is a reference object)
+ */
+ status = acpi_ex_resolve_object (&source_desc, target_type, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* If no implicit conversion, drop into the default case below */
+
+ if (!implicit_conversion) {
+ /* Force execution of default (no implicit conversion) */
+
+ target_type = ACPI_TYPE_ANY;
+ }
+
+ /*
+ * Do the actual store operation
+ */
+ switch (target_type) {
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ /*
+ * For fields, copy the source data to the target field.
+ */
+ status = acpi_ex_write_data_to_field (source_desc, target_desc, &walk_state->result_obj);
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * These target types are all of type Integer/String/Buffer, and
+ * therefore support implicit conversion before the store.
+ *
+ * Copy and/or convert the source object to a new target object
+ */
+ status = acpi_ex_store_object_to_object (source_desc, target_desc, &new_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (new_desc != target_desc) {
+ /*
+ * Store the new new_desc as the new value of the Name, and set
+ * the Name's type to that of the value being stored in it.
+ * source_desc reference count is incremented by attach_object.
+ *
+ * Note: This may change the type of the node if an explicit store
+ * has been performed such that the node/object type has been
+ * changed.
+ */
+ status = acpi_ns_attach_object (node, new_desc, new_desc->common.type);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Store %s into %s via Convert/Attach\n",
+ acpi_ut_get_object_type_name (source_desc),
+ acpi_ut_get_object_type_name (new_desc)));
+ }
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Storing %s (%p) directly into node (%p), no implicit conversion\n",
+ acpi_ut_get_object_type_name (source_desc), source_desc, node));
+
+ /* No conversions for all other types. Just attach the source object */
+
+ status = acpi_ns_attach_object (node, source_desc, ACPI_GET_OBJECT_TYPE (source_desc));
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
new file mode 100644
index 000000000000..d3677feb07fd
--- /dev/null
+++ b/drivers/acpi/executer/exstoren.c
@@ -0,0 +1,306 @@
+
+/******************************************************************************
+ *
+ * Module Name: exstoren - AML Interpreter object store support,
+ * Store to Node (namespace object)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exstoren")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_resolve_object
+ *
+ * PARAMETERS: source_desc_ptr - Pointer to the source object
+ * target_type - Current type of the target
+ * walk_state - Current walk state
+ *
+ * RETURN: Status, resolved object in source_desc_ptr.
+ *
+ * DESCRIPTION: Resolve an object. If the object is a reference, dereference
+ * it and return the actual object in the source_desc_ptr.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_resolve_object (
+ union acpi_operand_object **source_desc_ptr,
+ acpi_object_type target_type,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *source_desc = *source_desc_ptr;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_resolve_object");
+
+
+ /*
+ * Ensure we have a Target that can be stored to
+ */
+ switch (target_type) {
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ /*
+ * These cases all require only Integers or values that
+ * can be converted to Integers (Strings or Buffers)
+ */
+
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * Stores into a Field/Region or into a Integer/Buffer/String
+ * are all essentially the same. This case handles the
+ * "interchangeable" types Integer, String, and Buffer.
+ */
+ if (ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) {
+ /* Resolve a reference object first */
+
+ status = acpi_ex_resolve_to_value (source_desc_ptr, walk_state);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+ }
+
+ /* For copy_object, no further validation necessary */
+
+ if (walk_state->opcode == AML_COPY_OP) {
+ break;
+ }
+
+ /*
+ * Must have a Integer, Buffer, or String
+ */
+ if ((ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER) &&
+ (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) &&
+ (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING) &&
+ !((ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) && (source_desc->reference.opcode == AML_LOAD_OP))) {
+ /*
+ * Conversion successful but still not a valid type
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Cannot assign type %s to %s (must be type Int/Str/Buf)\n",
+ acpi_ut_get_object_type_name (source_desc),
+ acpi_ut_get_type_name (target_type)));
+ status = AE_AML_OPERAND_TYPE;
+ }
+ break;
+
+
+ case ACPI_TYPE_LOCAL_ALIAS:
+ case ACPI_TYPE_LOCAL_METHOD_ALIAS:
+
+ /*
+ * Aliases are resolved by acpi_ex_prep_operands
+ */
+ ACPI_REPORT_ERROR (("Store into Alias - should never happen\n"));
+ status = AE_AML_INTERNAL;
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+ default:
+
+ /*
+ * All other types than Alias and the various Fields come here,
+ * including the untyped case - ACPI_TYPE_ANY.
+ */
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_store_object_to_object
+ *
+ * PARAMETERS: source_desc - Object to store
+ * dest_desc - Object to receive a copy of the source
+ * new_desc - New object if dest_desc is obsoleted
+ * walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: "Store" an object to another object. This may include
+ * converting the source type to the target type (implicit
+ * conversion), and a copy of the value of the source to
+ * the target.
+ *
+ * The Assignment of an object to another (not named) object
+ * is handled here.
+ * The Source passed in will replace the current value (if any)
+ * with the input value.
+ *
+ * When storing into an object the data is converted to the
+ * target object type then stored in the object. This means
+ * that the target object type (for an initialized target) will
+ * not be changed by a store operation.
+ *
+ * This module allows destination types of Number, String,
+ * Buffer, and Package.
+ *
+ * Assumes parameters are already validated. NOTE: source_desc
+ * resolution (from a reference object) must be performed by
+ * the caller if necessary.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_store_object_to_object (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *dest_desc,
+ union acpi_operand_object **new_desc,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *actual_src_desc;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_object", source_desc);
+
+
+ actual_src_desc = source_desc;
+ if (!dest_desc) {
+ /*
+ * There is no destination object (An uninitialized node or
+ * package element), so we can simply copy the source object
+ * creating a new destination object
+ */
+ status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, new_desc, walk_state);
+ return_ACPI_STATUS (status);
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_GET_OBJECT_TYPE (dest_desc)) {
+ /*
+ * The source type does not match the type of the destination.
+ * Perform the "implicit conversion" of the source to the current type
+ * of the target as per the ACPI specification.
+ *
+ * If no conversion performed, actual_src_desc = source_desc.
+ * Otherwise, actual_src_desc is a temporary object to hold the
+ * converted object.
+ */
+ status = acpi_ex_convert_to_target_type (ACPI_GET_OBJECT_TYPE (dest_desc),
+ source_desc, &actual_src_desc, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (source_desc == actual_src_desc) {
+ /*
+ * No conversion was performed. Return the source_desc as the
+ * new object.
+ */
+ *new_desc = source_desc;
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ /*
+ * We now have two objects of identical types, and we can perform a
+ * copy of the *value* of the source object.
+ */
+ switch (ACPI_GET_OBJECT_TYPE (dest_desc)) {
+ case ACPI_TYPE_INTEGER:
+
+ dest_desc->integer.value = actual_src_desc->integer.value;
+
+ /* Truncate value if we are executing from a 32-bit ACPI table */
+
+ acpi_ex_truncate_for32bit_table (dest_desc);
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ status = acpi_ex_store_string_to_string (actual_src_desc, dest_desc);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ /*
+ * Note: There is different store behavior depending on the original
+ * source type
+ */
+ status = acpi_ex_store_buffer_to_buffer (actual_src_desc, dest_desc);
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+
+ status = acpi_ut_copy_iobject_to_iobject (actual_src_desc, &dest_desc,
+ walk_state);
+ break;
+
+ default:
+ /*
+ * All other types come here.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Store into type %s not implemented\n",
+ acpi_ut_get_object_type_name (dest_desc)));
+
+ status = AE_NOT_IMPLEMENTED;
+ break;
+ }
+
+ if (actual_src_desc != source_desc) {
+ /* Delete the intermediate (temporary) source object */
+
+ acpi_ut_remove_reference (actual_src_desc);
+ }
+
+ *new_desc = dest_desc;
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
new file mode 100644
index 000000000000..05e1ecae8d92
--- /dev/null
+++ b/drivers/acpi/executer/exstorob.c
@@ -0,0 +1,216 @@
+
+/******************************************************************************
+ *
+ * Module Name: exstorob - AML Interpreter object store support, store to object
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exstorob")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_store_buffer_to_buffer
+ *
+ * PARAMETERS: source_desc - Source object to copy
+ * target_desc - Destination object of the copy
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Copy a buffer object to another buffer object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_store_buffer_to_buffer (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *target_desc)
+{
+ u32 length;
+ u8 *buffer;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_store_buffer_to_buffer", source_desc);
+
+
+ /* We know that source_desc is a buffer by now */
+
+ buffer = (u8 *) source_desc->buffer.pointer;
+ length = source_desc->buffer.length;
+
+ /*
+ * If target is a buffer of length zero or is a static buffer,
+ * allocate a new buffer of the proper length
+ */
+ if ((target_desc->buffer.length == 0) ||
+ (target_desc->common.flags & AOPOBJ_STATIC_POINTER)) {
+ target_desc->buffer.pointer = ACPI_MEM_ALLOCATE (length);
+ if (!target_desc->buffer.pointer) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ target_desc->buffer.length = length;
+ }
+
+ /* Copy source buffer to target buffer */
+
+ if (length <= target_desc->buffer.length) {
+ /* Clear existing buffer and copy in the new one */
+
+ ACPI_MEMSET (target_desc->buffer.pointer, 0, target_desc->buffer.length);
+ ACPI_MEMCPY (target_desc->buffer.pointer, buffer, length);
+
+#ifdef ACPI_OBSOLETE_BEHAVIOR
+ /*
+ * NOTE: ACPI versions up to 3.0 specified that the buffer must be
+ * truncated if the string is smaller than the buffer. However, "other"
+ * implementations of ACPI never did this and thus became the defacto
+ * standard. ACPi 3.0_a changes this behavior such that the buffer
+ * is no longer truncated.
+ */
+
+ /*
+ * OBSOLETE BEHAVIOR:
+ * If the original source was a string, we must truncate the buffer,
+ * according to the ACPI spec. Integer-to-Buffer and Buffer-to-Buffer
+ * copy must not truncate the original buffer.
+ */
+ if (original_src_type == ACPI_TYPE_STRING) {
+ /* Set the new length of the target */
+
+ target_desc->buffer.length = length;
+ }
+#endif
+ }
+ else {
+ /* Truncate the source, copy only what will fit */
+
+ ACPI_MEMCPY (target_desc->buffer.pointer, buffer, target_desc->buffer.length);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Truncating source buffer from %X to %X\n",
+ length, target_desc->buffer.length));
+ }
+
+ /* Copy flags */
+
+ target_desc->buffer.flags = source_desc->buffer.flags;
+ target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_store_string_to_string
+ *
+ * PARAMETERS: source_desc - Source object to copy
+ * target_desc - Destination object of the copy
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Copy a String object to another String object
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_store_string_to_string (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *target_desc)
+{
+ u32 length;
+ u8 *buffer;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_store_string_to_string", source_desc);
+
+
+ /* We know that source_desc is a string by now */
+
+ buffer = (u8 *) source_desc->string.pointer;
+ length = source_desc->string.length;
+
+ /*
+ * Replace existing string value if it will fit and the string
+ * pointer is not a static pointer (part of an ACPI table)
+ */
+ if ((length < target_desc->string.length) &&
+ (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
+ /*
+ * String will fit in existing non-static buffer.
+ * Clear old string and copy in the new one
+ */
+ ACPI_MEMSET (target_desc->string.pointer, 0, (acpi_size) target_desc->string.length + 1);
+ ACPI_MEMCPY (target_desc->string.pointer, buffer, length);
+ }
+ else {
+ /*
+ * Free the current buffer, then allocate a new buffer
+ * large enough to hold the value
+ */
+ if (target_desc->string.pointer &&
+ (!(target_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
+ /* Only free if not a pointer into the DSDT */
+
+ ACPI_MEM_FREE (target_desc->string.pointer);
+ }
+
+ target_desc->string.pointer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1);
+ if (!target_desc->string.pointer) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ target_desc->common.flags &= ~AOPOBJ_STATIC_POINTER;
+ ACPI_MEMCPY (target_desc->string.pointer, buffer, length);
+ }
+
+ /* Set the new target length */
+
+ target_desc->string.length = length;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
new file mode 100644
index 000000000000..f92efc512890
--- /dev/null
+++ b/drivers/acpi/executer/exsystem.c
@@ -0,0 +1,378 @@
+
+/******************************************************************************
+ *
+ * Module Name: exsystem - Interface to OS services
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/acevents.h>
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exsystem")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_wait_semaphore
+ *
+ * PARAMETERS: Semaphore - OSD semaphore to wait on
+ * Timeout - Max time to wait
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implements a semaphore wait with a check to see if the
+ * semaphore is available immediately. If it is not, the
+ * interpreter is released.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_wait_semaphore (
+ acpi_handle semaphore,
+ u16 timeout)
+{
+ acpi_status status;
+ acpi_status status2;
+
+
+ ACPI_FUNCTION_TRACE ("ex_system_wait_semaphore");
+
+
+ status = acpi_os_wait_semaphore (semaphore, 1, 0);
+ if (ACPI_SUCCESS (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (status == AE_TIME) {
+ /* We must wait, so unlock the interpreter */
+
+ acpi_ex_exit_interpreter ();
+
+ status = acpi_os_wait_semaphore (semaphore, 1, timeout);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*** Thread awake after blocking, %s\n",
+ acpi_format_exception (status)));
+
+ /* Reacquire the interpreter */
+
+ status2 = acpi_ex_enter_interpreter ();
+ if (ACPI_FAILURE (status2)) {
+ /* Report fatal error, could not acquire interpreter */
+
+ return_ACPI_STATUS (status2);
+ }
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_do_stall
+ *
+ * PARAMETERS: how_long - The amount of time to stall,
+ * in microseconds
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Suspend running thread for specified amount of time.
+ * Note: ACPI specification requires that Stall() does not
+ * relinquish the processor, and delays longer than 100 usec
+ * should use Sleep() instead. We allow stalls up to 255 usec
+ * for compatibility with other interpreters and existing BIOSs.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_do_stall (
+ u32 how_long)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (how_long > 255) /* 255 microseconds */ {
+ /*
+ * Longer than 255 usec, this is an error
+ *
+ * (ACPI specifies 100 usec as max, but this gives some slack in
+ * order to support existing BIOSs)
+ */
+ ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", how_long));
+ status = AE_AML_OPERAND_VALUE;
+ }
+ else {
+ acpi_os_stall (how_long);
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_do_suspend
+ *
+ * PARAMETERS: how_long - The amount of time to suspend,
+ * in milliseconds
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Suspend running thread for specified amount of time.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_do_suspend (
+ acpi_integer how_long)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Since this thread will sleep, we must release the interpreter */
+
+ acpi_ex_exit_interpreter ();
+
+ acpi_os_sleep (how_long);
+
+ /* And now we must get the interpreter again */
+
+ status = acpi_ex_enter_interpreter ();
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_acquire_mutex
+ *
+ * PARAMETERS: *time_desc - The 'time to delay' object descriptor
+ * *obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML. This function will cause a lock to be generated
+ * for the Mutex pointed to by obj_desc.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_acquire_mutex (
+ union acpi_operand_object *time_desc,
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_system_acquire_mutex", obj_desc);
+
+
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Support for the _GL_ Mutex object -- go get the global lock
+ */
+ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
+ status = acpi_ev_acquire_global_lock ((u16) time_desc->integer.value);
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ex_system_wait_semaphore (obj_desc->mutex.semaphore,
+ (u16) time_desc->integer.value);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_release_mutex
+ *
+ * PARAMETERS: *obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML. This operation is a request to release a
+ * previously acquired Mutex. If the Mutex variable is set then
+ * it will be decremented.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_release_mutex (
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_system_release_mutex");
+
+
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Support for the _GL_ Mutex object -- release the global lock
+ */
+ if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
+ status = acpi_ev_release_global_lock ();
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_os_signal_semaphore (obj_desc->mutex.semaphore, 1);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_signal_event
+ *
+ * PARAMETERS: *obj_desc - The object descriptor for this op
+ *
+ * RETURN: AE_OK
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_signal_event (
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_system_signal_event");
+
+
+ if (obj_desc) {
+ status = acpi_os_signal_semaphore (obj_desc->event.semaphore, 1);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_wait_event
+ *
+ * PARAMETERS: *time_desc - The 'time to delay' object descriptor
+ * *obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Provides an access point to perform synchronization operations
+ * within the AML. This operation is a request to wait for an
+ * event.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_wait_event (
+ union acpi_operand_object *time_desc,
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ex_system_wait_event");
+
+
+ if (obj_desc) {
+ status = acpi_ex_system_wait_semaphore (obj_desc->event.semaphore,
+ (u16) time_desc->integer.value);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_system_reset_event
+ *
+ * PARAMETERS: *obj_desc - The object descriptor for this op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Reset an event to a known state.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_system_reset_event (
+ union acpi_operand_object *obj_desc)
+{
+ acpi_status status = AE_OK;
+ void *temp_semaphore;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * We are going to simply delete the existing semaphore and
+ * create a new one!
+ */
+ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0, &temp_semaphore);
+ if (ACPI_SUCCESS (status)) {
+ (void) acpi_os_delete_semaphore (obj_desc->event.semaphore);
+ obj_desc->event.semaphore = temp_semaphore;
+ }
+
+ return (status);
+}
+
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
new file mode 100644
index 000000000000..40c6abb8b49a
--- /dev/null
+++ b/drivers/acpi/executer/exutils.c
@@ -0,0 +1,378 @@
+
+/******************************************************************************
+ *
+ * Module Name: exutils - interpreter/scanner utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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.
+ */
+
+
+/*
+ * DEFINE_AML_GLOBALS is tested in amlcode.h
+ * to determine whether certain global names should be "defined" or only
+ * "declared" in the current compilation. This enhances maintainability
+ * by enabling a single header file to embody all knowledge of the names
+ * in question.
+ *
+ * Exactly one module of any executable should #define DEFINE_GLOBALS
+ * before #including the header files which use this convention. The
+ * names in question will be defined and initialized in that module,
+ * and declared as extern in all other modules which #include those
+ * header files.
+ */
+
+#define DEFINE_AML_GLOBALS
+
+#include <acpi/acpi.h>
+#include <acpi/acinterp.h>
+#include <acpi/amlcode.h>
+#include <acpi/acevents.h>
+
+#define _COMPONENT ACPI_EXECUTER
+ ACPI_MODULE_NAME ("exutils")
+
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_enter_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ * the interpreter region is a fatal system error
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ex_enter_interpreter (void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE ("ex_enter_interpreter");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_EXECUTE);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not acquire interpreter mutex\n"));
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_exit_interpreter
+ *
+ * PARAMETERS: None
+ *
+ * DESCRIPTION: Exit the interpreter execution region
+ *
+ * Cases where the interpreter is unlocked:
+ * 1) Completion of the execution of a control method
+ * 2) Method blocked on a Sleep() AML opcode
+ * 3) Method blocked on an Acquire() AML opcode
+ * 4) Method blocked on a Wait() AML opcode
+ * 5) Method blocked to acquire the global lock
+ * 6) Method blocked to execute a serialized control method that is
+ * already executing
+ * 7) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_exit_interpreter (void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ex_exit_interpreter");
+
+
+ status = acpi_ut_release_mutex (ACPI_MTX_EXECUTE);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not release interpreter mutex\n"));
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_truncate_for32bit_table
+ *
+ * PARAMETERS: obj_desc - Object to be truncated
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
+ * belongs to a 32-bit ACPI table.
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_truncate_for32bit_table (
+ union acpi_operand_object *obj_desc)
+{
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * Object must be a valid number and we must be executing
+ * a control method
+ */
+ if ((!obj_desc) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc) != ACPI_TYPE_INTEGER)) {
+ return;
+ }
+
+ if (acpi_gbl_integer_byte_width == 4) {
+ /*
+ * We are running a method that exists in a 32-bit ACPI table.
+ * Truncate the value to 32 bits by zeroing out the upper 32-bit field
+ */
+ obj_desc->integer.value &= (acpi_integer) ACPI_UINT32_MAX;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_acquire_global_lock
+ *
+ * PARAMETERS: field_flags - Flags with Lock rule:
+ * always_lock or never_lock
+ *
+ * RETURN: TRUE/FALSE indicating whether the lock was actually acquired
+ *
+ * DESCRIPTION: Obtain the global lock and keep track of this fact via two
+ * methods. A global variable keeps the state of the lock, and
+ * the state is returned to the caller.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ex_acquire_global_lock (
+ u32 field_flags)
+{
+ u8 locked = FALSE;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ex_acquire_global_lock");
+
+
+ /* Only attempt lock if the always_lock bit is set */
+
+ if (field_flags & AML_FIELD_LOCK_RULE_MASK) {
+ /* We should attempt to get the lock, wait forever */
+
+ status = acpi_ev_acquire_global_lock (ACPI_WAIT_FOREVER);
+ if (ACPI_SUCCESS (status)) {
+ locked = TRUE;
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not acquire Global Lock, %s\n",
+ acpi_format_exception (status)));
+ }
+ }
+
+ return_VALUE (locked);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_release_global_lock
+ *
+ * PARAMETERS: locked_by_me - Return value from corresponding call to
+ * acquire_global_lock.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release the global lock if it is locked.
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_release_global_lock (
+ u8 locked_by_me)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ex_release_global_lock");
+
+
+ /* Only attempt unlock if the caller locked it */
+
+ if (locked_by_me) {
+ /* OK, now release the lock */
+
+ status = acpi_ev_release_global_lock ();
+ if (ACPI_FAILURE (status)) {
+ /* Report the error, but there isn't much else we can do */
+
+ ACPI_REPORT_ERROR (("Could not release ACPI Global Lock, %s\n",
+ acpi_format_exception (status)));
+ }
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_digits_needed
+ *
+ * PARAMETERS: Value - Value to be represented
+ * Base - Base of representation
+ *
+ * RETURN: the number of digits needed to represent Value in Base
+ *
+ ******************************************************************************/
+
+u32
+acpi_ex_digits_needed (
+ acpi_integer value,
+ u32 base)
+{
+ u32 num_digits;
+ acpi_integer current_value;
+
+
+ ACPI_FUNCTION_TRACE ("ex_digits_needed");
+
+
+ /* acpi_integer is unsigned, so we don't worry about a '-' prefix */
+
+ if (value == 0) {
+ return_VALUE (1);
+ }
+
+ current_value = value;
+ num_digits = 0;
+
+ /* Count the digits in the requested base */
+
+ while (current_value) {
+ (void) acpi_ut_short_divide (current_value, base, &current_value, NULL);
+ num_digits++;
+ }
+
+ return_VALUE (num_digits);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_eisa_id_to_string
+ *
+ * PARAMETERS: numeric_id - EISA ID to be converted
+ * out_string - Where to put the converted string (8 bytes)
+ *
+ * DESCRIPTION: Convert a numeric EISA ID to string representation
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_eisa_id_to_string (
+ u32 numeric_id,
+ char *out_string)
+{
+ u32 eisa_id;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Swap ID to big-endian to get contiguous bits */
+
+ eisa_id = acpi_ut_dword_byte_swap (numeric_id);
+
+ out_string[0] = (char) ('@' + (((unsigned long) eisa_id >> 26) & 0x1f));
+ out_string[1] = (char) ('@' + ((eisa_id >> 21) & 0x1f));
+ out_string[2] = (char) ('@' + ((eisa_id >> 16) & 0x1f));
+ out_string[3] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 12);
+ out_string[4] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 8);
+ out_string[5] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 4);
+ out_string[6] = acpi_ut_hex_to_ascii_char ((acpi_integer) eisa_id, 0);
+ out_string[7] = 0;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_unsigned_integer_to_string
+ *
+ * PARAMETERS: Value - Value to be converted
+ * out_string - Where to put the converted string (8 bytes)
+ *
+ * RETURN: Convert a number to string representation
+ *
+ ******************************************************************************/
+
+void
+acpi_ex_unsigned_integer_to_string (
+ acpi_integer value,
+ char *out_string)
+{
+ u32 count;
+ u32 digits_needed;
+ u32 remainder;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ digits_needed = acpi_ex_digits_needed (value, 10);
+ out_string[digits_needed] = 0;
+
+ for (count = digits_needed; count > 0; count--) {
+ (void) acpi_ut_short_divide (value, 10, &value, &remainder);
+ out_string[count-1] = (char) ('0' + remainder);\
+ }
+}
+
+#endif
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
new file mode 100644
index 000000000000..14192ee55f8f
--- /dev/null
+++ b/drivers/acpi/fan.c
@@ -0,0 +1,302 @@
+/*
+ * acpi_fan.c - ACPI Fan Driver ($Revision: 29 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define ACPI_FAN_COMPONENT 0x00200000
+#define ACPI_FAN_CLASS "fan"
+#define ACPI_FAN_HID "PNP0C0B"
+#define ACPI_FAN_DRIVER_NAME "ACPI Fan Driver"
+#define ACPI_FAN_DEVICE_NAME "Fan"
+#define ACPI_FAN_FILE_STATE "state"
+#define ACPI_FAN_NOTIFY_STATUS 0x80
+
+#define _COMPONENT ACPI_FAN_COMPONENT
+ACPI_MODULE_NAME ("acpi_fan")
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION(ACPI_FAN_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int acpi_fan_add (struct acpi_device *device);
+static int acpi_fan_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_fan_driver = {
+ .name = ACPI_FAN_DRIVER_NAME,
+ .class = ACPI_FAN_CLASS,
+ .ids = ACPI_FAN_HID,
+ .ops = {
+ .add = acpi_fan_add,
+ .remove = acpi_fan_remove,
+ },
+};
+
+struct acpi_fan {
+ acpi_handle handle;
+};
+
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_fan_dir;
+
+
+static int
+acpi_fan_read_state (struct seq_file *seq, void *offset)
+{
+ struct acpi_fan *fan = seq->private;
+ int state = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_fan_read_state");
+
+ if (fan) {
+ if (acpi_bus_get_power(fan->handle, &state))
+ seq_printf(seq, "status: ERROR\n");
+ else
+ seq_printf(seq, "status: %s\n",
+ !state?"on":"off");
+ }
+ return_VALUE(0);
+}
+
+static int acpi_fan_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_fan_read_state, PDE(inode)->data);
+}
+
+static ssize_t
+acpi_fan_write_state (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ int result = 0;
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_fan *fan = (struct acpi_fan *) m->private;
+ char state_string[12] = {'\0'};
+
+ ACPI_FUNCTION_TRACE("acpi_fan_write_state");
+
+ if (!fan || (count > sizeof(state_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(state_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ state_string[count] = '\0';
+
+ result = acpi_bus_set_power(fan->handle,
+ simple_strtoul(state_string, NULL, 0));
+ if (result)
+ return_VALUE(result);
+
+ return_VALUE(count);
+}
+
+static struct file_operations acpi_fan_state_ops = {
+ .open = acpi_fan_state_open_fs,
+ .read = seq_read,
+ .write = acpi_fan_write_state,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int
+acpi_fan_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_fan_add_fs");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_fan_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ acpi_device_dir(device)->owner = THIS_MODULE;
+ }
+
+ /* 'status' [R/W] */
+ entry = create_proc_entry(ACPI_FAN_FILE_STATE,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_FAN_FILE_STATE));
+ else {
+ entry->proc_fops = &acpi_fan_state_ops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_fan_remove_fs (
+ struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_fan_remove_fs");
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_FAN_FILE_STATE,
+ acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device), acpi_fan_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_fan_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_fan *fan = NULL;
+ int state = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_fan_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ fan = kmalloc(sizeof(struct acpi_fan), GFP_KERNEL);
+ if (!fan)
+ return_VALUE(-ENOMEM);
+ memset(fan, 0, sizeof(struct acpi_fan));
+
+ fan->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_FAN_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_FAN_CLASS);
+ acpi_driver_data(device) = fan;
+
+ result = acpi_bus_get_power(fan->handle, &state);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error reading power state\n"));
+ goto end;
+ }
+
+ result = acpi_fan_add_fs(device);
+ if (result)
+ goto end;
+
+ printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
+ acpi_device_name(device), acpi_device_bid(device),
+ !device->power.state?"on":"off");
+
+end:
+ if (result)
+ kfree(fan);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_fan_remove (
+ struct acpi_device *device,
+ int type)
+{
+ struct acpi_fan *fan = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_fan_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ fan = (struct acpi_fan *) acpi_driver_data(device);
+
+ acpi_fan_remove_fs(device);
+
+ kfree(fan);
+
+ return_VALUE(0);
+}
+
+
+static int __init
+acpi_fan_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_fan_init");
+
+ acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
+ if (!acpi_fan_dir)
+ return_VALUE(-ENODEV);
+ acpi_fan_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&acpi_fan_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+
+static void __exit
+acpi_fan_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_fan_exit");
+
+ acpi_bus_unregister_driver(&acpi_fan_driver);
+
+ remove_proc_entry(ACPI_FAN_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+
+
+module_init(acpi_fan_init);
+module_exit(acpi_fan_exit);
+
diff --git a/drivers/acpi/hardware/Makefile b/drivers/acpi/hardware/Makefile
new file mode 100644
index 000000000000..438ad373b9ad
--- /dev/null
+++ b/drivers/acpi/hardware/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := hwacpi.o hwgpe.o hwregs.o hwsleep.o
+
+obj-$(ACPI_FUTURE_USAGE) += hwtimer.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
new file mode 100644
index 000000000000..529e922bdc85
--- /dev/null
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -0,0 +1,230 @@
+
+/******************************************************************************
+ *
+ * Module Name: hwacpi - ACPI Hardware Initialization/Mode Interface
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_HARDWARE
+ ACPI_MODULE_NAME ("hwacpi")
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initialize and validate various ACPI registers
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_initialize (
+ void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("hw_initialize");
+
+
+ /* We must have the ACPI tables by the time we get here */
+
+ if (!acpi_gbl_FADT) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "A FADT is not loaded\n"));
+
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ /* Sanity check the FADT for valid values */
+
+ status = acpi_ut_validate_fadt ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_set_mode
+ *
+ * PARAMETERS: Mode - SYS_MODE_ACPI or SYS_MODE_LEGACY
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Transitions the system into the requested mode.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_set_mode (
+ u32 mode)
+{
+
+ acpi_status status;
+ u32 retry;
+
+
+ ACPI_FUNCTION_TRACE ("hw_set_mode");
+
+ /*
+ * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
+ * system does not support mode transition.
+ */
+ if (!acpi_gbl_FADT->smi_cmd) {
+ ACPI_REPORT_ERROR (("No SMI_CMD in FADT, mode transition failed.\n"));
+ return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
+ }
+
+ /*
+ * ACPI 2.0 clarified the meaning of ACPI_ENABLE and ACPI_DISABLE
+ * in FADT: If it is zero, enabling or disabling is not supported.
+ * As old systems may have used zero for mode transition,
+ * we make sure both the numbers are zero to determine these
+ * transitions are not supported.
+ */
+ if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
+ ACPI_REPORT_ERROR (("No ACPI mode transition supported in this system (enable/disable both zero)\n"));
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ switch (mode) {
+ case ACPI_SYS_MODE_ACPI:
+
+ /* BIOS should have disabled ALL fixed and GP events */
+
+ status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd,
+ (u32) acpi_gbl_FADT->acpi_enable, 8);
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Attempting to enable ACPI mode\n"));
+ break;
+
+ case ACPI_SYS_MODE_LEGACY:
+
+ /*
+ * BIOS should clear all fixed status bits and restore fixed event
+ * enable bits to default
+ */
+ status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd,
+ (u32) acpi_gbl_FADT->acpi_disable, 8);
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Attempting to enable Legacy (non-ACPI) mode\n"));
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not write mode change, %s\n", acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Some hardware takes a LONG time to switch modes. Give them 3 sec to
+ * do so, but allow faster systems to proceed more quickly.
+ */
+ retry = 3000;
+ while (retry) {
+ if (acpi_hw_get_mode() == mode) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode));
+ return_ACPI_STATUS (AE_OK);
+ }
+ acpi_os_stall(1000);
+ retry--;
+ }
+
+ ACPI_REPORT_ERROR (("Hardware never changed modes\n"));
+ return_ACPI_STATUS (AE_NO_HARDWARE_RESPONSE);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_get_mode
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: SYS_MODE_ACPI or SYS_MODE_LEGACY
+ *
+ * DESCRIPTION: Return current operating state of system. Determined by
+ * querying the SCI_EN bit.
+ *
+ ******************************************************************************/
+
+u32
+acpi_hw_get_mode (void)
+{
+ acpi_status status;
+ u32 value;
+
+
+ ACPI_FUNCTION_TRACE ("hw_get_mode");
+
+
+ /*
+ * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
+ * system does not support mode transition.
+ */
+ if (!acpi_gbl_FADT->smi_cmd) {
+ return_VALUE (ACPI_SYS_MODE_ACPI);
+ }
+
+ status = acpi_get_register (ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_VALUE (ACPI_SYS_MODE_LEGACY);
+ }
+
+ if (value) {
+ return_VALUE (ACPI_SYS_MODE_ACPI);
+ }
+ else {
+ return_VALUE (ACPI_SYS_MODE_LEGACY);
+ }
+}
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
new file mode 100644
index 000000000000..9ac1d639bf51
--- /dev/null
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -0,0 +1,444 @@
+
+/******************************************************************************
+ *
+ * Module Name: hwgpe - Low level GPE enable/disable/clear functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+
+#define _COMPONENT ACPI_HARDWARE
+ ACPI_MODULE_NAME ("hwgpe")
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_write_gpe_enable_reg
+ *
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be enabled
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write a GPE enable register. Note: The bit for this GPE must
+ * already be cleared or set in the parent register
+ * enable_for_run mask.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_write_gpe_enable_reg (
+ struct acpi_gpe_event_info *gpe_event_info)
+{
+ struct acpi_gpe_register_info *gpe_register_info;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Get the info block for the entire GPE register */
+
+ gpe_register_info = gpe_event_info->register_info;
+ if (!gpe_register_info) {
+ return (AE_NOT_EXIST);
+ }
+
+ /* Write the entire GPE (runtime) enable register */
+
+ status = acpi_hw_low_level_write (8, gpe_register_info->enable_for_run,
+ &gpe_register_info->enable_address);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_clear_gpe
+ *
+ * PARAMETERS: gpe_event_info - Info block for the GPE to be cleared
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear the status bit for a single GPE.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_clear_gpe (
+ struct acpi_gpe_event_info *gpe_event_info)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * Write a one to the appropriate bit in the status register to
+ * clear this GPE.
+ */
+ status = acpi_hw_low_level_write (8, gpe_event_info->register_bit,
+ &gpe_event_info->register_info->status_address);
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_get_gpe_status
+ *
+ * PARAMETERS: gpe_event_info - Info block for the GPE to queried
+ * event_status - Where the GPE status is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return the status of a single GPE.
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_hw_get_gpe_status (
+ struct acpi_gpe_event_info *gpe_event_info,
+ acpi_event_status *event_status)
+{
+ u32 in_byte;
+ u8 register_bit;
+ struct acpi_gpe_register_info *gpe_register_info;
+ acpi_status status;
+ acpi_event_status local_event_status = 0;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (!event_status) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Get the info block for the entire GPE register */
+
+ gpe_register_info = gpe_event_info->register_info;
+
+ /* Get the register bitmask for this GPE */
+
+ register_bit = gpe_event_info->register_bit;
+
+ /* GPE currently enabled? (enabled for runtime?) */
+
+ if (register_bit & gpe_register_info->enable_for_run) {
+ local_event_status |= ACPI_EVENT_FLAG_ENABLED;
+ }
+
+ /* GPE enabled for wake? */
+
+ if (register_bit & gpe_register_info->enable_for_wake) {
+ local_event_status |= ACPI_EVENT_FLAG_WAKE_ENABLED;
+ }
+
+ /* GPE currently active (status bit == 1)? */
+
+ status = acpi_hw_low_level_read (8, &in_byte, &gpe_register_info->status_address);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ if (register_bit & in_byte) {
+ local_event_status |= ACPI_EVENT_FLAG_SET;
+ }
+
+ /* Set return value */
+
+ (*event_status) = local_event_status;
+
+
+unlock_and_exit:
+ return (status);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_disable_gpe_block
+ *
+ * PARAMETERS: gpe_xrupt_info - GPE Interrupt info
+ * gpe_block - Gpe Block info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable all GPEs within a GPE block
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_disable_gpe_block (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block)
+{
+ u32 i;
+ acpi_status status;
+
+
+ /* Examine each GPE Register within the block */
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ /* Disable all GPEs in this register */
+
+ status = acpi_hw_low_level_write (8, 0x00,
+ &gpe_block->register_info[i].enable_address);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_clear_gpe_block
+ *
+ * PARAMETERS: gpe_xrupt_info - GPE Interrupt info
+ * gpe_block - Gpe Block info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear status bits for all GPEs within a GPE block
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_clear_gpe_block (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block)
+{
+ u32 i;
+ acpi_status status;
+
+
+ /* Examine each GPE Register within the block */
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ /* Clear status on all GPEs in this register */
+
+ status = acpi_hw_low_level_write (8, 0xFF,
+ &gpe_block->register_info[i].status_address);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_enable_runtime_gpe_block
+ *
+ * PARAMETERS: gpe_xrupt_info - GPE Interrupt info
+ * gpe_block - Gpe Block info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable all "runtime" GPEs within a GPE block. (Includes
+ * combination wake/run GPEs.)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_enable_runtime_gpe_block (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block)
+{
+ u32 i;
+ acpi_status status;
+
+
+ /* NOTE: assumes that all GPEs are currently disabled */
+
+ /* Examine each GPE Register within the block */
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ if (!gpe_block->register_info[i].enable_for_run) {
+ continue;
+ }
+
+ /* Enable all "runtime" GPEs in this register */
+
+ status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_run,
+ &gpe_block->register_info[i].enable_address);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_enable_wakeup_gpe_block
+ *
+ * PARAMETERS: gpe_xrupt_info - GPE Interrupt info
+ * gpe_block - Gpe Block info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable all "wake" GPEs within a GPE block. (Includes
+ * combination wake/run GPEs.)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_enable_wakeup_gpe_block (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block)
+{
+ u32 i;
+ acpi_status status;
+
+
+ /* Examine each GPE Register within the block */
+
+ for (i = 0; i < gpe_block->register_count; i++) {
+ if (!gpe_block->register_info[i].enable_for_wake) {
+ continue;
+ }
+
+ /* Enable all "wake" GPEs in this register */
+
+ status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_wake,
+ &gpe_block->register_info[i].enable_address);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_disable_all_gpes
+ *
+ * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Disable and clear all GPEs
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_disable_all_gpes (
+ u32 flags)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("hw_disable_all_gpes");
+
+
+ status = acpi_ev_walk_gpe_list (acpi_hw_disable_gpe_block, flags);
+ status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, flags);
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_enable_all_runtime_gpes
+ *
+ * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable all GPEs of the given type
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_enable_all_runtime_gpes (
+ u32 flags)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("hw_enable_all_runtime_gpes");
+
+
+ status = acpi_ev_walk_gpe_list (acpi_hw_enable_runtime_gpe_block, flags);
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_enable_all_wakeup_gpes
+ *
+ * PARAMETERS: Flags - ACPI_NOT_ISR or ACPI_ISR
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable all GPEs of the given type
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_enable_all_wakeup_gpes (
+ u32 flags)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("hw_enable_all_wakeup_gpes");
+
+
+ status = acpi_ev_walk_gpe_list (acpi_hw_enable_wakeup_gpe_block, flags);
+ return_ACPI_STATUS (status);
+}
+
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
new file mode 100644
index 000000000000..91af0c2ddcf7
--- /dev/null
+++ b/drivers/acpi/hardware/hwregs.c
@@ -0,0 +1,850 @@
+
+/*******************************************************************************
+ *
+ * Module Name: hwregs - Read/write access functions for the various ACPI
+ * control and status registers.
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+
+#define _COMPONENT ACPI_HARDWARE
+ ACPI_MODULE_NAME ("hwregs")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_clear_acpi_status
+ *
+ * PARAMETERS: Flags - Lock the hardware or not
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Clears all fixed and general purpose status bits
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_clear_acpi_status (
+ u32 flags)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("hw_clear_acpi_status");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %04X to %04X\n",
+ ACPI_BITMASK_ALL_FIXED_STATUS,
+ (u16) acpi_gbl_FADT->xpm1a_evt_blk.address));
+
+ if (flags & ACPI_MTX_LOCK) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS,
+ ACPI_BITMASK_ALL_FIXED_STATUS);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Clear the fixed events */
+
+ if (acpi_gbl_FADT->xpm1b_evt_blk.address) {
+ status = acpi_hw_low_level_write (16, ACPI_BITMASK_ALL_FIXED_STATUS,
+ &acpi_gbl_FADT->xpm1b_evt_blk);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Clear the GPE Bits in all GPE registers in all GPE blocks */
+
+ status = acpi_ev_walk_gpe_list (acpi_hw_clear_gpe_block, ACPI_ISR);
+
+unlock_and_exit:
+ if (flags & ACPI_MTX_LOCK) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_sleep_type_data
+ *
+ * PARAMETERS: sleep_state - Numeric sleep state
+ * *sleep_type_a - Where SLP_TYPa is returned
+ * *sleep_type_b - Where SLP_TYPb is returned
+ *
+ * RETURN: Status - ACPI status
+ *
+ * DESCRIPTION: Obtain the SLP_TYPa and SLP_TYPb values for the requested sleep
+ * state.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_sleep_type_data (
+ u8 sleep_state,
+ u8 *sleep_type_a,
+ u8 *sleep_type_b)
+{
+ acpi_status status = AE_OK;
+ struct acpi_parameter_info info;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data");
+
+
+ /*
+ * Validate parameters
+ */
+ if ((sleep_state > ACPI_S_STATES_MAX) ||
+ !sleep_type_a || !sleep_type_b) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Evaluate the namespace object containing the values for this state
+ */
+ info.parameters = NULL;
+ status = acpi_ns_evaluate_by_name ((char *) acpi_gbl_sleep_state_names[sleep_state],
+ &info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s while evaluating sleep_state [%s]\n",
+ acpi_format_exception (status), acpi_gbl_sleep_state_names[sleep_state]));
+
+ return_ACPI_STATUS (status);
+ }
+
+ /* Must have a return object */
+
+ if (!info.return_object) {
+ ACPI_REPORT_ERROR (("Missing Sleep State object\n"));
+ status = AE_NOT_EXIST;
+ }
+
+ /* It must be of type Package */
+
+ else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) {
+ ACPI_REPORT_ERROR (("Sleep State object not a Package\n"));
+ status = AE_AML_OPERAND_TYPE;
+ }
+
+ /* The package must have at least two elements */
+
+ else if (info.return_object->package.count < 2) {
+ ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n"));
+ status = AE_AML_NO_OPERAND;
+ }
+
+ /* The first two elements must both be of type Integer */
+
+ else if ((ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[0]) != ACPI_TYPE_INTEGER) ||
+ (ACPI_GET_OBJECT_TYPE (info.return_object->package.elements[1]) != ACPI_TYPE_INTEGER)) {
+ ACPI_REPORT_ERROR (("Sleep State package elements are not both Integers (%s, %s)\n",
+ acpi_ut_get_object_type_name (info.return_object->package.elements[0]),
+ acpi_ut_get_object_type_name (info.return_object->package.elements[1])));
+ status = AE_AML_OPERAND_TYPE;
+ }
+ else {
+ /*
+ * Valid _Sx_ package size, type, and value
+ */
+ *sleep_type_a = (u8) (info.return_object->package.elements[0])->integer.value;
+ *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "While evaluating sleep_state [%s], bad Sleep object %p type %s\n",
+ acpi_gbl_sleep_state_names[sleep_state], info.return_object,
+ acpi_ut_get_object_type_name (info.return_object)));
+ }
+
+ acpi_ut_remove_reference (info.return_object);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_sleep_type_data);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_hw_get_register_bit_mask
+ *
+ * PARAMETERS: register_id - Index of ACPI Register to access
+ *
+ * RETURN: The bit mask to be used when accessing the register
+ *
+ * DESCRIPTION: Map register_id into a register bit mask.
+ *
+ ******************************************************************************/
+
+struct acpi_bit_register_info *
+acpi_hw_get_bit_register_info (
+ u32 register_id)
+{
+ ACPI_FUNCTION_NAME ("hw_get_bit_register_info");
+
+
+ if (register_id > ACPI_BITREG_MAX) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid bit_register ID: %X\n", register_id));
+ return (NULL);
+ }
+
+ return (&acpi_gbl_bit_register_info[register_id]);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_register
+ *
+ * PARAMETERS: register_id - ID of ACPI bit_register to access
+ * return_value - Value that was read from the register
+ * Flags - Lock the hardware or not
+ *
+ * RETURN: Status and the value read from specified Register. Value
+ * returned is normalized to bit0 (is shifted all the way right)
+ *
+ * DESCRIPTION: ACPI bit_register read function.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_register (
+ u32 register_id,
+ u32 *return_value,
+ u32 flags)
+{
+ u32 register_value = 0;
+ struct acpi_bit_register_info *bit_reg_info;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_register");
+
+
+ /* Get the info structure corresponding to the requested ACPI Register */
+
+ bit_reg_info = acpi_hw_get_bit_register_info (register_id);
+ if (!bit_reg_info) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (flags & ACPI_MTX_LOCK) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Read from the register */
+
+ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
+ bit_reg_info->parent_register, &register_value);
+
+ if (flags & ACPI_MTX_LOCK) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ /* Normalize the value that was read */
+
+ register_value = ((register_value & bit_reg_info->access_bit_mask)
+ >> bit_reg_info->bit_position);
+
+ *return_value = register_value;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read value %8.8X register %X\n",
+ register_value, bit_reg_info->parent_register));
+ }
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_register);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_set_register
+ *
+ * PARAMETERS: register_id - ID of ACPI bit_register to access
+ * Value - (only used on write) value to write to the
+ * Register, NOT pre-normalized to the bit pos
+ * Flags - Lock the hardware or not
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: ACPI Bit Register write function.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_set_register (
+ u32 register_id,
+ u32 value,
+ u32 flags)
+{
+ u32 register_value = 0;
+ struct acpi_bit_register_info *bit_reg_info;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("acpi_set_register", register_id);
+
+
+ /* Get the info structure corresponding to the requested ACPI Register */
+
+ bit_reg_info = acpi_hw_get_bit_register_info (register_id);
+ if (!bit_reg_info) {
+ ACPI_REPORT_ERROR (("Bad ACPI HW register_id: %X\n", register_id));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (flags & ACPI_MTX_LOCK) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Always do a register read first so we can insert the new bits */
+
+ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
+ bit_reg_info->parent_register, &register_value);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Decode the Register ID
+ * Register ID = [Register block ID] | [bit ID]
+ *
+ * Check bit ID to fine locate Register offset.
+ * Check Mask to determine Register offset, and then read-write.
+ */
+ switch (bit_reg_info->parent_register) {
+ case ACPI_REGISTER_PM1_STATUS:
+
+ /*
+ * Status Registers are different from the rest. Clear by
+ * writing 1, and writing 0 has no effect. So, the only relevant
+ * information is the single bit we're interested in, all others should
+ * be written as 0 so they will be left unchanged.
+ */
+ value = ACPI_REGISTER_PREPARE_BITS (value,
+ bit_reg_info->bit_position, bit_reg_info->access_bit_mask);
+ if (value) {
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_STATUS, (u16) value);
+ register_value = 0;
+ }
+ break;
+
+
+ case ACPI_REGISTER_PM1_ENABLE:
+
+ ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position,
+ bit_reg_info->access_bit_mask, value);
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_ENABLE, (u16) register_value);
+ break;
+
+
+ case ACPI_REGISTER_PM1_CONTROL:
+
+ /*
+ * Write the PM1 Control register.
+ * Note that at this level, the fact that there are actually TWO
+ * registers (A and B - and B may not exist) is abstracted.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM1 control: Read %X\n", register_value));
+
+ ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position,
+ bit_reg_info->access_bit_mask, value);
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_CONTROL, (u16) register_value);
+ break;
+
+
+ case ACPI_REGISTER_PM2_CONTROL:
+
+ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM2_CONTROL, &register_value);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n",
+ register_value,
+ ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address)));
+
+ ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position,
+ bit_reg_info->access_bit_mask, value);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n",
+ register_value,
+ ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address)));
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM2_CONTROL, (u8) (register_value));
+ break;
+
+
+ default:
+ break;
+ }
+
+
+unlock_and_exit:
+
+ if (flags & ACPI_MTX_LOCK) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ /* Normalize the value that was read */
+
+ ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position));
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n",
+ value, register_value, bit_reg_info->parent_register));
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_set_register);
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_register_read
+ *
+ * PARAMETERS: use_lock - Mutex hw access
+ * register_id - register_iD + Offset
+ * return_value - Value that was read from the register
+ *
+ * RETURN: Status and the value read.
+ *
+ * DESCRIPTION: Acpi register read function. Registers are read at the
+ * given offset.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_register_read (
+ u8 use_lock,
+ u32 register_id,
+ u32 *return_value)
+{
+ u32 value1 = 0;
+ u32 value2 = 0;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("hw_register_read");
+
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ switch (register_id) {
+ case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
+
+ status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->xpm1a_evt_blk);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->xpm1b_evt_blk);
+ value1 |= value2;
+ break;
+
+
+ case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
+
+ status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_xpm1a_enable);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_xpm1b_enable);
+ value1 |= value2;
+ break;
+
+
+ case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
+
+ status = acpi_hw_low_level_read (16, &value1, &acpi_gbl_FADT->xpm1a_cnt_blk);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ status = acpi_hw_low_level_read (16, &value2, &acpi_gbl_FADT->xpm1b_cnt_blk);
+ value1 |= value2;
+ break;
+
+
+ case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
+
+ status = acpi_hw_low_level_read (8, &value1, &acpi_gbl_FADT->xpm2_cnt_blk);
+ break;
+
+
+ case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
+
+ status = acpi_hw_low_level_read (32, &value1, &acpi_gbl_FADT->xpm_tmr_blk);
+ break;
+
+ case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
+
+ status = acpi_os_read_port (acpi_gbl_FADT->smi_cmd, &value1, 8);
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", register_id));
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+unlock_and_exit:
+ if (ACPI_MTX_LOCK == use_lock) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ *return_value = value1;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_register_write
+ *
+ * PARAMETERS: use_lock - Mutex hw access
+ * register_id - register_iD + Offset
+ * Value - The value to write
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acpi register Write function. Registers are written at the
+ * given offset.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_register_write (
+ u8 use_lock,
+ u32 register_id,
+ u32 value)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("hw_register_write");
+
+
+ if (ACPI_MTX_LOCK == use_lock) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_HARDWARE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ switch (register_id) {
+ case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_evt_blk);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_evt_blk);
+ break;
+
+
+ case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access*/
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_xpm1a_enable);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* PM1B is optional */
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_xpm1b_enable);
+ break;
+
+
+ case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_cnt_blk);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_cnt_blk);
+ break;
+
+
+ case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1a_cnt_blk);
+ break;
+
+
+ case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
+
+ status = acpi_hw_low_level_write (16, value, &acpi_gbl_FADT->xpm1b_cnt_blk);
+ break;
+
+
+ case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
+
+ status = acpi_hw_low_level_write (8, value, &acpi_gbl_FADT->xpm2_cnt_blk);
+ break;
+
+
+ case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
+
+ status = acpi_hw_low_level_write (32, value, &acpi_gbl_FADT->xpm_tmr_blk);
+ break;
+
+
+ case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
+
+ /* SMI_CMD is currently always in IO space */
+
+ status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, value, 8);
+ break;
+
+
+ default:
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+unlock_and_exit:
+ if (ACPI_MTX_LOCK == use_lock) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_HARDWARE);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_low_level_read
+ *
+ * PARAMETERS: Width - 8, 16, or 32
+ * Value - Where the value is returned
+ * Reg - GAS register structure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Read from either memory or IO space.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_low_level_read (
+ u32 width,
+ u32 *value,
+ struct acpi_generic_address *reg)
+{
+ u64 address;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_NAME ("hw_low_level_read");
+
+
+ /*
+ * Must have a valid pointer to a GAS structure, and
+ * a non-zero address within. However, don't return an error
+ * because the PM1A/B code must not fail if B isn't present.
+ */
+ if (!reg) {
+ return (AE_OK);
+ }
+
+ /* Get a local copy of the address. Handles possible alignment issues */
+
+ ACPI_MOVE_64_TO_64 (&address, &reg->address);
+ if (!address) {
+ return (AE_OK);
+ }
+ *value = 0;
+
+ /*
+ * Two address spaces supported: Memory or IO.
+ * PCI_Config is not supported here because the GAS struct is insufficient
+ */
+ switch (reg->address_space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+
+ status = acpi_os_read_memory (
+ (acpi_physical_address) address,
+ value, width);
+ break;
+
+
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+
+ status = acpi_os_read_port ((acpi_io_address) address,
+ value, width);
+ break;
+
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unsupported address space: %X\n", reg->address_space_id));
+ return (AE_BAD_PARAMETER);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
+ *value, width,
+ ACPI_FORMAT_UINT64 (address),
+ acpi_ut_get_region_name (reg->address_space_id)));
+
+ return (status);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_hw_low_level_write
+ *
+ * PARAMETERS: Width - 8, 16, or 32
+ * Value - To be written
+ * Reg - GAS register structure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write to either memory or IO space.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_hw_low_level_write (
+ u32 width,
+ u32 value,
+ struct acpi_generic_address *reg)
+{
+ u64 address;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_NAME ("hw_low_level_write");
+
+
+ /*
+ * Must have a valid pointer to a GAS structure, and
+ * a non-zero address within. However, don't return an error
+ * because the PM1A/B code must not fail if B isn't present.
+ */
+ if (!reg) {
+ return (AE_OK);
+ }
+
+ /* Get a local copy of the address. Handles possible alignment issues */
+
+ ACPI_MOVE_64_TO_64 (&address, &reg->address);
+ if (!address) {
+ return (AE_OK);
+ }
+
+ /*
+ * Two address spaces supported: Memory or IO.
+ * PCI_Config is not supported here because the GAS struct is insufficient
+ */
+ switch (reg->address_space_id) {
+ case ACPI_ADR_SPACE_SYSTEM_MEMORY:
+
+ status = acpi_os_write_memory (
+ (acpi_physical_address) address,
+ value, width);
+ break;
+
+
+ case ACPI_ADR_SPACE_SYSTEM_IO:
+
+ status = acpi_os_write_port ((acpi_io_address) address,
+ value, width);
+ break;
+
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unsupported address space: %X\n", reg->address_space_id));
+ return (AE_BAD_PARAMETER);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
+ value, width,
+ ACPI_FORMAT_UINT64 (address),
+ acpi_ut_get_region_name (reg->address_space_id)));
+
+ return (status);
+}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
new file mode 100644
index 000000000000..77b3e9a8550b
--- /dev/null
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -0,0 +1,582 @@
+
+/******************************************************************************
+ *
+ * Name: hwsleep.c - ACPI Hardware Sleep/Wake Interface
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+
+#define _COMPONENT ACPI_HARDWARE
+ ACPI_MODULE_NAME ("hwsleep")
+
+
+#define METHOD_NAME__BFS "\\_BFS"
+#define METHOD_NAME__GTS "\\_GTS"
+#define METHOD_NAME__PTS "\\_PTS"
+#define METHOD_NAME__SST "\\_SI._SST"
+#define METHOD_NAME__WAK "\\_WAK"
+
+#define ACPI_SST_INDICATOR_OFF 0
+#define ACPI_SST_WORKING 1
+#define ACPI_SST_WAKING 2
+#define ACPI_SST_SLEEPING 3
+#define ACPI_SST_SLEEP_CONTEXT 4
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_set_firmware_waking_vector
+ *
+ * PARAMETERS: physical_address - Physical address of ACPI real mode
+ * entry point.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: access function for d_firmware_waking_vector field in FACS
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_set_firmware_waking_vector (
+ acpi_physical_address physical_address)
+{
+
+ ACPI_FUNCTION_TRACE ("acpi_set_firmware_waking_vector");
+
+
+ /* Set the vector */
+
+ if (acpi_gbl_common_fACS.vector_width == 32) {
+ *(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector))
+ = (u32) physical_address;
+ }
+ else {
+ *acpi_gbl_common_fACS.firmware_waking_vector
+ = physical_address;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_firmware_waking_vector
+ *
+ * PARAMETERS: *physical_address - Output buffer where contents of
+ * the firmware_waking_vector field of
+ * the FACS will be stored.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Access function for firmware_waking_vector field in FACS
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_get_firmware_waking_vector (
+ acpi_physical_address *physical_address)
+{
+
+ ACPI_FUNCTION_TRACE ("acpi_get_firmware_waking_vector");
+
+
+ if (!physical_address) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Get the vector */
+
+ if (acpi_gbl_common_fACS.vector_width == 32) {
+ *physical_address = (acpi_physical_address)
+ *(ACPI_CAST_PTR (u32, acpi_gbl_common_fACS.firmware_waking_vector));
+ }
+ else {
+ *physical_address =
+ *acpi_gbl_common_fACS.firmware_waking_vector;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+#endif
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_enter_sleep_state_prep
+ *
+ * PARAMETERS: sleep_state - Which sleep state to enter
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Prepare to enter a system sleep state (see ACPI 2.0 spec p 231)
+ * This function must execute with interrupts enabled.
+ * We break sleeping into 2 stages so that OSPM can handle
+ * various OS-specific tasks between the two steps.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_enter_sleep_state_prep (
+ u8 sleep_state)
+{
+ acpi_status status;
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_prep");
+
+
+ /*
+ * _PSW methods could be run here to enable wake-on keyboard, LAN, etc.
+ */
+ status = acpi_get_sleep_type_data (sleep_state,
+ &acpi_gbl_sleep_type_a, &acpi_gbl_sleep_type_b);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Setup parameter object */
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = sleep_state;
+
+ /* Run the _PTS and _GTS methods */
+
+ status = acpi_evaluate_object (NULL, METHOD_NAME__PTS, &arg_list, NULL);
+ if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_evaluate_object (NULL, METHOD_NAME__GTS, &arg_list, NULL);
+ if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Setup the argument to _SST */
+
+ switch (sleep_state) {
+ case ACPI_STATE_S0:
+ arg.integer.value = ACPI_SST_WORKING;
+ break;
+
+ case ACPI_STATE_S1:
+ case ACPI_STATE_S2:
+ case ACPI_STATE_S3:
+ arg.integer.value = ACPI_SST_SLEEPING;
+ break;
+
+ case ACPI_STATE_S4:
+ arg.integer.value = ACPI_SST_SLEEP_CONTEXT;
+ break;
+
+ default:
+ arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */
+ break;
+ }
+
+ /* Set the system indicators to show the desired sleep state. */
+
+ status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
+ if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+ ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_enter_sleep_state
+ *
+ * PARAMETERS: sleep_state - Which sleep state to enter
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enter a system sleep state (see ACPI 2.0 spec p 231)
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ *
+ ******************************************************************************/
+
+acpi_status asmlinkage
+acpi_enter_sleep_state (
+ u8 sleep_state)
+{
+ u32 PM1Acontrol;
+ u32 PM1Bcontrol;
+ struct acpi_bit_register_info *sleep_type_reg_info;
+ struct acpi_bit_register_info *sleep_enable_reg_info;
+ u32 in_value;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state");
+
+
+ if ((acpi_gbl_sleep_type_a > ACPI_SLEEP_TYPE_MAX) ||
+ (acpi_gbl_sleep_type_b > ACPI_SLEEP_TYPE_MAX)) {
+ ACPI_REPORT_ERROR (("Sleep values out of range: A=%X B=%X\n",
+ acpi_gbl_sleep_type_a, acpi_gbl_sleep_type_b));
+ return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
+ }
+
+ sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
+ sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
+
+ /* Clear wake status */
+
+ status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Clear all fixed and general purpose status bits */
+
+ status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * 1) Disable/Clear all GPEs
+ * 2) Enable all wakeup GPEs
+ */
+ status = acpi_hw_disable_all_gpes (ACPI_ISR);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ acpi_gbl_system_awake_and_running = FALSE;
+
+ status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get current value of PM1A control */
+
+ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Entering sleep state [S%d]\n", sleep_state));
+
+ /* Clear SLP_EN and SLP_TYP fields */
+
+ PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask);
+ PM1Bcontrol = PM1Acontrol;
+
+ /* Insert SLP_TYP bits */
+
+ PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
+ PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
+
+ /*
+ * We split the writes of SLP_TYP and SLP_EN to workaround
+ * poorly implemented hardware.
+ */
+
+ /* Write #1: fill in SLP_TYP data */
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Insert SLP_ENABLE bit */
+
+ PM1Acontrol |= sleep_enable_reg_info->access_bit_mask;
+ PM1Bcontrol |= sleep_enable_reg_info->access_bit_mask;
+
+ /* Write #2: SLP_TYP + SLP_EN */
+
+ ACPI_FLUSH_CPU_CACHE ();
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (sleep_state > ACPI_STATE_S3) {
+ /*
+ * We wanted to sleep > S3, but it didn't happen (by virtue of the fact that
+ * we are still executing!)
+ *
+ * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines.
+ *
+ * We wait so long to allow chipsets that poll this reg very slowly to
+ * still read the right value. Ideally, this block would go
+ * away entirely.
+ */
+ acpi_os_stall (10000000);
+
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL,
+ sleep_enable_reg_info->access_bit_mask);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Wait until we enter sleep state */
+
+ do {
+ status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Spin until we wake */
+
+ } while (!in_value);
+
+ return_ACPI_STATUS (AE_OK);
+}
+EXPORT_SYMBOL(acpi_enter_sleep_state);
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_enter_sleep_state_s4bios
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform a S4 bios request.
+ * THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
+ *
+ ******************************************************************************/
+
+acpi_status asmlinkage
+acpi_enter_sleep_state_s4bios (
+ void)
+{
+ u32 in_value;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_enter_sleep_state_s4bios");
+
+
+ status = acpi_set_register (ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_hw_clear_acpi_status (ACPI_MTX_DO_NOT_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * 1) Disable/Clear all GPEs
+ * 2) Enable all wakeup GPEs
+ */
+ status = acpi_hw_disable_all_gpes (ACPI_ISR);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ acpi_gbl_system_awake_and_running = FALSE;
+
+ status = acpi_hw_enable_all_wakeup_gpes (ACPI_ISR);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_FLUSH_CPU_CACHE ();
+
+ status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8);
+
+ do {
+ acpi_os_stall(1000);
+ status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ } while (!in_value);
+
+ return_ACPI_STATUS (AE_OK);
+}
+EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios);
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_leave_sleep_state
+ *
+ * PARAMETERS: sleep_state - Which sleep state we just exited
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform OS-independent ACPI cleanup after a sleep
+ * Called with interrupts ENABLED.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_leave_sleep_state (
+ u8 sleep_state)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status;
+ struct acpi_bit_register_info *sleep_type_reg_info;
+ struct acpi_bit_register_info *sleep_enable_reg_info;
+ u32 PM1Acontrol;
+ u32 PM1Bcontrol;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_leave_sleep_state");
+
+
+ /*
+ * Set SLP_TYPE and SLP_EN to state S0.
+ * This is unclear from the ACPI Spec, but it is required
+ * by some machines.
+ */
+ status = acpi_get_sleep_type_data (ACPI_STATE_S0,
+ &acpi_gbl_sleep_type_a, &acpi_gbl_sleep_type_b);
+ if (ACPI_SUCCESS (status)) {
+ sleep_type_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_TYPE_A);
+ sleep_enable_reg_info = acpi_hw_get_bit_register_info (ACPI_BITREG_SLEEP_ENABLE);
+
+ /* Get current value of PM1A control */
+
+ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
+ if (ACPI_SUCCESS (status)) {
+ /* Clear SLP_EN and SLP_TYP fields */
+
+ PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
+ sleep_enable_reg_info->access_bit_mask);
+ PM1Bcontrol = PM1Acontrol;
+
+ /* Insert SLP_TYP bits */
+
+ PM1Acontrol |= (acpi_gbl_sleep_type_a << sleep_type_reg_info->bit_position);
+ PM1Bcontrol |= (acpi_gbl_sleep_type_b << sleep_type_reg_info->bit_position);
+
+ /* Just ignore any errors */
+
+ (void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
+ (void) acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
+ }
+ }
+
+ /* Ensure enter_sleep_state_prep -> enter_sleep_state ordering */
+
+ acpi_gbl_sleep_type_a = ACPI_SLEEP_TYPE_INVALID;
+
+ /* Setup parameter object */
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+
+ /* Ignore any errors from these methods */
+
+ arg.integer.value = ACPI_SST_WAKING;
+ status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
+ if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+ ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+ }
+
+ arg.integer.value = sleep_state;
+ status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL);
+ if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+ ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status)));
+ }
+
+ status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL);
+ if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+ ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status)));
+ }
+ /* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
+
+ /*
+ * Restore the GPEs:
+ * 1) Disable/Clear all GPEs
+ * 2) Enable all runtime GPEs
+ */
+ status = acpi_hw_disable_all_gpes (ACPI_NOT_ISR);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ acpi_gbl_system_awake_and_running = TRUE;
+
+ status = acpi_hw_enable_all_runtime_gpes (ACPI_NOT_ISR);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Enable power button */
+
+ (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].enable_register_id,
+ 1, ACPI_MTX_DO_NOT_LOCK);
+ (void) acpi_set_register(acpi_gbl_fixed_event_info[ACPI_EVENT_POWER_BUTTON].status_register_id,
+ 1, ACPI_MTX_DO_NOT_LOCK);
+
+ arg.integer.value = ACPI_SST_WORKING;
+ status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
+ if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
+ ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+ }
+
+ return_ACPI_STATUS (status);
+}
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
new file mode 100644
index 000000000000..1906167d7294
--- /dev/null
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -0,0 +1,203 @@
+
+/******************************************************************************
+ *
+ * Name: hwtimer.c - ACPI Power Management Timer Interface
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+
+#define _COMPONENT ACPI_HARDWARE
+ ACPI_MODULE_NAME ("hwtimer")
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_timer_resolution
+ *
+ * PARAMETERS: Resolution - Where the resolution is returned
+ *
+ * RETURN: Status and timer resolution
+ *
+ * DESCRIPTION: Obtains resolution of the ACPI PM Timer (24 or 32 bits).
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_timer_resolution (
+ u32 *resolution)
+{
+ ACPI_FUNCTION_TRACE ("acpi_get_timer_resolution");
+
+
+ if (!resolution) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (0 == acpi_gbl_FADT->tmr_val_ext) {
+ *resolution = 24;
+ }
+ else {
+ *resolution = 32;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_timer
+ *
+ * PARAMETERS: Ticks - Where the timer value is returned
+ *
+ * RETURN: Status and current ticks
+ *
+ * DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks).
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_timer (
+ u32 *ticks)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_timer");
+
+
+ if (!ticks) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_hw_low_level_read (32, ticks, &acpi_gbl_FADT->xpm_tmr_blk);
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_timer);
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_timer_duration
+ *
+ * PARAMETERS: start_ticks - Starting timestamp
+ * end_ticks - End timestamp
+ * time_elapsed - Where the elapsed time is returned
+ *
+ * RETURN: Status and time_elapsed
+ *
+ * DESCRIPTION: Computes the time elapsed (in microseconds) between two
+ * PM Timer time stamps, taking into account the possibility of
+ * rollovers, the timer resolution, and timer frequency.
+ *
+ * The PM Timer's clock ticks at roughly 3.6 times per
+ * _microsecond_, and its clock continues through Cx state
+ * transitions (unlike many CPU timestamp counters) -- making it
+ * a versatile and accurate timer.
+ *
+ * Note that this function accommodates only a single timer
+ * rollover. Thus for 24-bit timers, this function should only
+ * be used for calculating durations less than ~4.6 seconds
+ * (~20 minutes for 32-bit timers) -- calculations below:
+ *
+ * 2**24 Ticks / 3,600,000 Ticks/Sec = 4.66 sec
+ * 2**32 Ticks / 3,600,000 Ticks/Sec = 1193 sec or 19.88 minutes
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_timer_duration (
+ u32 start_ticks,
+ u32 end_ticks,
+ u32 *time_elapsed)
+{
+ acpi_status status;
+ u32 delta_ticks;
+ acpi_integer quotient;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_timer_duration");
+
+
+ if (!time_elapsed) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Compute Tick Delta:
+ * Handle (max one) timer rollovers on 24-bit versus 32-bit timers.
+ */
+ if (start_ticks < end_ticks) {
+ delta_ticks = end_ticks - start_ticks;
+ }
+ else if (start_ticks > end_ticks) {
+ if (0 == acpi_gbl_FADT->tmr_val_ext) {
+ /* 24-bit Timer */
+
+ delta_ticks = (((0x00FFFFFF - start_ticks) + end_ticks) & 0x00FFFFFF);
+ }
+ else {
+ /* 32-bit Timer */
+
+ delta_ticks = (0xFFFFFFFF - start_ticks) + end_ticks;
+ }
+ }
+ else /* start_ticks == end_ticks */ {
+ *time_elapsed = 0;
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Compute Duration (Requires a 64-bit multiply and divide):
+ *
+ * time_elapsed = (delta_ticks * 1000000) / PM_TIMER_FREQUENCY;
+ */
+ status = acpi_ut_short_divide (((u64) delta_ticks) * 1000000,
+ PM_TIMER_FREQUENCY, &quotient, NULL);
+
+ *time_elapsed = (u32) quotient;
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_timer_duration);
+
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
new file mode 100644
index 000000000000..0fb731a470dc
--- /dev/null
+++ b/drivers/acpi/ibm_acpi.c
@@ -0,0 +1,1242 @@
+/*
+ * ibm_acpi.c - IBM ThinkPad ACPI Extras
+ *
+ *
+ * Copyright (C) 2004 Borislav Deianov
+ *
+ * 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
+ *
+ * Changelog:
+ *
+ * 2004-08-09 0.1 initial release, support for X series
+ * 2004-08-14 0.2 support for T series, X20
+ * bluetooth enable/disable
+ * hotkey events disabled by default
+ * removed fan control, currently useless
+ * 2004-08-17 0.3 support for R40
+ * lcd off, brightness control
+ * thinklight on/off
+ * 2004-09-16 0.4 support for module parameters
+ * hotkey mask can be prefixed by 0x
+ * video output switching
+ * video expansion control
+ * ultrabay eject support
+ * removed lcd brightness/on/off control, didn't work
+ * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20
+ * proc file format changed
+ * video_switch command
+ * experimental cmos control
+ * experimental led control
+ * experimental acpi sounds
+ * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device
+ * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20
+ * fix LED control on A21e
+ * 2004-11-08 0.8 fix init error case, don't return from a macro
+ * thanks to Chris Wright <chrisw@osdl.org>
+ */
+
+#define IBM_VERSION "0.8"
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acnamesp.h>
+
+#define IBM_NAME "ibm"
+#define IBM_DESC "IBM ThinkPad ACPI Extras"
+#define IBM_FILE "ibm_acpi"
+#define IBM_URL "http://ibm-acpi.sf.net/"
+
+#define IBM_DIR IBM_NAME
+
+#define IBM_LOG IBM_FILE ": "
+#define IBM_ERR KERN_ERR IBM_LOG
+#define IBM_NOTICE KERN_NOTICE IBM_LOG
+#define IBM_INFO KERN_INFO IBM_LOG
+#define IBM_DEBUG KERN_DEBUG IBM_LOG
+
+#define IBM_MAX_ACPI_ARGS 3
+
+#define __unused __attribute__ ((unused))
+
+static int experimental;
+module_param(experimental, int, 0);
+
+static acpi_handle root_handle = NULL;
+
+#define IBM_HANDLE(object, parent, paths...) \
+ static acpi_handle object##_handle; \
+ static acpi_handle *object##_parent = &parent##_handle; \
+ static char *object##_paths[] = { paths }
+
+IBM_HANDLE(ec, root,
+ "\\_SB.PCI0.ISA.EC", /* A21e, A22p, T20, T21, X20 */
+ "\\_SB.PCI0.LPC.EC", /* all others */
+);
+
+IBM_HANDLE(vid, root,
+ "\\_SB.PCI0.VID", /* A21e, G40, X30, X40 */
+ "\\_SB.PCI0.AGP.VID", /* all others */
+);
+
+IBM_HANDLE(cmos, root,
+ "\\UCMS", /* R50, R50p, R51, T4x, X31, X40 */
+ "\\CMOS", /* A3x, G40, R32, T23, T30, X22, X24, X30 */
+ "\\CMS", /* R40, R40e */
+); /* A21e, A22p, T20, T21, X20 */
+
+IBM_HANDLE(dock, root,
+ "\\_SB.GDCK", /* X30, X31, X40 */
+ "\\_SB.PCI0.DOCK", /* A22p, T20, T21, X20 */
+ "\\_SB.PCI0.PCI1.DOCK", /* all others */
+); /* A21e, G40, R32, R40, R40e */
+
+IBM_HANDLE(bay, root,
+ "\\_SB.PCI0.IDE0.SCND.MSTR"); /* all except A21e */
+IBM_HANDLE(bayej, root,
+ "\\_SB.PCI0.IDE0.SCND.MSTR._EJ0"); /* all except A2x, A3x */
+
+IBM_HANDLE(lght, root, "\\LGHT"); /* A21e, A22p, T20, T21, X20 */
+IBM_HANDLE(hkey, ec, "HKEY"); /* all */
+IBM_HANDLE(led, ec, "LED"); /* all except A21e, A22p, T20, T21, X20 */
+IBM_HANDLE(sysl, ec, "SYSL"); /* A21e, A22p, T20, T21, X20 */
+IBM_HANDLE(bled, ec, "BLED"); /* A22p, T20, T21, X20 */
+IBM_HANDLE(beep, ec, "BEEP"); /* all models */
+
+struct ibm_struct {
+ char *name;
+
+ char *hid;
+ struct acpi_driver *driver;
+
+ int (*init) (struct ibm_struct *);
+ int (*read) (struct ibm_struct *, char *);
+ int (*write) (struct ibm_struct *, char *);
+ void (*exit) (struct ibm_struct *);
+
+ void (*notify) (struct ibm_struct *, u32);
+ acpi_handle *handle;
+ int type;
+ struct acpi_device *device;
+
+ int driver_registered;
+ int proc_created;
+ int init_called;
+ int notify_installed;
+
+ int supported;
+ union {
+ struct {
+ int status;
+ int mask;
+ } hotkey;
+ struct {
+ int autoswitch;
+ } video;
+ } state;
+
+ int experimental;
+};
+
+static struct proc_dir_entry *proc_dir = NULL;
+
+#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
+#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
+#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
+
+static int acpi_evalf(acpi_handle handle,
+ void *res, char *method, char *fmt, ...)
+{
+ char *fmt0 = fmt;
+ struct acpi_object_list params;
+ union acpi_object in_objs[IBM_MAX_ACPI_ARGS];
+ struct acpi_buffer result;
+ union acpi_object out_obj;
+ acpi_status status;
+ va_list ap;
+ char res_type;
+ int success;
+ int quiet;
+
+ if (!*fmt) {
+ printk(IBM_ERR "acpi_evalf() called with empty format\n");
+ return 0;
+ }
+
+ if (*fmt == 'q') {
+ quiet = 1;
+ fmt++;
+ } else
+ quiet = 0;
+
+ res_type = *(fmt++);
+
+ params.count = 0;
+ params.pointer = &in_objs[0];
+
+ va_start(ap, fmt);
+ while (*fmt) {
+ char c = *(fmt++);
+ switch (c) {
+ case 'd': /* int */
+ in_objs[params.count].integer.value = va_arg(ap, int);
+ in_objs[params.count++].type = ACPI_TYPE_INTEGER;
+ break;
+ /* add more types as needed */
+ default:
+ printk(IBM_ERR "acpi_evalf() called "
+ "with invalid format character '%c'\n", c);
+ return 0;
+ }
+ }
+ va_end(ap);
+
+ result.length = sizeof(out_obj);
+ result.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, method, &params, &result);
+
+ switch (res_type) {
+ case 'd': /* int */
+ if (res)
+ *(int *)res = out_obj.integer.value;
+ success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER;
+ break;
+ case 'v': /* void */
+ success = status == AE_OK;
+ break;
+ /* add more types as needed */
+ default:
+ printk(IBM_ERR "acpi_evalf() called "
+ "with invalid format character '%c'\n", res_type);
+ return 0;
+ }
+
+ if (!success && !quiet)
+ printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n",
+ method, fmt0, status);
+
+ return success;
+}
+
+static void __unused acpi_print_int(acpi_handle handle, char *method)
+{
+ int i;
+
+ if (acpi_evalf(handle, &i, method, "d"))
+ printk(IBM_INFO "%s = 0x%x\n", method, i);
+ else
+ printk(IBM_ERR "error calling %s\n", method);
+}
+
+static char *next_cmd(char **cmds)
+{
+ char *start = *cmds;
+ char *end;
+
+ while ((end = strchr(start, ',')) && end == start)
+ start = end + 1;
+
+ if (!end)
+ return NULL;
+
+ *end = 0;
+ *cmds = end + 1;
+ return start;
+}
+
+static int driver_init(struct ibm_struct *ibm)
+{
+ printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
+ printk(IBM_INFO "%s\n", IBM_URL);
+
+ return 0;
+}
+
+static int driver_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+
+ len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);
+ len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);
+
+ return len;
+}
+
+static int hotkey_get(struct ibm_struct *ibm, int *status, int *mask)
+{
+ if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
+ return -EIO;
+ if (ibm->supported) {
+ if (!acpi_evalf(hkey_handle, mask, "DHKN", "qd"))
+ return -EIO;
+ } else {
+ *mask = ibm->state.hotkey.mask;
+ }
+ return 0;
+}
+
+static int hotkey_set(struct ibm_struct *ibm, int status, int mask)
+{
+ int i;
+
+ if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status))
+ return -EIO;
+
+ if (!ibm->supported)
+ return 0;
+
+ for (i=0; i<32; i++) {
+ int bit = ((1 << i) & mask) != 0;
+ if (!acpi_evalf(hkey_handle, NULL, "MHKM", "vdd", i+1, bit))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int hotkey_init(struct ibm_struct *ibm)
+{
+ int ret;
+
+ ibm->supported = 1;
+ ret = hotkey_get(ibm,
+ &ibm->state.hotkey.status,
+ &ibm->state.hotkey.mask);
+ if (ret < 0) {
+ /* mask not supported on A21e, A22p, T20, T21, X20, X22, X24 */
+ ibm->supported = 0;
+ ret = hotkey_get(ibm,
+ &ibm->state.hotkey.status,
+ &ibm->state.hotkey.mask);
+ }
+
+ return ret;
+}
+
+static int hotkey_read(struct ibm_struct *ibm, char *p)
+{
+ int status, mask;
+ int len = 0;
+
+ if (hotkey_get(ibm, &status, &mask) < 0)
+ return -EIO;
+
+ len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
+ if (ibm->supported) {
+ len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
+ len += sprintf(p + len,
+ "commands:\tenable, disable, reset, <mask>\n");
+ } else {
+ len += sprintf(p + len, "mask:\t\tnot supported\n");
+ len += sprintf(p + len, "commands:\tenable, disable, reset\n");
+ }
+
+ return len;
+}
+
+static int hotkey_write(struct ibm_struct *ibm, char *buf)
+{
+ int status, mask;
+ char *cmd;
+ int do_cmd = 0;
+
+ if (hotkey_get(ibm, &status, &mask) < 0)
+ return -ENODEV;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ status = 1;
+ } else if (strlencmp(cmd, "disable") == 0) {
+ status = 0;
+ } else if (strlencmp(cmd, "reset") == 0) {
+ status = ibm->state.hotkey.status;
+ mask = ibm->state.hotkey.mask;
+ } else if (sscanf(cmd, "0x%x", &mask) == 1) {
+ /* mask set */
+ } else if (sscanf(cmd, "%x", &mask) == 1) {
+ /* mask set */
+ } else
+ return -EINVAL;
+ do_cmd = 1;
+ }
+
+ if (do_cmd && hotkey_set(ibm, status, mask) < 0)
+ return -EIO;
+
+ return 0;
+}
+
+static void hotkey_exit(struct ibm_struct *ibm)
+{
+ hotkey_set(ibm, ibm->state.hotkey.status, ibm->state.hotkey.mask);
+}
+
+static void hotkey_notify(struct ibm_struct *ibm, u32 event)
+{
+ int hkey;
+
+ if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
+ acpi_bus_generate_event(ibm->device, event, hkey);
+ else {
+ printk(IBM_ERR "unknown hotkey event %d\n", event);
+ acpi_bus_generate_event(ibm->device, event, 0);
+ }
+}
+
+static int bluetooth_init(struct ibm_struct *ibm)
+{
+ /* bluetooth not supported on A21e, G40, T20, T21, X20 */
+ ibm->supported = acpi_evalf(hkey_handle, NULL, "GBDC", "qv");
+
+ return 0;
+}
+
+static int bluetooth_status(struct ibm_struct *ibm)
+{
+ int status;
+
+ if (!ibm->supported || !acpi_evalf(hkey_handle, &status, "GBDC", "d"))
+ status = 0;
+
+ return status;
+}
+
+static int bluetooth_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+ int status = bluetooth_status(ibm);
+
+ if (!ibm->supported)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else if (!(status & 1))
+ len += sprintf(p + len, "status:\t\tnot installed\n");
+ else {
+ len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 1));
+ len += sprintf(p + len, "commands:\tenable, disable\n");
+ }
+
+ return len;
+}
+
+static int bluetooth_write(struct ibm_struct *ibm, char *buf)
+{
+ int status = bluetooth_status(ibm);
+ char *cmd;
+ int do_cmd = 0;
+
+ if (!ibm->supported)
+ return -EINVAL;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "enable") == 0) {
+ status |= 2;
+ } else if (strlencmp(cmd, "disable") == 0) {
+ status &= ~2;
+ } else
+ return -EINVAL;
+ do_cmd = 1;
+ }
+
+ if (do_cmd && !acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status))
+ return -EIO;
+
+ return 0;
+}
+
+static int video_init(struct ibm_struct *ibm)
+{
+ if (!acpi_evalf(vid_handle,
+ &ibm->state.video.autoswitch, "^VDEE", "d"))
+ return -ENODEV;
+
+ return 0;
+}
+
+static int video_status(struct ibm_struct *ibm)
+{
+ int status = 0;
+ int i;
+
+ acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1);
+ if (acpi_evalf(NULL, &i, "\\VCDC", "d"))
+ status |= 0x02 * i;
+
+ acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0);
+ if (acpi_evalf(NULL, &i, "\\VCDL", "d"))
+ status |= 0x01 * i;
+ if (acpi_evalf(NULL, &i, "\\VCDD", "d"))
+ status |= 0x08 * i;
+
+ if (acpi_evalf(vid_handle, &i, "^VDEE", "d"))
+ status |= 0x10 * (i & 1);
+
+ return status;
+}
+
+static int video_read(struct ibm_struct *ibm, char *p)
+{
+ int status = video_status(ibm);
+ int len = 0;
+
+ len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));
+ len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));
+ len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));
+ len += sprintf(p + len, "auto:\t\t%s\n", enabled(status, 4));
+ len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable, "
+ "crt_enable, crt_disable\n");
+ len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable, "
+ "auto_enable, auto_disable\n");
+ len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");
+
+ return len;
+}
+
+static int video_write(struct ibm_struct *ibm, char *buf)
+{
+ char *cmd;
+ int enable, disable, status;
+
+ enable = disable = 0;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "lcd_enable") == 0) {
+ enable |= 0x01;
+ } else if (strlencmp(cmd, "lcd_disable") == 0) {
+ disable |= 0x01;
+ } else if (strlencmp(cmd, "crt_enable") == 0) {
+ enable |= 0x02;
+ } else if (strlencmp(cmd, "crt_disable") == 0) {
+ disable |= 0x02;
+ } else if (strlencmp(cmd, "dvi_enable") == 0) {
+ enable |= 0x08;
+ } else if (strlencmp(cmd, "dvi_disable") == 0) {
+ disable |= 0x08;
+ } else if (strlencmp(cmd, "auto_enable") == 0) {
+ if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
+ return -EIO;
+ } else if (strlencmp(cmd, "auto_disable") == 0) {
+ if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 0))
+ return -EIO;
+ } else if (strlencmp(cmd, "video_switch") == 0) {
+ int autoswitch;
+ if (!acpi_evalf(vid_handle, &autoswitch, "^VDEE", "d"))
+ return -EIO;
+ if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", 1))
+ return -EIO;
+ if (!acpi_evalf(vid_handle, NULL, "VSWT", "v"))
+ return -EIO;
+ if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd",
+ autoswitch))
+ return -EIO;
+ } else if (strlencmp(cmd, "expand_toggle") == 0) {
+ if (!acpi_evalf(NULL, NULL, "\\VEXP", "v"))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ if (enable || disable) {
+ status = (video_status(ibm) & 0x0f & ~disable) | enable;
+ if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80))
+ return -EIO;
+ if (!acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void video_exit(struct ibm_struct *ibm)
+{
+ acpi_evalf(vid_handle, NULL, "_DOS", "vd",
+ ibm->state.video.autoswitch);
+}
+
+static int light_init(struct ibm_struct *ibm)
+{
+ /* kblt not supported on G40, R32, X20 */
+ ibm->supported = acpi_evalf(ec_handle, NULL, "KBLT", "qv");
+
+ return 0;
+}
+
+static int light_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+ int status = 0;
+
+ if (ibm->supported) {
+ if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
+ return -EIO;
+ len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
+ } else
+ len += sprintf(p + len, "status:\t\tunknown\n");
+
+ len += sprintf(p + len, "commands:\ton, off\n");
+
+ return len;
+}
+
+static int light_write(struct ibm_struct *ibm, char *buf)
+{
+ int cmos_cmd, lght_cmd;
+ char *cmd;
+ int success;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "on") == 0) {
+ cmos_cmd = 0x0c;
+ lght_cmd = 1;
+ } else if (strlencmp(cmd, "off") == 0) {
+ cmos_cmd = 0x0d;
+ lght_cmd = 0;
+ } else
+ return -EINVAL;
+
+ success = cmos_handle ?
+ acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
+ acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
+ if (!success)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int _sta(acpi_handle handle)
+{
+ int status;
+
+ if (!handle || !acpi_evalf(handle, &status, "_STA", "d"))
+ status = 0;
+
+ return status;
+}
+
+#define dock_docked() (_sta(dock_handle) & 1)
+
+static int dock_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+ int docked = dock_docked();
+
+ if (!dock_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else if (!docked)
+ len += sprintf(p + len, "status:\t\tundocked\n");
+ else {
+ len += sprintf(p + len, "status:\t\tdocked\n");
+ len += sprintf(p + len, "commands:\tdock, undock\n");
+ }
+
+ return len;
+}
+
+static int dock_write(struct ibm_struct *ibm, char *buf)
+{
+ char *cmd;
+
+ if (!dock_docked())
+ return -EINVAL;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "undock") == 0) {
+ if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 0))
+ return -EIO;
+ if (!acpi_evalf(dock_handle, NULL, "_EJ0", "vd", 1))
+ return -EIO;
+ } else if (strlencmp(cmd, "dock") == 0) {
+ if (!acpi_evalf(dock_handle, NULL, "_DCK", "vd", 1))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void dock_notify(struct ibm_struct *ibm, u32 event)
+{
+ int docked = dock_docked();
+
+ if (event == 3 && docked)
+ acpi_bus_generate_event(ibm->device, event, 1); /* button */
+ else if (event == 3 && !docked)
+ acpi_bus_generate_event(ibm->device, event, 2); /* undock */
+ else if (event == 0 && docked)
+ acpi_bus_generate_event(ibm->device, event, 3); /* dock */
+ else {
+ printk(IBM_ERR "unknown dock event %d, status %d\n",
+ event, _sta(dock_handle));
+ acpi_bus_generate_event(ibm->device, event, 0); /* unknown */
+ }
+}
+
+#define bay_occupied() (_sta(bay_handle) & 1)
+
+static int bay_init(struct ibm_struct *ibm)
+{
+ /* bay not supported on A21e, A22p, A31, A31p, G40, R32, R40e */
+ ibm->supported = bay_handle && bayej_handle &&
+ acpi_evalf(bay_handle, NULL, "_STA", "qv");
+
+ return 0;
+}
+
+static int bay_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+ int occupied = bay_occupied();
+
+ if (!ibm->supported)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else if (!occupied)
+ len += sprintf(p + len, "status:\t\tunoccupied\n");
+ else {
+ len += sprintf(p + len, "status:\t\toccupied\n");
+ len += sprintf(p + len, "commands:\teject\n");
+ }
+
+ return len;
+}
+
+static int bay_write(struct ibm_struct *ibm, char *buf)
+{
+ char *cmd;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (strlencmp(cmd, "eject") == 0) {
+ if (!ibm->supported ||
+ !acpi_evalf(bay_handle, NULL, "_EJ0", "vd", 1))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void bay_notify(struct ibm_struct *ibm, u32 event)
+{
+ acpi_bus_generate_event(ibm->device, event, 0);
+}
+
+static int cmos_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+
+ /* cmos not supported on A21e, A22p, T20, T21, X20 */
+ if (!cmos_handle)
+ len += sprintf(p + len, "status:\t\tnot supported\n");
+ else {
+ len += sprintf(p + len, "status:\t\tsupported\n");
+ len += sprintf(p + len, "commands:\t<int>\n");
+ }
+
+ return len;
+}
+
+static int cmos_write(struct ibm_struct *ibm, char *buf)
+{
+ char *cmd;
+ int cmos_cmd;
+
+ if (!cmos_handle)
+ return -EINVAL;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%u", &cmos_cmd) == 1) {
+ /* cmos_cmd set */
+ } else
+ return -EINVAL;
+
+ if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int led_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+
+ len += sprintf(p + len, "commands:\t"
+ "<int> on, <int> off, <int> blink\n");
+
+ return len;
+}
+
+static int led_write(struct ibm_struct *ibm, char *buf)
+{
+ char *cmd;
+ unsigned int led;
+ int led_cmd, sysl_cmd, bled_a, bled_b;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%u", &led) != 1)
+ return -EINVAL;
+
+ if (strstr(cmd, "blink")) {
+ led_cmd = 0xc0;
+ sysl_cmd = 2;
+ bled_a = 2;
+ bled_b = 1;
+ } else if (strstr(cmd, "on")) {
+ led_cmd = 0x80;
+ sysl_cmd = 1;
+ bled_a = 2;
+ bled_b = 0;
+ } else if (strstr(cmd, "off")) {
+ led_cmd = sysl_cmd = bled_a = bled_b = 0;
+ } else
+ return -EINVAL;
+
+ if (led_handle) {
+ if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
+ led, led_cmd))
+ return -EIO;
+ } else if (led < 2) {
+ if (acpi_evalf(sysl_handle, NULL, NULL, "vdd",
+ led, sysl_cmd))
+ return -EIO;
+ } else if (led == 2 && bled_handle) {
+ if (acpi_evalf(bled_handle, NULL, NULL, "vdd",
+ bled_a, bled_b))
+ return -EIO;
+ } else
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int beep_read(struct ibm_struct *ibm, char *p)
+{
+ int len = 0;
+
+ len += sprintf(p + len, "commands:\t<int>\n");
+
+ return len;
+}
+
+static int beep_write(struct ibm_struct *ibm, char *buf)
+{
+ char *cmd;
+ int beep_cmd;
+
+ while ((cmd = next_cmd(&buf))) {
+ if (sscanf(cmd, "%u", &beep_cmd) == 1) {
+ /* beep_cmd set */
+ } else
+ return -EINVAL;
+
+ if (!acpi_evalf(beep_handle, NULL, NULL, "vd", beep_cmd))
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static struct ibm_struct ibms[] = {
+ {
+ .name = "driver",
+ .init = driver_init,
+ .read = driver_read,
+ },
+ {
+ .name = "hotkey",
+ .hid = "IBM0068",
+ .init = hotkey_init,
+ .read = hotkey_read,
+ .write = hotkey_write,
+ .exit = hotkey_exit,
+ .notify = hotkey_notify,
+ .handle = &hkey_handle,
+ .type = ACPI_DEVICE_NOTIFY,
+ },
+ {
+ .name = "bluetooth",
+ .init = bluetooth_init,
+ .read = bluetooth_read,
+ .write = bluetooth_write,
+ },
+ {
+ .name = "video",
+ .init = video_init,
+ .read = video_read,
+ .write = video_write,
+ .exit = video_exit,
+ },
+ {
+ .name = "light",
+ .init = light_init,
+ .read = light_read,
+ .write = light_write,
+ },
+ {
+ .name = "dock",
+ .read = dock_read,
+ .write = dock_write,
+ .notify = dock_notify,
+ .handle = &dock_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+ },
+ {
+ .name = "bay",
+ .init = bay_init,
+ .read = bay_read,
+ .write = bay_write,
+ .notify = bay_notify,
+ .handle = &bay_handle,
+ .type = ACPI_SYSTEM_NOTIFY,
+ },
+ {
+ .name = "cmos",
+ .read = cmos_read,
+ .write = cmos_write,
+ .experimental = 1,
+ },
+ {
+ .name = "led",
+ .read = led_read,
+ .write = led_write,
+ .experimental = 1,
+ },
+ {
+ .name = "beep",
+ .read = beep_read,
+ .write = beep_write,
+ .experimental = 1,
+ },
+};
+#define NUM_IBMS (sizeof(ibms)/sizeof(ibms[0]))
+
+static int dispatch_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct ibm_struct *ibm = (struct ibm_struct *)data;
+ int len;
+
+ if (!ibm || !ibm->read)
+ return -EINVAL;
+
+ len = ibm->read(ibm, page);
+ if (len < 0)
+ return len;
+
+ if (len <= off + count)
+ *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len > count)
+ len = count;
+ if (len < 0)
+ len = 0;
+
+ return len;
+}
+
+static int dispatch_write(struct file *file, const char __user *userbuf,
+ unsigned long count, void *data)
+{
+ struct ibm_struct *ibm = (struct ibm_struct *)data;
+ char *kernbuf;
+ int ret;
+
+ if (!ibm || !ibm->write)
+ return -EINVAL;
+
+ kernbuf = kmalloc(count + 2, GFP_KERNEL);
+ if (!kernbuf)
+ return -ENOMEM;
+
+ if (copy_from_user(kernbuf, userbuf, count)) {
+ kfree(kernbuf);
+ return -EFAULT;
+ }
+
+ kernbuf[count] = 0;
+ strcat(kernbuf, ",");
+ ret = ibm->write(ibm, kernbuf);
+ if (ret == 0)
+ ret = count;
+
+ kfree(kernbuf);
+
+ return ret;
+}
+
+static void dispatch_notify(acpi_handle handle, u32 event, void *data)
+{
+ struct ibm_struct *ibm = (struct ibm_struct *)data;
+
+ if (!ibm || !ibm->notify)
+ return;
+
+ ibm->notify(ibm, event);
+}
+
+static int setup_notify(struct ibm_struct *ibm)
+{
+ acpi_status status;
+ int ret;
+
+ if (!*ibm->handle)
+ return 0;
+
+ ret = acpi_bus_get_device(*ibm->handle, &ibm->device);
+ if (ret < 0) {
+ printk(IBM_ERR "%s device not present\n", ibm->name);
+ return 0;
+ }
+
+ acpi_driver_data(ibm->device) = ibm;
+ sprintf(acpi_device_class(ibm->device), "%s/%s", IBM_NAME, ibm->name);
+
+ status = acpi_install_notify_handler(*ibm->handle, ibm->type,
+ dispatch_notify, ibm);
+ if (ACPI_FAILURE(status)) {
+ printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n",
+ ibm->name, status);
+ return -ENODEV;
+ }
+
+ ibm->notify_installed = 1;
+
+ return 0;
+}
+
+static int device_add(struct acpi_device *device)
+{
+ return 0;
+}
+
+static int register_driver(struct ibm_struct *ibm)
+{
+ int ret;
+
+ ibm->driver = kmalloc(sizeof(struct acpi_driver), GFP_KERNEL);
+ if (!ibm->driver) {
+ printk(IBM_ERR "kmalloc(ibm->driver) failed\n");
+ return -1;
+ }
+
+ memset(ibm->driver, 0, sizeof(struct acpi_driver));
+ sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
+ ibm->driver->ids = ibm->hid;
+ ibm->driver->ops.add = &device_add;
+
+ ret = acpi_bus_register_driver(ibm->driver);
+ if (ret < 0) {
+ printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n",
+ ibm->hid, ret);
+ kfree(ibm->driver);
+ }
+
+ return ret;
+}
+
+static int ibm_init(struct ibm_struct *ibm)
+{
+ int ret;
+ struct proc_dir_entry *entry;
+
+ if (ibm->experimental && !experimental)
+ return 0;
+
+ if (ibm->hid) {
+ ret = register_driver(ibm);
+ if (ret < 0)
+ return ret;
+ ibm->driver_registered = 1;
+ }
+
+ if (ibm->init) {
+ ret = ibm->init(ibm);
+ if (ret != 0)
+ return ret;
+ ibm->init_called = 1;
+ }
+
+ entry = create_proc_entry(ibm->name, S_IFREG | S_IRUGO | S_IWUSR,
+ proc_dir);
+ if (!entry) {
+ printk(IBM_ERR "unable to create proc entry %s\n", ibm->name);
+ return -ENODEV;
+ }
+ entry->owner = THIS_MODULE;
+ ibm->proc_created = 1;
+
+ entry->data = ibm;
+ if (ibm->read)
+ entry->read_proc = &dispatch_read;
+ if (ibm->write)
+ entry->write_proc = &dispatch_write;
+
+ if (ibm->notify) {
+ ret = setup_notify(ibm);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ibm_exit(struct ibm_struct *ibm)
+{
+ if (ibm->notify_installed)
+ acpi_remove_notify_handler(*ibm->handle, ibm->type,
+ dispatch_notify);
+
+ if (ibm->proc_created)
+ remove_proc_entry(ibm->name, proc_dir);
+
+ if (ibm->init_called && ibm->exit)
+ ibm->exit(ibm);
+
+ if (ibm->driver_registered) {
+ acpi_bus_unregister_driver(ibm->driver);
+ kfree(ibm->driver);
+ }
+}
+
+static int ibm_handle_init(char *name,
+ acpi_handle *handle, acpi_handle parent,
+ char **paths, int num_paths, int required)
+{
+ int i;
+ acpi_status status;
+
+ for (i=0; i<num_paths; i++) {
+ status = acpi_get_handle(parent, paths[i], handle);
+ if (ACPI_SUCCESS(status))
+ return 0;
+ }
+
+ *handle = NULL;
+
+ if (required) {
+ printk(IBM_ERR "%s object not found\n", name);
+ return -1;
+ }
+
+ return 0;
+}
+
+#define IBM_HANDLE_INIT(object, required) \
+ ibm_handle_init(#object, &object##_handle, *object##_parent, \
+ object##_paths, sizeof(object##_paths)/sizeof(char*), required)
+
+
+static int set_ibm_param(const char *val, struct kernel_param *kp)
+{
+ unsigned int i;
+ char arg_with_comma[32];
+
+ if (strlen(val) > 30)
+ return -ENOSPC;
+
+ strcpy(arg_with_comma, val);
+ strcat(arg_with_comma, ",");
+
+ for (i=0; i<NUM_IBMS; i++)
+ if (strcmp(ibms[i].name, kp->name) == 0)
+ return ibms[i].write(&ibms[i], arg_with_comma);
+ BUG();
+ return -EINVAL;
+}
+
+#define IBM_PARAM(feature) \
+ module_param_call(feature, set_ibm_param, NULL, NULL, 0)
+
+static void acpi_ibm_exit(void)
+{
+ int i;
+
+ for (i=NUM_IBMS-1; i>=0; i--)
+ ibm_exit(&ibms[i]);
+
+ remove_proc_entry(IBM_DIR, acpi_root_dir);
+}
+
+static int __init acpi_ibm_init(void)
+{
+ int ret, i;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ /* these handles are required */
+ if (IBM_HANDLE_INIT(ec, 1) < 0 ||
+ IBM_HANDLE_INIT(hkey, 1) < 0 ||
+ IBM_HANDLE_INIT(vid, 1) < 0 ||
+ IBM_HANDLE_INIT(beep, 1) < 0)
+ return -ENODEV;
+
+ /* these handles have alternatives */
+ IBM_HANDLE_INIT(lght, 0);
+ if (IBM_HANDLE_INIT(cmos, !lght_handle) < 0)
+ return -ENODEV;
+ IBM_HANDLE_INIT(sysl, 0);
+ if (IBM_HANDLE_INIT(led, !sysl_handle) < 0)
+ return -ENODEV;
+
+ /* these handles are not required */
+ IBM_HANDLE_INIT(dock, 0);
+ IBM_HANDLE_INIT(bay, 0);
+ IBM_HANDLE_INIT(bayej, 0);
+ IBM_HANDLE_INIT(bled, 0);
+
+ proc_dir = proc_mkdir(IBM_DIR, acpi_root_dir);
+ if (!proc_dir) {
+ printk(IBM_ERR "unable to create proc dir %s", IBM_DIR);
+ return -ENODEV;
+ }
+ proc_dir->owner = THIS_MODULE;
+
+ for (i=0; i<NUM_IBMS; i++) {
+ ret = ibm_init(&ibms[i]);
+ if (ret < 0) {
+ acpi_ibm_exit();
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+module_init(acpi_ibm_init);
+module_exit(acpi_ibm_exit);
+
+MODULE_AUTHOR("Borislav Deianov");
+MODULE_DESCRIPTION(IBM_DESC);
+MODULE_LICENSE("GPL");
+
+IBM_PARAM(hotkey);
+IBM_PARAM(bluetooth);
+IBM_PARAM(video);
+IBM_PARAM(light);
+IBM_PARAM(dock);
+IBM_PARAM(bay);
+IBM_PARAM(cmos);
+IBM_PARAM(led);
+IBM_PARAM(beep);
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
new file mode 100644
index 000000000000..61ea70742d49
--- /dev/null
+++ b/drivers/acpi/motherboard.c
@@ -0,0 +1,177 @@
+/*
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define _COMPONENT ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME ("acpi_motherboard")
+
+/* Dell use PNP0C01 instead of PNP0C02 */
+#define ACPI_MB_HID1 "PNP0C01"
+#define ACPI_MB_HID2 "PNP0C02"
+
+/**
+ * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
+ * Doesn't care about the failure of 'request_region', since other may reserve
+ * the io ports as well
+ */
+#define IS_RESERVED_ADDR(base, len) \
+ (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
+ && ((base) + (len) > PCIBIOS_MIN_IO))
+
+/*
+ * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
+ * the io ports if they really know they can use it, while
+ * still preventing hotplug PCI devices from using it.
+ */
+
+static acpi_status
+acpi_reserve_io_ranges (struct acpi_resource *res, void *data)
+{
+ struct resource *requested_res = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_reserve_io_ranges");
+
+ if (res->id == ACPI_RSTYPE_IO) {
+ struct acpi_resource_io *io_res = &res->data.io;
+
+ if (io_res->min_base_address != io_res->max_base_address)
+ return_VALUE(AE_OK);
+ if (IS_RESERVED_ADDR(io_res->min_base_address, io_res->range_length)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n",
+ io_res->min_base_address,
+ io_res->min_base_address + io_res->range_length));
+ requested_res = request_region(io_res->min_base_address,
+ io_res->range_length, "motherboard");
+ }
+ } else if (res->id == ACPI_RSTYPE_FIXED_IO) {
+ struct acpi_resource_fixed_io *fixed_io_res = &res->data.fixed_io;
+
+ if (IS_RESERVED_ADDR(fixed_io_res->base_address, fixed_io_res->range_length)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Motherboard resources 0x%08x - 0x%08x\n",
+ fixed_io_res->base_address,
+ fixed_io_res->base_address + fixed_io_res->range_length));
+ requested_res = request_region(fixed_io_res->base_address,
+ fixed_io_res->range_length, "motherboard");
+ }
+ } else {
+ /* Memory mapped IO? */
+ }
+
+ if (requested_res)
+ requested_res->flags &= ~IORESOURCE_BUSY;
+ return_VALUE(AE_OK);
+}
+
+static int acpi_motherboard_add (struct acpi_device *device)
+{
+ if (!device)
+ return -EINVAL;
+ acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+ acpi_reserve_io_ranges, NULL);
+
+ return 0;
+}
+
+static struct acpi_driver acpi_motherboard_driver1 = {
+ .name = "motherboard",
+ .class = "",
+ .ids = ACPI_MB_HID1,
+ .ops = {
+ .add = acpi_motherboard_add,
+ },
+};
+
+static struct acpi_driver acpi_motherboard_driver2 = {
+ .name = "motherboard",
+ .class = "",
+ .ids = ACPI_MB_HID2,
+ .ops = {
+ .add = acpi_motherboard_add,
+ },
+};
+
+static void __init
+acpi_reserve_resources (void)
+{
+ if (acpi_gbl_FADT->xpm1a_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
+ request_region(acpi_gbl_FADT->xpm1a_evt_blk.address,
+ acpi_gbl_FADT->pm1_evt_len, "PM1a_EVT_BLK");
+
+ if (acpi_gbl_FADT->xpm1b_evt_blk.address && acpi_gbl_FADT->pm1_evt_len)
+ request_region(acpi_gbl_FADT->xpm1b_evt_blk.address,
+ acpi_gbl_FADT->pm1_evt_len, "PM1b_EVT_BLK");
+
+ if (acpi_gbl_FADT->xpm1a_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
+ request_region(acpi_gbl_FADT->xpm1a_cnt_blk.address,
+ acpi_gbl_FADT->pm1_cnt_len, "PM1a_CNT_BLK");
+
+ if (acpi_gbl_FADT->xpm1b_cnt_blk.address && acpi_gbl_FADT->pm1_cnt_len)
+ request_region(acpi_gbl_FADT->xpm1b_cnt_blk.address,
+ acpi_gbl_FADT->pm1_cnt_len, "PM1b_CNT_BLK");
+
+ if (acpi_gbl_FADT->xpm_tmr_blk.address && acpi_gbl_FADT->pm_tm_len == 4)
+ request_region(acpi_gbl_FADT->xpm_tmr_blk.address,
+ 4, "PM_TMR");
+
+ if (acpi_gbl_FADT->xpm2_cnt_blk.address && acpi_gbl_FADT->pm2_cnt_len)
+ request_region(acpi_gbl_FADT->xpm2_cnt_blk.address,
+ acpi_gbl_FADT->pm2_cnt_len, "PM2_CNT_BLK");
+
+ /* Length of GPE blocks must be a non-negative multiple of 2 */
+
+ if (acpi_gbl_FADT->xgpe0_blk.address && acpi_gbl_FADT->gpe0_blk_len &&
+ !(acpi_gbl_FADT->gpe0_blk_len & 0x1))
+ request_region(acpi_gbl_FADT->xgpe0_blk.address,
+ acpi_gbl_FADT->gpe0_blk_len, "GPE0_BLK");
+
+ if (acpi_gbl_FADT->xgpe1_blk.address && acpi_gbl_FADT->gpe1_blk_len &&
+ !(acpi_gbl_FADT->gpe1_blk_len & 0x1))
+ request_region(acpi_gbl_FADT->xgpe1_blk.address,
+ acpi_gbl_FADT->gpe1_blk_len, "GPE1_BLK");
+}
+
+static int __init acpi_motherboard_init(void)
+{
+ acpi_bus_register_driver(&acpi_motherboard_driver1);
+ acpi_bus_register_driver(&acpi_motherboard_driver2);
+ /*
+ * Guarantee motherboard IO reservation first
+ * This module must run after scan.c
+ */
+ if (!acpi_disabled)
+ acpi_reserve_resources ();
+ return 0;
+}
+
+/**
+ * Reserve motherboard resources after PCI claim BARs,
+ * but before PCI assign resources for uninitialized PCI devices
+ */
+fs_initcall(acpi_motherboard_init);
diff --git a/drivers/acpi/namespace/Makefile b/drivers/acpi/namespace/Makefile
new file mode 100644
index 000000000000..3f63d3640696
--- /dev/null
+++ b/drivers/acpi/namespace/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := nsaccess.o nsload.o nssearch.o nsxfeval.o \
+ nsalloc.o nseval.o nsnames.o nsutils.o nsxfname.o \
+ nsdump.o nsinit.o nsobject.o nswalk.o nsxfobj.o \
+ nsparse.o
+
+obj-$(ACPI_FUTURE_USAGE) += nsdumpdv.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
new file mode 100644
index 000000000000..1c0c12336c57
--- /dev/null
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -0,0 +1,637 @@
+/*******************************************************************************
+ *
+ * Module Name: nsaccess - Top-level functions for accessing ACPI namespace
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acdispat.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsaccess")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_root_initialize
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate and initialize the default root named objects
+ *
+ * MUTEX: Locks namespace for entire execution
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_root_initialize (void)
+{
+ acpi_status status;
+ const struct acpi_predefined_names *init_val = NULL;
+ struct acpi_namespace_node *new_node;
+ union acpi_operand_object *obj_desc;
+ acpi_string val = NULL;
+
+
+ ACPI_FUNCTION_TRACE ("ns_root_initialize");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * The global root ptr is initially NULL, so a non-NULL value indicates
+ * that acpi_ns_root_initialize() has already been called; just return.
+ */
+ if (acpi_gbl_root_node) {
+ status = AE_OK;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Tell the rest of the subsystem that the root is initialized
+ * (This is OK because the namespace is locked)
+ */
+ acpi_gbl_root_node = &acpi_gbl_root_node_struct;
+
+ /* Enter the pre-defined names in the name table */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Entering predefined entries into namespace\n"));
+
+ for (init_val = acpi_gbl_pre_defined_names; init_val->name; init_val++) {
+ /* _OSI is optional for now, will be permanent later */
+
+ if (!ACPI_STRCMP (init_val->name, "_OSI") && !acpi_gbl_create_osi_method) {
+ continue;
+ }
+
+ status = acpi_ns_lookup (NULL, init_val->name, init_val->type,
+ ACPI_IMODE_LOAD_PASS2, ACPI_NS_NO_UPSEARCH,
+ NULL, &new_node);
+
+ if (ACPI_FAILURE (status) || (!new_node)) /* Must be on same line for code converter */ {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not create predefined name %s, %s\n",
+ init_val->name, acpi_format_exception (status)));
+ }
+
+ /*
+ * Name entered successfully.
+ * If entry in pre_defined_names[] specifies an
+ * initial value, create the initial value.
+ */
+ if (init_val->val) {
+ status = acpi_os_predefined_override (init_val, &val);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not override predefined %s\n",
+ init_val->name));
+ }
+
+ if (!val) {
+ val = init_val->val;
+ }
+
+ /*
+ * Entry requests an initial value, allocate a
+ * descriptor for it.
+ */
+ obj_desc = acpi_ut_create_internal_object (init_val->type);
+ if (!obj_desc) {
+ status = AE_NO_MEMORY;
+ goto unlock_and_exit;
+ }
+
+ /*
+ * Convert value string from table entry to
+ * internal representation. Only types actually
+ * used for initial values are implemented here.
+ */
+ switch (init_val->type) {
+ case ACPI_TYPE_METHOD:
+ obj_desc->method.param_count = (u8) ACPI_TO_INTEGER (val);
+ obj_desc->common.flags |= AOPOBJ_DATA_VALID;
+
+#if defined (_ACPI_ASL_COMPILER) || defined (_ACPI_DUMP_App)
+
+ /*
+ * i_aSL Compiler cheats by putting parameter count
+ * in the owner_iD
+ */
+ new_node->owner_id = obj_desc->method.param_count;
+#else
+ /* Mark this as a very SPECIAL method */
+
+ obj_desc->method.method_flags = AML_METHOD_INTERNAL_ONLY;
+ obj_desc->method.implementation = acpi_ut_osi_implementation;
+#endif
+ break;
+
+ case ACPI_TYPE_INTEGER:
+
+ obj_desc->integer.value = ACPI_TO_INTEGER (val);
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ /*
+ * Build an object around the static string
+ */
+ obj_desc->string.length = (u32) ACPI_STRLEN (val);
+ obj_desc->string.pointer = val;
+ obj_desc->common.flags |= AOPOBJ_STATIC_POINTER;
+ break;
+
+
+ case ACPI_TYPE_MUTEX:
+
+ obj_desc->mutex.node = new_node;
+ obj_desc->mutex.sync_level = (u8) (ACPI_TO_INTEGER (val) - 1);
+
+ if (ACPI_STRCMP (init_val->name, "_GL_") == 0) {
+ /*
+ * Create a counting semaphore for the
+ * global lock
+ */
+ status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT,
+ 1, &obj_desc->mutex.semaphore);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (obj_desc);
+ goto unlock_and_exit;
+ }
+
+ /*
+ * We just created the mutex for the
+ * global lock, save it
+ */
+ acpi_gbl_global_lock_semaphore = obj_desc->mutex.semaphore;
+ }
+ else {
+ /* Create a mutex */
+
+ status = acpi_os_create_semaphore (1, 1,
+ &obj_desc->mutex.semaphore);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_remove_reference (obj_desc);
+ goto unlock_and_exit;
+ }
+ }
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("Unsupported initial type value %X\n",
+ init_val->type));
+ acpi_ut_remove_reference (obj_desc);
+ obj_desc = NULL;
+ continue;
+ }
+
+ /* Store pointer to value descriptor in the Node */
+
+ status = acpi_ns_attach_object (new_node, obj_desc,
+ ACPI_GET_OBJECT_TYPE (obj_desc));
+
+ /* Remove local reference to the object */
+
+ acpi_ut_remove_reference (obj_desc);
+ }
+ }
+
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+
+ /* Save a handle to "_GPE", it is always present */
+
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ns_get_node_by_path ("\\_GPE", NULL, ACPI_NS_NO_UPSEARCH,
+ &acpi_gbl_fadt_gpe_device);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_lookup
+ *
+ * PARAMETERS: prefix_node - Search scope if name is not fully qualified
+ * Pathname - Search pathname, in internal format
+ * (as represented in the AML stream)
+ * Type - Type associated with name
+ * interpreter_mode - IMODE_LOAD_PASS2 => add name if not found
+ * Flags - Flags describing the search restrictions
+ * walk_state - Current state of the walk
+ * return_node - Where the Node is placed (if found
+ * or created successfully)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find or enter the passed name in the name space.
+ * Log an error if name not found in Exec mode.
+ *
+ * MUTEX: Assumes namespace is locked.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_lookup (
+ union acpi_generic_state *scope_info,
+ char *pathname,
+ acpi_object_type type,
+ acpi_interpreter_mode interpreter_mode,
+ u32 flags,
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node **return_node)
+{
+ acpi_status status;
+ char *path = pathname;
+ struct acpi_namespace_node *prefix_node;
+ struct acpi_namespace_node *current_node = NULL;
+ struct acpi_namespace_node *this_node = NULL;
+ u32 num_segments;
+ u32 num_carats;
+ acpi_name simple_name;
+ acpi_object_type type_to_check_for;
+ acpi_object_type this_search_type;
+ u32 search_parent_flag = ACPI_NS_SEARCH_PARENT;
+ u32 local_flags = flags & ~(ACPI_NS_ERROR_IF_FOUND |
+ ACPI_NS_SEARCH_PARENT);
+
+
+ ACPI_FUNCTION_TRACE ("ns_lookup");
+
+
+ if (!return_node) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ acpi_gbl_ns_lookup_count++;
+ *return_node = ACPI_ENTRY_NOT_FOUND;
+
+ if (!acpi_gbl_root_node) {
+ return_ACPI_STATUS (AE_NO_NAMESPACE);
+ }
+
+ /*
+ * Get the prefix scope.
+ * A null scope means use the root scope
+ */
+ if ((!scope_info) ||
+ (!scope_info->scope.node)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Null scope prefix, using root node (%p)\n",
+ acpi_gbl_root_node));
+
+ prefix_node = acpi_gbl_root_node;
+ }
+ else {
+ prefix_node = scope_info->scope.node;
+ if (ACPI_GET_DESCRIPTOR_TYPE (prefix_node) != ACPI_DESC_TYPE_NAMED) {
+ ACPI_REPORT_ERROR (("ns_lookup: %p is not a namespace node [%s]\n",
+ prefix_node, acpi_ut_get_descriptor_name (prefix_node)));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ /*
+ * This node might not be a actual "scope" node (such as a
+ * Device/Method, etc.) It could be a Package or other object node.
+ * Backup up the tree to find the containing scope node.
+ */
+ while (!acpi_ns_opens_scope (prefix_node->type) &&
+ prefix_node->type != ACPI_TYPE_ANY) {
+ prefix_node = acpi_ns_get_parent_node (prefix_node);
+ }
+ }
+
+ /* Save type TBD: may be no longer necessary */
+
+ type_to_check_for = type;
+
+ /*
+ * Begin examination of the actual pathname
+ */
+ if (!pathname) {
+ /* A Null name_path is allowed and refers to the root */
+
+ num_segments = 0;
+ this_node = acpi_gbl_root_node;
+ path = "";
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Null Pathname (Zero segments), Flags=%X\n", flags));
+ }
+ else {
+ /*
+ * Name pointer is valid (and must be in internal name format)
+ *
+ * Check for scope prefixes:
+ *
+ * As represented in the AML stream, a namepath consists of an
+ * optional scope prefix followed by a name segment part.
+ *
+ * If present, the scope prefix is either a Root Prefix (in
+ * which case the name is fully qualified), or one or more
+ * Parent Prefixes (in which case the name's scope is relative
+ * to the current scope).
+ */
+ if (*path == (u8) AML_ROOT_PREFIX) {
+ /* Pathname is fully qualified, start from the root */
+
+ this_node = acpi_gbl_root_node;
+ search_parent_flag = ACPI_NS_NO_UPSEARCH;
+
+ /* Point to name segment part */
+
+ path++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Path is absolute from root [%p]\n", this_node));
+ }
+ else {
+ /* Pathname is relative to current scope, start there */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Searching relative to prefix scope [%4.4s] (%p)\n",
+ acpi_ut_get_node_name (prefix_node), prefix_node));
+
+ /*
+ * Handle multiple Parent Prefixes (carat) by just getting
+ * the parent node for each prefix instance.
+ */
+ this_node = prefix_node;
+ num_carats = 0;
+ while (*path == (u8) AML_PARENT_PREFIX) {
+ /* Name is fully qualified, no search rules apply */
+
+ search_parent_flag = ACPI_NS_NO_UPSEARCH;
+ /*
+ * Point past this prefix to the name segment
+ * part or the next Parent Prefix
+ */
+ path++;
+
+ /* Backup to the parent node */
+
+ num_carats++;
+ this_node = acpi_ns_get_parent_node (this_node);
+ if (!this_node) {
+ /* Current scope has no parent scope */
+
+ ACPI_REPORT_ERROR (
+ ("ACPI path has too many parent prefixes (^) - reached beyond root node\n"));
+ return_ACPI_STATUS (AE_NOT_FOUND);
+ }
+ }
+
+ if (search_parent_flag == ACPI_NS_NO_UPSEARCH) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Search scope is [%4.4s], path has %d carat(s)\n",
+ acpi_ut_get_node_name (this_node), num_carats));
+ }
+ }
+
+ /*
+ * Determine the number of ACPI name segments in this pathname.
+ *
+ * The segment part consists of either:
+ * - A Null name segment (0)
+ * - A dual_name_prefix followed by two 4-byte name segments
+ * - A multi_name_prefix followed by a byte indicating the
+ * number of segments and the segments themselves.
+ * - A single 4-byte name segment
+ *
+ * Examine the name prefix opcode, if any, to determine the number of
+ * segments.
+ */
+ switch (*path) {
+ case 0:
+ /*
+ * Null name after a root or parent prefixes. We already
+ * have the correct target node and there are no name segments.
+ */
+ num_segments = 0;
+ type = this_node->type;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Prefix-only Pathname (Zero name segments), Flags=%X\n",
+ flags));
+ break;
+
+ case AML_DUAL_NAME_PREFIX:
+
+ /* More than one name_seg, search rules do not apply */
+
+ search_parent_flag = ACPI_NS_NO_UPSEARCH;
+
+ /* Two segments, point to first name segment */
+
+ num_segments = 2;
+ path++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Dual Pathname (2 segments, Flags=%X)\n", flags));
+ break;
+
+ case AML_MULTI_NAME_PREFIX_OP:
+
+ /* More than one name_seg, search rules do not apply */
+
+ search_parent_flag = ACPI_NS_NO_UPSEARCH;
+
+ /* Extract segment count, point to first name segment */
+
+ path++;
+ num_segments = (u32) (u8) *path;
+ path++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Multi Pathname (%d Segments, Flags=%X) \n",
+ num_segments, flags));
+ break;
+
+ default:
+ /*
+ * Not a Null name, no Dual or Multi prefix, hence there is
+ * only one name segment and Pathname is already pointing to it.
+ */
+ num_segments = 1;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Simple Pathname (1 segment, Flags=%X)\n", flags));
+ break;
+ }
+
+ ACPI_DEBUG_EXEC (acpi_ns_print_pathname (num_segments, path));
+ }
+
+
+ /*
+ * Search namespace for each segment of the name. Loop through and
+ * verify (or add to the namespace) each name segment.
+ *
+ * The object type is significant only at the last name
+ * segment. (We don't care about the types along the path, only
+ * the type of the final target object.)
+ */
+ this_search_type = ACPI_TYPE_ANY;
+ current_node = this_node;
+ while (num_segments && current_node) {
+ num_segments--;
+ if (!num_segments) {
+ /*
+ * This is the last segment, enable typechecking
+ */
+ this_search_type = type;
+
+ /*
+ * Only allow automatic parent search (search rules) if the caller
+ * requested it AND we have a single, non-fully-qualified name_seg
+ */
+ if ((search_parent_flag != ACPI_NS_NO_UPSEARCH) &&
+ (flags & ACPI_NS_SEARCH_PARENT)) {
+ local_flags |= ACPI_NS_SEARCH_PARENT;
+ }
+
+ /* Set error flag according to caller */
+
+ if (flags & ACPI_NS_ERROR_IF_FOUND) {
+ local_flags |= ACPI_NS_ERROR_IF_FOUND;
+ }
+ }
+
+ /* Extract one ACPI name from the front of the pathname */
+
+ ACPI_MOVE_32_TO_32 (&simple_name, path);
+
+ /* Try to find the single (4 character) ACPI name */
+
+ status = acpi_ns_search_and_enter (simple_name, walk_state, current_node,
+ interpreter_mode, this_search_type, local_flags, &this_node);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_NOT_FOUND) {
+ /* Name not found in ACPI namespace */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Name [%4.4s] not found in scope [%4.4s] %p\n",
+ (char *) &simple_name, (char *) &current_node->name,
+ current_node));
+ }
+
+ *return_node = this_node;
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Sanity typecheck of the target object:
+ *
+ * If 1) This is the last segment (num_segments == 0)
+ * 2) And we are looking for a specific type
+ * (Not checking for TYPE_ANY)
+ * 3) Which is not an alias
+ * 4) Which is not a local type (TYPE_SCOPE)
+ * 5) And the type of target object is known (not TYPE_ANY)
+ * 6) And target object does not match what we are looking for
+ *
+ * Then we have a type mismatch. Just warn and ignore it.
+ */
+ if ((num_segments == 0) &&
+ (type_to_check_for != ACPI_TYPE_ANY) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_ALIAS) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_METHOD_ALIAS) &&
+ (type_to_check_for != ACPI_TYPE_LOCAL_SCOPE) &&
+ (this_node->type != ACPI_TYPE_ANY) &&
+ (this_node->type != type_to_check_for)) {
+ /* Complain about a type mismatch */
+
+ ACPI_REPORT_WARNING (
+ ("ns_lookup: Type mismatch on %4.4s (%s), searching for (%s)\n",
+ (char *) &simple_name, acpi_ut_get_type_name (this_node->type),
+ acpi_ut_get_type_name (type_to_check_for)));
+ }
+
+ /*
+ * If this is the last name segment and we are not looking for a
+ * specific type, but the type of found object is known, use that type
+ * to see if it opens a scope.
+ */
+ if ((num_segments == 0) && (type == ACPI_TYPE_ANY)) {
+ type = this_node->type;
+ }
+
+ /* Point to next name segment and make this node current */
+
+ path += ACPI_NAME_SIZE;
+ current_node = this_node;
+ }
+
+ /*
+ * Always check if we need to open a new scope
+ */
+ if (!(flags & ACPI_NS_DONT_OPEN_SCOPE) && (walk_state)) {
+ /*
+ * If entry is a type which opens a scope, push the new scope on the
+ * scope stack.
+ */
+ if (acpi_ns_opens_scope (type)) {
+ status = acpi_ds_scope_stack_push (this_node, type, walk_state);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ }
+
+ *return_node = this_node;
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
new file mode 100644
index 000000000000..bfd922c5c7d1
--- /dev/null
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -0,0 +1,685 @@
+/*******************************************************************************
+ *
+ * Module Name: nsalloc - Namespace allocation and deletion utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsalloc")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_create_node
+ *
+ * PARAMETERS: acpi_name - Name of the new node
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Create a namespace node
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *
+acpi_ns_create_node (
+ u32 name)
+{
+ struct acpi_namespace_node *node;
+
+
+ ACPI_FUNCTION_TRACE ("ns_create_node");
+
+
+ node = ACPI_MEM_CALLOCATE (sizeof (struct acpi_namespace_node));
+ if (!node) {
+ return_PTR (NULL);
+ }
+
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_allocated++);
+
+ node->name.integer = name;
+ node->reference_count = 1;
+ ACPI_SET_DESCRIPTOR_TYPE (node, ACPI_DESC_TYPE_NAMED);
+
+ return_PTR (node);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_delete_node
+ *
+ * PARAMETERS: Node - Node to be deleted
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete a namespace node
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_delete_node (
+ struct acpi_namespace_node *node)
+{
+ struct acpi_namespace_node *parent_node;
+ struct acpi_namespace_node *prev_node;
+ struct acpi_namespace_node *next_node;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ns_delete_node", node);
+
+
+ parent_node = acpi_ns_get_parent_node (node);
+
+ prev_node = NULL;
+ next_node = parent_node->child;
+
+ /* Find the node that is the previous peer in the parent's child list */
+
+ while (next_node != node) {
+ prev_node = next_node;
+ next_node = prev_node->peer;
+ }
+
+ if (prev_node) {
+ /* Node is not first child, unlink it */
+
+ prev_node->peer = next_node->peer;
+ if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
+ prev_node->flags |= ANOBJ_END_OF_PEER_LIST;
+ }
+ }
+ else {
+ /* Node is first child (has no previous peer) */
+
+ if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
+ /* No peers at all */
+
+ parent_node->child = NULL;
+ }
+ else { /* Link peer list to parent */
+
+ parent_node->child = next_node->peer;
+ }
+ }
+
+
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++);
+
+ /*
+ * Detach an object if there is one then delete the node
+ */
+ acpi_ns_detach_object (node);
+ ACPI_MEM_FREE (node);
+ return_VOID;
+}
+
+
+#ifdef ACPI_ALPHABETIC_NAMESPACE
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_compare_names
+ *
+ * PARAMETERS: Name1 - First name to compare
+ * Name2 - Second name to compare
+ *
+ * RETURN: value from strncmp
+ *
+ * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an
+ * underscore are forced to be alphabetically first.
+ *
+ ******************************************************************************/
+
+int
+acpi_ns_compare_names (
+ char *name1,
+ char *name2)
+{
+ char reversed_name1[ACPI_NAME_SIZE];
+ char reversed_name2[ACPI_NAME_SIZE];
+ u32 i;
+ u32 j;
+
+
+ /*
+ * Replace all instances of "underscore" with a value that is smaller so
+ * that all names that are prefixed with underscore(s) are alphabetically
+ * first.
+ *
+ * Reverse the name bytewise so we can just do a 32-bit compare instead
+ * of a strncmp.
+ */
+ for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) {
+ reversed_name1[j] = name1[i];
+ if (name1[i] == '_') {
+ reversed_name1[j] = '*';
+ }
+
+ reversed_name2[j] = name2[i];
+ if (name2[i] == '_') {
+ reversed_name2[j] = '*';
+ }
+ }
+
+ return (*(int *) reversed_name1 - *(int *) reversed_name2);
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_install_node
+ *
+ * PARAMETERS: walk_state - Current state of the walk
+ * parent_node - The parent of the new Node
+ * Node - The new Node to install
+ * Type - ACPI object type of the new Node
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a new namespace node and install it amongst
+ * its peers.
+ *
+ * Note: Current namespace lookup is linear search. However, the
+ * nodes are linked in alphabetical order to 1) put all reserved
+ * names (start with underscore) first, and to 2) make a readable
+ * namespace dump.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_install_node (
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node *parent_node, /* Parent */
+ struct acpi_namespace_node *node, /* New Child*/
+ acpi_object_type type)
+{
+ u16 owner_id = 0;
+ struct acpi_namespace_node *child_node;
+#ifdef ACPI_ALPHABETIC_NAMESPACE
+
+ struct acpi_namespace_node *previous_child_node;
+#endif
+
+
+ ACPI_FUNCTION_TRACE ("ns_install_node");
+
+
+ /*
+ * Get the owner ID from the Walk state
+ * The owner ID is used to track table deletion and
+ * deletion of objects created by methods
+ */
+ if (walk_state) {
+ owner_id = walk_state->owner_id;
+ }
+
+ /* Link the new entry into the parent and existing children */
+
+ child_node = parent_node->child;
+ if (!child_node) {
+ parent_node->child = node;
+ node->flags |= ANOBJ_END_OF_PEER_LIST;
+ node->peer = parent_node;
+ }
+ else {
+#ifdef ACPI_ALPHABETIC_NAMESPACE
+ /*
+ * Walk the list whilst searching for the correct
+ * alphabetic placement.
+ */
+ previous_child_node = NULL;
+ while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) {
+ if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
+ /* Last peer; Clear end-of-list flag */
+
+ child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
+
+ /* This node is the new peer to the child node */
+
+ child_node->peer = node;
+
+ /* This node is the new end-of-list */
+
+ node->flags |= ANOBJ_END_OF_PEER_LIST;
+ node->peer = parent_node;
+ break;
+ }
+
+ /* Get next peer */
+
+ previous_child_node = child_node;
+ child_node = child_node->peer;
+ }
+
+ /* Did the node get inserted at the end-of-list? */
+
+ if (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
+ /*
+ * Loop above terminated without reaching the end-of-list.
+ * Insert the new node at the current location
+ */
+ if (previous_child_node) {
+ /* Insert node alphabetically */
+
+ node->peer = child_node;
+ previous_child_node->peer = node;
+ }
+ else {
+ /* Insert node alphabetically at start of list */
+
+ node->peer = child_node;
+ parent_node->child = node;
+ }
+ }
+#else
+ while (!(child_node->flags & ANOBJ_END_OF_PEER_LIST)) {
+ child_node = child_node->peer;
+ }
+
+ child_node->peer = node;
+
+ /* Clear end-of-list flag */
+
+ child_node->flags &= ~ANOBJ_END_OF_PEER_LIST;
+ node->flags |= ANOBJ_END_OF_PEER_LIST;
+ node->peer = parent_node;
+#endif
+ }
+
+ /* Init the new entry */
+
+ node->owner_id = owner_id;
+ node->type = (u8) type;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "%4.4s (%s) [Node %p Owner %X] added to %4.4s (%s) [Node %p]\n",
+ acpi_ut_get_node_name (node), acpi_ut_get_type_name (node->type), node, owner_id,
+ acpi_ut_get_node_name (parent_node), acpi_ut_get_type_name (parent_node->type),
+ parent_node));
+
+ /*
+ * Increment the reference count(s) of all parents up to
+ * the root!
+ */
+ while ((node = acpi_ns_get_parent_node (node)) != NULL) {
+ node->reference_count++;
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_delete_children
+ *
+ * PARAMETERS: parent_node - Delete this objects children
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete all children of the parent object. In other words,
+ * deletes a "scope".
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_delete_children (
+ struct acpi_namespace_node *parent_node)
+{
+ struct acpi_namespace_node *child_node;
+ struct acpi_namespace_node *next_node;
+ struct acpi_namespace_node *node;
+ u8 flags;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ns_delete_children", parent_node);
+
+
+ if (!parent_node) {
+ return_VOID;
+ }
+
+ /* If no children, all done! */
+
+ child_node = parent_node->child;
+ if (!child_node) {
+ return_VOID;
+ }
+
+ /*
+ * Deallocate all children at this level
+ */
+ do {
+ /* Get the things we need */
+
+ next_node = child_node->peer;
+ flags = child_node->flags;
+
+ /* Grandchildren should have all been deleted already */
+
+ if (child_node->child) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Found a grandchild! P=%p C=%p\n",
+ parent_node, child_node));
+ }
+
+ /* Now we can free this child object */
+
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p, Remaining %X\n",
+ child_node, acpi_gbl_current_node_count));
+
+ /*
+ * Detach an object if there is one, then free the child node
+ */
+ acpi_ns_detach_object (child_node);
+
+ /*
+ * Decrement the reference count(s) of all parents up to
+ * the root! (counts were incremented when the node was created)
+ */
+ node = child_node;
+ while ((node = acpi_ns_get_parent_node (node)) != NULL) {
+ node->reference_count--;
+ }
+
+ /* There should be only one reference remaining on this node */
+
+ if (child_node->reference_count != 1) {
+ ACPI_REPORT_WARNING (("Existing references (%d) on node being deleted (%p)\n",
+ child_node->reference_count, child_node));
+ }
+
+ /* Now we can delete the node */
+
+ ACPI_MEM_FREE (child_node);
+
+ /* And move on to the next child in the list */
+
+ child_node = next_node;
+
+ } while (!(flags & ANOBJ_END_OF_PEER_LIST));
+
+
+ /* Clear the parent's child pointer */
+
+ parent_node->child = NULL;
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_delete_namespace_subtree
+ *
+ * PARAMETERS: parent_node - Root of the subtree to be deleted
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete a subtree of the namespace. This includes all objects
+ * stored within the subtree.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_delete_namespace_subtree (
+ struct acpi_namespace_node *parent_node)
+{
+ struct acpi_namespace_node *child_node = NULL;
+ u32 level = 1;
+
+
+ ACPI_FUNCTION_TRACE ("ns_delete_namespace_subtree");
+
+
+ if (!parent_node) {
+ return_VOID;
+ }
+
+ /*
+ * Traverse the tree of objects until we bubble back up
+ * to where we started.
+ */
+ while (level > 0) {
+ /* Get the next node in this scope (NULL if none) */
+
+ child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node,
+ child_node);
+ if (child_node) {
+ /* Found a child node - detach any attached object */
+
+ acpi_ns_detach_object (child_node);
+
+ /* Check if this node has any children */
+
+ if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) {
+ /*
+ * There is at least one child of this node,
+ * visit the node
+ */
+ level++;
+ parent_node = child_node;
+ child_node = NULL;
+ }
+ }
+ else {
+ /*
+ * No more children of this parent node.
+ * Move up to the grandparent.
+ */
+ level--;
+
+ /*
+ * Now delete all of the children of this parent
+ * all at the same time.
+ */
+ acpi_ns_delete_children (parent_node);
+
+ /* New "last child" is this parent node */
+
+ child_node = parent_node;
+
+ /* Move up the tree to the grandparent */
+
+ parent_node = acpi_ns_get_parent_node (parent_node);
+ }
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_remove_reference
+ *
+ * PARAMETERS: Node - Named node whose reference count is to be
+ * decremented
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Remove a Node reference. Decrements the reference count
+ * of all parent Nodes up to the root. Any node along
+ * the way that reaches zero references is freed.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_remove_reference (
+ struct acpi_namespace_node *node)
+{
+ struct acpi_namespace_node *parent_node;
+ struct acpi_namespace_node *this_node;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * Decrement the reference count(s) of this node and all
+ * nodes up to the root, Delete anything with zero remaining references.
+ */
+ this_node = node;
+ while (this_node) {
+ /* Prepare to move up to parent */
+
+ parent_node = acpi_ns_get_parent_node (this_node);
+
+ /* Decrement the reference count on this node */
+
+ this_node->reference_count--;
+
+ /* Delete the node if no more references */
+
+ if (!this_node->reference_count) {
+ /* Delete all children and delete the node */
+
+ acpi_ns_delete_children (this_node);
+ acpi_ns_delete_node (this_node);
+ }
+
+ this_node = parent_node;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_delete_namespace_by_owner
+ *
+ * PARAMETERS: owner_id - All nodes with this owner will be deleted
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete entries within the namespace that are owned by a
+ * specific ID. Used to delete entire ACPI tables. All
+ * reference counts are updated.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_delete_namespace_by_owner (
+ u16 owner_id)
+{
+ struct acpi_namespace_node *child_node;
+ struct acpi_namespace_node *deletion_node;
+ u32 level;
+ struct acpi_namespace_node *parent_node;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ns_delete_namespace_by_owner", owner_id);
+
+
+ parent_node = acpi_gbl_root_node;
+ child_node = NULL;
+ deletion_node = NULL;
+ level = 1;
+
+ /*
+ * Traverse the tree of nodes until we bubble back up
+ * to where we started.
+ */
+ while (level > 0) {
+ /*
+ * Get the next child of this parent node. When child_node is NULL,
+ * the first child of the parent is returned
+ */
+ child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node, child_node);
+
+ if (deletion_node) {
+ acpi_ns_remove_reference (deletion_node);
+ deletion_node = NULL;
+ }
+
+ if (child_node) {
+ if (child_node->owner_id == owner_id) {
+ /* Found a matching child node - detach any attached object */
+
+ acpi_ns_detach_object (child_node);
+ }
+
+ /* Check if this node has any children */
+
+ if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) {
+ /*
+ * There is at least one child of this node,
+ * visit the node
+ */
+ level++;
+ parent_node = child_node;
+ child_node = NULL;
+ }
+ else if (child_node->owner_id == owner_id) {
+ deletion_node = child_node;
+ }
+ }
+ else {
+ /*
+ * No more children of this parent node.
+ * Move up to the grandparent.
+ */
+ level--;
+ if (level != 0) {
+ if (parent_node->owner_id == owner_id) {
+ deletion_node = parent_node;
+ }
+ }
+
+ /* New "last child" is this parent node */
+
+ child_node = parent_node;
+
+ /* Move up the tree to the grandparent */
+
+ parent_node = acpi_ns_get_parent_node (parent_node);
+ }
+ }
+
+ return_VOID;
+}
+
+
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
new file mode 100644
index 000000000000..1f6af3eb6c91
--- /dev/null
+++ b/drivers/acpi/namespace/nsdump.c
@@ -0,0 +1,673 @@
+/******************************************************************************
+ *
+ * Module Name: nsdump - table dumping routines for debug
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsdump")
+
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_print_pathname
+ *
+ * PARAMETERS: num_segment - Number of ACPI name segments
+ * Pathname - The compressed (internal) path
+ *
+ * DESCRIPTION: Print an object's full namespace pathname
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_print_pathname (
+ u32 num_segments,
+ char *pathname)
+{
+ ACPI_FUNCTION_NAME ("ns_print_pathname");
+
+
+ if (!(acpi_dbg_level & ACPI_LV_NAMES) || !(acpi_dbg_layer & ACPI_NAMESPACE)) {
+ return;
+ }
+
+ /* Print the entire name */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "["));
+
+ while (num_segments) {
+ acpi_os_printf ("%4.4s", pathname);
+ pathname += ACPI_NAME_SIZE;
+
+ num_segments--;
+ if (num_segments) {
+ acpi_os_printf (".");
+ }
+ }
+
+ acpi_os_printf ("]\n");
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_dump_pathname
+ *
+ * PARAMETERS: Handle - Object
+ * Msg - Prefix message
+ * Level - Desired debug level
+ * Component - Caller's component ID
+ *
+ * DESCRIPTION: Print an object's full namespace pathname
+ * Manages allocation/freeing of a pathname buffer
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_dump_pathname (
+ acpi_handle handle,
+ char *msg,
+ u32 level,
+ u32 component)
+{
+
+ ACPI_FUNCTION_TRACE ("ns_dump_pathname");
+
+
+ /* Do this only if the requested debug level and component are enabled */
+
+ if (!(acpi_dbg_level & level) || !(acpi_dbg_layer & component)) {
+ return_VOID;
+ }
+
+ /* Convert handle to a full pathname and print it (with supplied message) */
+
+ acpi_ns_print_node_pathname (handle, msg);
+ acpi_os_printf ("\n");
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_dump_one_object
+ *
+ * PARAMETERS: Handle - Node to be dumped
+ * Level - Nesting level of the handle
+ * Context - Passed into walk_namespace
+ *
+ * DESCRIPTION: Dump a single Node
+ * This procedure is a user_function called by acpi_ns_walk_namespace.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_dump_one_object (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ struct acpi_walk_info *info = (struct acpi_walk_info *) context;
+ struct acpi_namespace_node *this_node;
+ union acpi_operand_object *obj_desc = NULL;
+ acpi_object_type obj_type;
+ acpi_object_type type;
+ u32 bytes_to_dump;
+ u32 dbg_level;
+ u32 i;
+
+
+ ACPI_FUNCTION_NAME ("ns_dump_one_object");
+
+
+ /* Is output enabled? */
+
+ if (!(acpi_dbg_level & info->debug_level)) {
+ return (AE_OK);
+ }
+
+ if (!obj_handle) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Null object handle\n"));
+ return (AE_OK);
+ }
+
+ this_node = acpi_ns_map_handle_to_node (obj_handle);
+ type = this_node->type;
+
+ /* Check if the owner matches */
+
+ if ((info->owner_id != ACPI_UINT32_MAX) &&
+ (info->owner_id != this_node->owner_id)) {
+ return (AE_OK);
+ }
+
+ /* Indent the object according to the level */
+
+ acpi_os_printf ("%2d%*s", (u32) level - 1, (int) level * 2, " ");
+
+ /* Check the node type and name */
+
+ if (type > ACPI_TYPE_LOCAL_MAX) {
+ ACPI_REPORT_WARNING (("Invalid ACPI Type %08X\n", type));
+ }
+
+ if (!acpi_ut_valid_acpi_name (this_node->name.integer)) {
+ ACPI_REPORT_WARNING (("Invalid ACPI Name %08X\n",
+ this_node->name.integer));
+ }
+
+ /*
+ * Now we can print out the pertinent information
+ */
+ acpi_os_printf ("%4.4s %-12s %p ",
+ acpi_ut_get_node_name (this_node), acpi_ut_get_type_name (type), this_node);
+
+ dbg_level = acpi_dbg_level;
+ acpi_dbg_level = 0;
+ obj_desc = acpi_ns_get_attached_object (this_node);
+ acpi_dbg_level = dbg_level;
+
+ switch (info->display_type) {
+ case ACPI_DISPLAY_SUMMARY:
+
+ if (!obj_desc) {
+ /* No attached object, we are done */
+
+ acpi_os_printf ("\n");
+ return (AE_OK);
+ }
+
+ switch (type) {
+ case ACPI_TYPE_PROCESSOR:
+
+ acpi_os_printf ("ID %X Len %.4X Addr %p\n",
+ obj_desc->processor.proc_id, obj_desc->processor.length,
+ (char *) obj_desc->processor.address);
+ break;
+
+
+ case ACPI_TYPE_DEVICE:
+
+ acpi_os_printf ("Notify Object: %p\n", obj_desc);
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ acpi_os_printf ("Args %X Len %.4X Aml %p\n",
+ (u32) obj_desc->method.param_count,
+ obj_desc->method.aml_length, obj_desc->method.aml_start);
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+
+ acpi_os_printf ("= %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ acpi_os_printf ("Elements %.2X\n",
+ obj_desc->package.count);
+ }
+ else {
+ acpi_os_printf ("[Length not yet evaluated]\n");
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ acpi_os_printf ("Len %.2X",
+ obj_desc->buffer.length);
+
+ /* Dump some of the buffer */
+
+ if (obj_desc->buffer.length > 0) {
+ acpi_os_printf (" =");
+ for (i = 0; (i < obj_desc->buffer.length && i < 12); i++) {
+ acpi_os_printf (" %.2hX", obj_desc->buffer.pointer[i]);
+ }
+ }
+ acpi_os_printf ("\n");
+ }
+ else {
+ acpi_os_printf ("[Length not yet evaluated]\n");
+ }
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ acpi_os_printf ("Len %.2X ", obj_desc->string.length);
+ acpi_ut_print_string (obj_desc->string.pointer, 32);
+ acpi_os_printf ("\n");
+ break;
+
+
+ case ACPI_TYPE_REGION:
+
+ acpi_os_printf ("[%s]",
+ acpi_ut_get_region_name (obj_desc->region.space_id));
+ if (obj_desc->region.flags & AOPOBJ_DATA_VALID) {
+ acpi_os_printf (" Addr %8.8X%8.8X Len %.4X\n",
+ ACPI_FORMAT_UINT64 (obj_desc->region.address),
+ obj_desc->region.length);
+ }
+ else {
+ acpi_os_printf (" [Address/Length not yet evaluated]\n");
+ }
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ acpi_os_printf ("[%s]\n",
+ acpi_ps_get_opcode_name (obj_desc->reference.opcode));
+ break;
+
+
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ if (obj_desc->buffer_field.buffer_obj &&
+ obj_desc->buffer_field.buffer_obj->buffer.node) {
+ acpi_os_printf ("Buf [%4.4s]",
+ acpi_ut_get_node_name (obj_desc->buffer_field.buffer_obj->buffer.node));
+ }
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+ acpi_os_printf ("Rgn [%4.4s]",
+ acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node));
+ break;
+
+
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ acpi_os_printf ("Rgn [%4.4s] Bnk [%4.4s]",
+ acpi_ut_get_node_name (obj_desc->common_field.region_obj->region.node),
+ acpi_ut_get_node_name (obj_desc->bank_field.bank_obj->common_field.node));
+ break;
+
+
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ acpi_os_printf ("Idx [%4.4s] Dat [%4.4s]",
+ acpi_ut_get_node_name (obj_desc->index_field.index_obj->common_field.node),
+ acpi_ut_get_node_name (obj_desc->index_field.data_obj->common_field.node));
+ break;
+
+
+ case ACPI_TYPE_LOCAL_ALIAS:
+ case ACPI_TYPE_LOCAL_METHOD_ALIAS:
+
+ acpi_os_printf ("Target %4.4s (%p)\n",
+ acpi_ut_get_node_name (obj_desc), obj_desc);
+ break;
+
+ default:
+
+ acpi_os_printf ("Object %p\n", obj_desc);
+ break;
+ }
+
+ /* Common field handling */
+
+ switch (type) {
+ case ACPI_TYPE_BUFFER_FIELD:
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ acpi_os_printf (" Off %.3X Len %.2X Acc %.2hd\n",
+ (obj_desc->common_field.base_byte_offset * 8)
+ + obj_desc->common_field.start_field_bit_offset,
+ obj_desc->common_field.bit_length,
+ obj_desc->common_field.access_byte_width);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+
+ case ACPI_DISPLAY_OBJECTS:
+
+ acpi_os_printf ("O:%p", obj_desc);
+ if (!obj_desc) {
+ /* No attached object, we are done */
+
+ acpi_os_printf ("\n");
+ return (AE_OK);
+ }
+
+ acpi_os_printf ("(R%d)",
+ obj_desc->common.reference_count);
+
+ switch (type) {
+ case ACPI_TYPE_METHOD:
+
+ /* Name is a Method and its AML offset/length are set */
+
+ acpi_os_printf (" M:%p-%X\n", obj_desc->method.aml_start,
+ obj_desc->method.aml_length);
+ break;
+
+ case ACPI_TYPE_INTEGER:
+
+ acpi_os_printf (" I:%8.8X8.8%X\n",
+ ACPI_FORMAT_UINT64 (obj_desc->integer.value));
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ acpi_os_printf (" S:%p-%X\n", obj_desc->string.pointer,
+ obj_desc->string.length);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ acpi_os_printf (" B:%p-%X\n", obj_desc->buffer.pointer,
+ obj_desc->buffer.length);
+ break;
+
+ default:
+
+ acpi_os_printf ("\n");
+ break;
+ }
+ break;
+
+
+ default:
+ acpi_os_printf ("\n");
+ break;
+ }
+
+ /* If debug turned off, done */
+
+ if (!(acpi_dbg_level & ACPI_LV_VALUES)) {
+ return (AE_OK);
+ }
+
+
+ /* If there is an attached object, display it */
+
+ dbg_level = acpi_dbg_level;
+ acpi_dbg_level = 0;
+ obj_desc = acpi_ns_get_attached_object (this_node);
+ acpi_dbg_level = dbg_level;
+
+ /* Dump attached objects */
+
+ while (obj_desc) {
+ obj_type = ACPI_TYPE_INVALID;
+ acpi_os_printf (" Attached Object %p: ", obj_desc);
+
+ /* Decode the type of attached object and dump the contents */
+
+ switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
+ case ACPI_DESC_TYPE_NAMED:
+
+ acpi_os_printf ("(Ptr to Node)\n");
+ bytes_to_dump = sizeof (struct acpi_namespace_node);
+ break;
+
+
+ case ACPI_DESC_TYPE_OPERAND:
+
+ obj_type = ACPI_GET_OBJECT_TYPE (obj_desc);
+
+ if (obj_type > ACPI_TYPE_LOCAL_MAX) {
+ acpi_os_printf ("(Ptr to ACPI Object type %X [UNKNOWN])\n",
+ obj_type);
+ bytes_to_dump = 32;
+ }
+ else {
+ acpi_os_printf ("(Ptr to ACPI Object type %s, %X)\n",
+ acpi_ut_get_type_name (obj_type), obj_type);
+ bytes_to_dump = sizeof (union acpi_operand_object);
+ }
+ break;
+
+
+ default:
+
+ acpi_os_printf (
+ "(String or Buffer ptr - not an object descriptor) [%s]\n",
+ acpi_ut_get_descriptor_name (obj_desc));
+ bytes_to_dump = 16;
+ break;
+ }
+
+ ACPI_DUMP_BUFFER (obj_desc, bytes_to_dump);
+
+ /* If value is NOT an internal object, we are done */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) != ACPI_DESC_TYPE_OPERAND) {
+ goto cleanup;
+ }
+
+ /*
+ * Valid object, get the pointer to next level, if any
+ */
+ switch (obj_type) {
+ case ACPI_TYPE_STRING:
+ obj_desc = (void *) obj_desc->string.pointer;
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ obj_desc = (void *) obj_desc->buffer.pointer;
+ break;
+
+ case ACPI_TYPE_BUFFER_FIELD:
+ obj_desc = (union acpi_operand_object *) obj_desc->buffer_field.buffer_obj;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ obj_desc = (void *) obj_desc->package.elements;
+ break;
+
+ case ACPI_TYPE_METHOD:
+ obj_desc = (void *) obj_desc->method.aml_start;
+ break;
+
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+ obj_desc = (void *) obj_desc->field.region_obj;
+ break;
+
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+ obj_desc = (void *) obj_desc->bank_field.region_obj;
+ break;
+
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+ obj_desc = (void *) obj_desc->index_field.index_obj;
+ break;
+
+ default:
+ goto cleanup;
+ }
+
+ obj_type = ACPI_TYPE_INVALID; /* Terminate loop after next pass */
+ }
+
+cleanup:
+ acpi_os_printf ("\n");
+ return (AE_OK);
+}
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_dump_objects
+ *
+ * PARAMETERS: Type - Object type to be dumped
+ * max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX
+ * for an effectively unlimited depth.
+ * owner_id - Dump only objects owned by this ID. Use
+ * ACPI_UINT32_MAX to match all owners.
+ * start_handle - Where in namespace to start/end search
+ *
+ * DESCRIPTION: Dump typed objects within the loaded namespace.
+ * Uses acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_dump_objects (
+ acpi_object_type type,
+ u8 display_type,
+ u32 max_depth,
+ u32 owner_id,
+ acpi_handle start_handle)
+{
+ struct acpi_walk_info info;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ info.debug_level = ACPI_LV_TABLES;
+ info.owner_id = owner_id;
+ info.display_type = display_type;
+
+ (void) acpi_ns_walk_namespace (type, start_handle, max_depth,
+ ACPI_NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object,
+ (void *) &info, NULL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_dump_tables
+ *
+ * PARAMETERS: search_base - Root of subtree to be dumped, or
+ * NS_ALL to dump the entire namespace
+ * max_depth - Maximum depth of dump. Use INT_MAX
+ * for an effectively unlimited depth.
+ *
+ * DESCRIPTION: Dump the name space, or a portion of it.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_dump_tables (
+ acpi_handle search_base,
+ u32 max_depth)
+{
+ acpi_handle search_handle = search_base;
+
+
+ ACPI_FUNCTION_TRACE ("ns_dump_tables");
+
+
+ if (!acpi_gbl_root_node) {
+ /*
+ * If the name space has not been initialized,
+ * there is nothing to dump.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "namespace not initialized!\n"));
+ return_VOID;
+ }
+
+ if (ACPI_NS_ALL == search_base) {
+ /* entire namespace */
+
+ search_handle = acpi_gbl_root_node;
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "\\\n"));
+ }
+
+ acpi_ns_dump_objects (ACPI_TYPE_ANY, ACPI_DISPLAY_OBJECTS, max_depth,
+ ACPI_UINT32_MAX, search_handle);
+ return_VOID;
+}
+
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_dump_entry
+ *
+ * PARAMETERS: Handle - Node to be dumped
+ * debug_level - Output level
+ *
+ * DESCRIPTION: Dump a single Node
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_dump_entry (
+ acpi_handle handle,
+ u32 debug_level)
+{
+ struct acpi_walk_info info;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ info.debug_level = debug_level;
+ info.owner_id = ACPI_UINT32_MAX;
+ info.display_type = ACPI_DISPLAY_SUMMARY;
+
+ (void) acpi_ns_dump_one_object (handle, 1, &info, NULL);
+}
+
+#endif
+
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
new file mode 100644
index 000000000000..d30a59e6b07d
--- /dev/null
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -0,0 +1,146 @@
+/******************************************************************************
+ *
+ * Module Name: nsdump - table dumping routines for debug
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsdumpdv")
+
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_dump_one_device
+ *
+ * PARAMETERS: Handle - Node to be dumped
+ * Level - Nesting level of the handle
+ * Context - Passed into walk_namespace
+ *
+ * DESCRIPTION: Dump a single Node that represents a device
+ * This procedure is a user_function called by acpi_ns_walk_namespace.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_dump_one_device (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ struct acpi_buffer buffer;
+ struct acpi_device_info *info;
+ acpi_status status;
+ u32 i;
+
+
+ ACPI_FUNCTION_NAME ("ns_dump_one_device");
+
+
+ status = acpi_ns_dump_one_object (obj_handle, level, context, return_value);
+
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+ status = acpi_get_object_info (obj_handle, &buffer);
+ if (ACPI_SUCCESS (status)) {
+ info = buffer.pointer;
+ for (i = 0; i < level; i++) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES, " "));
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_TABLES,
+ " HID: %s, ADR: %8.8X%8.8X, Status: %X\n",
+ info->hardware_id.value, ACPI_FORMAT_UINT64 (info->address),
+ info->current_status));
+ ACPI_MEM_FREE (info);
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_dump_root_devices
+ *
+ * PARAMETERS: None
+ *
+ * DESCRIPTION: Dump all objects of type "device"
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_dump_root_devices (void)
+{
+ acpi_handle sys_bus_handle;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_NAME ("ns_dump_root_devices");
+
+
+ /* Only dump the table if tracing is enabled */
+
+ if (!(ACPI_LV_TABLES & acpi_dbg_level)) {
+ return;
+ }
+
+ status = acpi_get_handle(NULL, ACPI_NS_SYSTEM_BUS, &sys_bus_handle);
+ if (ACPI_FAILURE (status)) {
+ return;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES,
+ "Display of all devices in the namespace:\n"));
+
+ status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE, sys_bus_handle,
+ ACPI_UINT32_MAX, ACPI_NS_WALK_NO_UNLOCK,
+ acpi_ns_dump_one_device, NULL, NULL);
+}
+
+#endif
+
+
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
new file mode 100644
index 000000000000..0d008d53657e
--- /dev/null
+++ b/drivers/acpi/namespace/nseval.c
@@ -0,0 +1,487 @@
+/*******************************************************************************
+ *
+ * Module Name: nseval - Object evaluation interfaces -- includes control
+ * method lookup and execution.
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nseval")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_evaluate_relative
+ *
+ * PARAMETERS: Pathname - Name of method to execute, If NULL, the
+ * handle is the object to execute
+ * Info - Method info block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find and execute the requested method using the handle as a
+ * scope
+ *
+ * MUTEX: Locks Namespace
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_evaluate_relative (
+ char *pathname,
+ struct acpi_parameter_info *info)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node = NULL;
+ union acpi_generic_state *scope_info;
+ char *internal_path = NULL;
+
+
+ ACPI_FUNCTION_TRACE ("ns_evaluate_relative");
+
+
+ /*
+ * Must have a valid object handle
+ */
+ if (!info || !info->node) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Build an internal name string for the method */
+
+ status = acpi_ns_internalize_name (pathname, &internal_path);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ scope_info = acpi_ut_create_generic_state ();
+ if (!scope_info) {
+ goto cleanup1;
+ }
+
+ /* Get the prefix handle and Node */
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ info->node = acpi_ns_map_handle_to_node (info->node);
+ if (!info->node) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ status = AE_BAD_PARAMETER;
+ goto cleanup;
+ }
+
+ /* Lookup the name in the namespace */
+
+ scope_info->scope.node = info->node;
+ status = acpi_ns_lookup (scope_info, internal_path, ACPI_TYPE_ANY,
+ ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
+ &node);
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Object [%s] not found [%s]\n",
+ pathname, acpi_format_exception (status)));
+ goto cleanup;
+ }
+
+ /*
+ * Now that we have a handle to the object, we can attempt to evaluate it.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
+ pathname, node, acpi_ns_get_attached_object (node)));
+
+ info->node = node;
+ status = acpi_ns_evaluate_by_handle (info);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n",
+ pathname));
+
+cleanup:
+ acpi_ut_delete_generic_state (scope_info);
+
+cleanup1:
+ ACPI_MEM_FREE (internal_path);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_evaluate_by_name
+ *
+ * PARAMETERS: Pathname - Fully qualified pathname to the object
+ * Info - Contains:
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ * Params - List of parameters to pass to the method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find and execute the requested method passing the given
+ * parameters
+ *
+ * MUTEX: Locks Namespace
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_evaluate_by_name (
+ char *pathname,
+ struct acpi_parameter_info *info)
+{
+ acpi_status status;
+ char *internal_path = NULL;
+
+
+ ACPI_FUNCTION_TRACE ("ns_evaluate_by_name");
+
+
+ /* Build an internal name string for the method */
+
+ status = acpi_ns_internalize_name (pathname, &internal_path);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Lookup the name in the namespace */
+
+ status = acpi_ns_lookup (NULL, internal_path, ACPI_TYPE_ANY,
+ ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, NULL,
+ &info->node);
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Object at [%s] was not found, status=%.4X\n",
+ pathname, status));
+ goto cleanup;
+ }
+
+ /*
+ * Now that we have a handle to the object, we can attempt to evaluate it.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "%s [%p] Value %p\n",
+ pathname, info->node, acpi_ns_get_attached_object (info->node)));
+
+ status = acpi_ns_evaluate_by_handle (info);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "*** Completed eval of object %s ***\n",
+ pathname));
+
+
+cleanup:
+
+ /* Cleanup */
+
+ if (internal_path) {
+ ACPI_MEM_FREE (internal_path);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_evaluate_by_handle
+ *
+ * PARAMETERS: Handle - Method Node to execute
+ * Params - List of parameters to pass to the method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ * param_type - Type of Parameter list
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute the requested method passing the given parameters
+ *
+ * MUTEX: Locks Namespace
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_evaluate_by_handle (
+ struct acpi_parameter_info *info)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ns_evaluate_by_handle");
+
+
+ /* Check if namespace has been initialized */
+
+ if (!acpi_gbl_root_node) {
+ return_ACPI_STATUS (AE_NO_NAMESPACE);
+ }
+
+ /* Parameter Validation */
+
+ if (!info) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Initialize the return value to an invalid object */
+
+ info->return_object = NULL;
+
+ /* Get the prefix handle and Node */
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ info->node = acpi_ns_map_handle_to_node (info->node);
+ if (!info->node) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * For a method alias, we must grab the actual method node so that proper
+ * scoping context will be established before execution.
+ */
+ if (acpi_ns_get_type (info->node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+ info->node = ACPI_CAST_PTR (struct acpi_namespace_node, info->node->object);
+ }
+
+ /*
+ * Two major cases here:
+ * 1) The object is an actual control method -- execute it.
+ * 2) The object is not a method -- just return it's current value
+ *
+ * In both cases, the namespace is unlocked by the acpi_ns* procedure
+ */
+ if (acpi_ns_get_type (info->node) == ACPI_TYPE_METHOD) {
+ /*
+ * Case 1) We have an actual control method to execute
+ */
+ status = acpi_ns_execute_control_method (info);
+ }
+ else {
+ /*
+ * Case 2) Object is NOT a method, just return its current value
+ */
+ status = acpi_ns_get_object_value (info);
+ }
+
+ /*
+ * Check if there is a return value on the stack that must be dealt with
+ */
+ if (status == AE_CTRL_RETURN_VALUE) {
+ /* Map AE_CTRL_RETURN_VALUE to AE_OK, we are done with it */
+
+ status = AE_OK;
+ }
+
+ /*
+ * Namespace was unlocked by the handling acpi_ns* function, so we
+ * just return
+ */
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_execute_control_method
+ *
+ * PARAMETERS: Info - Method info block (w/params)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute the requested method passing the given parameters
+ *
+ * MUTEX: Assumes namespace is locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_execute_control_method (
+ struct acpi_parameter_info *info)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE ("ns_execute_control_method");
+
+
+ /* Verify that there is a method associated with this object */
+
+ obj_desc = acpi_ns_get_attached_object (info->node);
+ if (!obj_desc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No attached method object\n"));
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (AE_NULL_OBJECT);
+ }
+
+ ACPI_DUMP_PATHNAME (info->node, "Execute Method:",
+ ACPI_LV_INFO, _COMPONENT);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Method at AML address %p Length %X\n",
+ obj_desc->method.aml_start + 1, obj_desc->method.aml_length - 1));
+
+ /*
+ * Unlock the namespace before execution. This allows namespace access
+ * via the external Acpi* interfaces while a method is being executed.
+ * However, any namespace deletion must acquire both the namespace and
+ * interpreter locks to ensure that no thread is using the portion of the
+ * namespace that is being deleted.
+ */
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Execute the method via the interpreter. The interpreter is locked
+ * here before calling into the AML parser
+ */
+ status = acpi_ex_enter_interpreter ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_psx_execute (info);
+ acpi_ex_exit_interpreter ();
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_object_value
+ *
+ * PARAMETERS: Info - Method info block (w/params)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return the current value of the object
+ *
+ * MUTEX: Assumes namespace is locked, leaves namespace unlocked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_get_object_value (
+ struct acpi_parameter_info *info)
+{
+ acpi_status status = AE_OK;
+ struct acpi_namespace_node *resolved_node = info->node;
+
+
+ ACPI_FUNCTION_TRACE ("ns_get_object_value");
+
+
+ /*
+ * Objects require additional resolution steps (e.g., the Node may be a
+ * field that must be read, etc.) -- we can't just grab the object out of
+ * the node.
+ */
+
+ /*
+ * Use resolve_node_to_value() to get the associated value. This call always
+ * deletes obj_desc (allocated above).
+ *
+ * NOTE: we can get away with passing in NULL for a walk state because
+ * obj_desc is guaranteed to not be a reference to either a method local or
+ * a method argument (because this interface can only be called from the
+ * acpi_evaluate external interface, never called from a running method.)
+ *
+ * Even though we do not directly invoke the interpreter for this, we must
+ * enter it because we could access an opregion. The opregion access code
+ * assumes that the interpreter is locked.
+ *
+ * We must release the namespace lock before entering the intepreter.
+ */
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ex_enter_interpreter ();
+ if (ACPI_SUCCESS (status)) {
+ status = acpi_ex_resolve_node_to_value (&resolved_node, NULL);
+ /*
+ * If acpi_ex_resolve_node_to_value() succeeded, the return value was placed
+ * in resolved_node.
+ */
+ acpi_ex_exit_interpreter ();
+
+ if (ACPI_SUCCESS (status)) {
+ status = AE_CTRL_RETURN_VALUE;
+ info->return_object = ACPI_CAST_PTR
+ (union acpi_operand_object, resolved_node);
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Returning object %p [%s]\n",
+ info->return_object,
+ acpi_ut_get_object_type_name (info->return_object)));
+ }
+ }
+
+ /* Namespace is unlocked */
+
+ return_ACPI_STATUS (status);
+}
+
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
new file mode 100644
index 000000000000..4a46b380605b
--- /dev/null
+++ b/drivers/acpi/namespace/nsinit.c
@@ -0,0 +1,441 @@
+/******************************************************************************
+ *
+ * Module Name: nsinit - namespace initialization
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsinit")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_initialize_objects
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk the entire namespace and perform any necessary
+ * initialization on the objects found therein
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_initialize_objects (
+ void)
+{
+ acpi_status status;
+ struct acpi_init_walk_info info;
+
+
+ ACPI_FUNCTION_TRACE ("ns_initialize_objects");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "**** Starting initialization of namespace objects ****\n"));
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+ "Completing Region/Field/Buffer/Package initialization:"));
+
+ /* Set all init info to zero */
+
+ ACPI_MEMSET (&info, 0, sizeof (struct acpi_init_walk_info));
+
+ /* Walk entire namespace from the supplied root */
+
+ status = acpi_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, acpi_ns_init_one_object,
+ &info, NULL);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n",
+ acpi_format_exception (status)));
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+ "\nInitialized %hd/%hd Regions %hd/%hd Fields %hd/%hd Buffers %hd/%hd Packages (%hd nodes)\n",
+ info.op_region_init, info.op_region_count,
+ info.field_init, info.field_count,
+ info.buffer_init, info.buffer_count,
+ info.package_init, info.package_count, info.object_count));
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "%hd Control Methods found\n", info.method_count));
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "%hd Op Regions found\n", info.op_region_count));
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_initialize_devices
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: acpi_status
+ *
+ * DESCRIPTION: Walk the entire namespace and initialize all ACPI devices.
+ * This means running _INI on all present devices.
+ *
+ * Note: We install PCI config space handler on region access,
+ * not here.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_initialize_devices (
+ void)
+{
+ acpi_status status;
+ struct acpi_device_walk_info info;
+
+
+ ACPI_FUNCTION_TRACE ("ns_initialize_devices");
+
+
+ /* Init counters */
+
+ info.device_count = 0;
+ info.num_STA = 0;
+ info.num_INI = 0;
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+ "Executing all Device _STA and_INI methods:"));
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Walk namespace for all objects */
+
+ status = acpi_ns_walk_namespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, TRUE, acpi_ns_init_one_device, &info, NULL);
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "walk_namespace failed! %s\n",
+ acpi_format_exception (status)));
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+ "\n%hd Devices found containing: %hd _STA, %hd _INI methods\n",
+ info.device_count, info.num_STA, info.num_INI));
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_init_one_object
+ *
+ * PARAMETERS: obj_handle - Node
+ * Level - Current nesting level
+ * Context - Points to a init info struct
+ * return_value - Not used
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Callback from acpi_walk_namespace. Invoked for every object
+ * within the namespace.
+ *
+ * Currently, the only objects that require initialization are:
+ * 1) Methods
+ * 2) Op Regions
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_init_one_object (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value)
+{
+ acpi_object_type type;
+ acpi_status status;
+ struct acpi_init_walk_info *info = (struct acpi_init_walk_info *) context;
+ struct acpi_namespace_node *node = (struct acpi_namespace_node *) obj_handle;
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_NAME ("ns_init_one_object");
+
+
+ info->object_count++;
+
+ /* And even then, we are only interested in a few object types */
+
+ type = acpi_ns_get_type (obj_handle);
+ obj_desc = acpi_ns_get_attached_object (node);
+ if (!obj_desc) {
+ return (AE_OK);
+ }
+
+ /* Increment counters for object types we are looking for */
+
+ switch (type) {
+ case ACPI_TYPE_REGION:
+ info->op_region_count++;
+ break;
+
+ case ACPI_TYPE_BUFFER_FIELD:
+ info->field_count++;
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ info->buffer_count++;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ info->package_count++;
+ break;
+
+ default:
+
+ /* No init required, just exit now */
+ return (AE_OK);
+ }
+
+ /*
+ * If the object is already initialized, nothing else to do
+ */
+ if (obj_desc->common.flags & AOPOBJ_DATA_VALID) {
+ return (AE_OK);
+ }
+
+ /*
+ * Must lock the interpreter before executing AML code
+ */
+ status = acpi_ex_enter_interpreter ();
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /*
+ * Each of these types can contain executable AML code within the
+ * declaration.
+ */
+ switch (type) {
+ case ACPI_TYPE_REGION:
+
+ info->op_region_init++;
+ status = acpi_ds_get_region_arguments (obj_desc);
+ break;
+
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ info->field_init++;
+ status = acpi_ds_get_buffer_field_arguments (obj_desc);
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ info->buffer_init++;
+ status = acpi_ds_get_buffer_arguments (obj_desc);
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+
+ info->package_init++;
+ status = acpi_ds_get_package_arguments (obj_desc);
+ break;
+
+ default:
+ /* No other types can get here */
+ break;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR, "\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not execute arguments for [%4.4s] (%s), %s\n",
+ acpi_ut_get_node_name (node), acpi_ut_get_type_name (type),
+ acpi_format_exception (status)));
+ }
+
+ /*
+ * Print a dot for each object unless we are going to print the entire
+ * pathname
+ */
+ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
+ }
+
+ /*
+ * We ignore errors from above, and always return OK, since we don't want
+ * to abort the walk on any single error.
+ */
+ acpi_ex_exit_interpreter ();
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_init_one_device
+ *
+ * PARAMETERS: acpi_walk_callback
+ *
+ * RETURN: acpi_status
+ *
+ * DESCRIPTION: This is called once per device soon after ACPI is enabled
+ * to initialize each device. It determines if the device is
+ * present, and if so, calls _INI.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_init_one_device (
+ acpi_handle obj_handle,
+ u32 nesting_level,
+ void *context,
+ void **return_value)
+{
+ struct acpi_device_walk_info *info = (struct acpi_device_walk_info *) context;
+ struct acpi_parameter_info pinfo;
+ u32 flags;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ns_init_one_device");
+
+
+ pinfo.parameters = NULL;
+ pinfo.parameter_type = ACPI_PARAM_ARGS;
+
+ pinfo.node = acpi_ns_map_handle_to_node (obj_handle);
+ if (!pinfo.node) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We will run _STA/_INI on Devices, Processors and thermal_zones only
+ */
+ if ((pinfo.node->type != ACPI_TYPE_DEVICE) &&
+ (pinfo.node->type != ACPI_TYPE_PROCESSOR) &&
+ (pinfo.node->type != ACPI_TYPE_THERMAL)) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ if ((acpi_dbg_level <= ACPI_LV_ALL_EXCEPTIONS) &&
+ (!(acpi_dbg_level & ACPI_LV_INFO))) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
+ }
+
+ info->device_count++;
+
+ /*
+ * Run _STA to determine if we can run _INI on the device.
+ */
+ ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_STA"));
+ status = acpi_ut_execute_STA (pinfo.node, &flags);
+
+ if (ACPI_FAILURE (status)) {
+ if (pinfo.node->type == ACPI_TYPE_DEVICE) {
+ /* Ignore error and move on to next device */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* _STA is not required for Processor or thermal_zone objects */
+ }
+ else {
+ info->num_STA++;
+
+ if (!(flags & 0x01)) {
+ /* Don't look at children of a not present device */
+
+ return_ACPI_STATUS(AE_CTRL_DEPTH);
+ }
+ }
+
+ /*
+ * The device is present. Run _INI.
+ */
+ ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI"));
+ status = acpi_ns_evaluate_relative ("_INI", &pinfo);
+ if (ACPI_FAILURE (status)) {
+ /* No _INI (AE_NOT_FOUND) means device requires no initialization */
+
+ if (status != AE_NOT_FOUND) {
+ /* Ignore error and move on to next device */
+
+#ifdef ACPI_DEBUG_OUTPUT
+ char *scope_name = acpi_ns_get_external_pathname (pinfo.node);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "%s._INI failed: %s\n",
+ scope_name, acpi_format_exception (status)));
+
+ ACPI_MEM_FREE (scope_name);
+#endif
+ }
+
+ status = AE_OK;
+ }
+ else {
+ /* Delete any return object (especially if implicit_return is enabled) */
+
+ if (pinfo.return_object) {
+ acpi_ut_remove_reference (pinfo.return_object);
+ }
+
+ /* Count of successful INIs */
+
+ info->num_INI++;
+ }
+
+ if (acpi_gbl_init_handler) {
+ /* External initialization handler is present, call it */
+
+ status = acpi_gbl_init_handler (pinfo.node, ACPI_INIT_DEVICE_INI);
+ }
+
+ return_ACPI_STATUS (status);
+}
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
new file mode 100644
index 000000000000..1d7aedf68a77
--- /dev/null
+++ b/drivers/acpi/namespace/nsload.c
@@ -0,0 +1,460 @@
+/******************************************************************************
+ *
+ * Module Name: nsload - namespace loading/expanding/contracting procedures
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acdispat.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsload")
+
+
+#ifndef ACPI_NO_METHOD_EXECUTION
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_load_table
+ *
+ * PARAMETERS: table_desc - Descriptor for table to be loaded
+ * Node - Owning NS node
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load one ACPI table into the namespace
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_load_table (
+ struct acpi_table_desc *table_desc,
+ struct acpi_namespace_node *node)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ns_load_table");
+
+
+ /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
+
+ if (!(acpi_gbl_table_data[table_desc->type].flags & ACPI_TABLE_EXECUTABLE)) {
+ /* Just ignore this table */
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Check validity of the AML start and length */
+
+ if (!table_desc->aml_start) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null AML pointer\n"));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "AML block at %p\n",
+ table_desc->aml_start));
+
+ /* Ignore table if there is no AML contained within */
+
+ if (!table_desc->aml_length) {
+ ACPI_REPORT_WARNING (("Zero-length AML block in table [%4.4s]\n",
+ table_desc->pointer->signature));
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Parse the table and load the namespace with all named
+ * objects found within. Control methods are NOT parsed
+ * at this time. In fact, the control methods cannot be
+ * parsed until the entire namespace is loaded, because
+ * if a control method makes a forward reference (call)
+ * to another control method, we can't continue parsing
+ * because we don't know how many arguments to parse next!
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "**** Loading table into namespace ****\n"));
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ns_parse_table (table_desc, node->child);
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Now we can parse the control methods. We always parse
+ * them here for a sanity check, and if configured for
+ * just-in-time parsing, we delete the control method
+ * parse trees.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "**** Begin Table Method Parsing and Object Initialization ****\n"));
+
+ status = acpi_ds_initialize_objects (table_desc, node);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "**** Completed Table Method Parsing and Object Initialization ****\n"));
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_load_table_by_type
+ *
+ * PARAMETERS: table_type - Id of the table type to load
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load an ACPI table or tables into the namespace. All tables
+ * of the given type are loaded. The mechanism allows this
+ * routine to be called repeatedly.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_load_table_by_type (
+ acpi_table_type table_type)
+{
+ u32 i;
+ acpi_status status;
+ struct acpi_table_desc *table_desc;
+
+
+ ACPI_FUNCTION_TRACE ("ns_load_table_by_type");
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Table types supported are:
+ * DSDT (one), SSDT/PSDT (multiple)
+ */
+ switch (table_type) {
+ case ACPI_TABLE_DSDT:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading DSDT\n"));
+
+ table_desc = acpi_gbl_table_lists[ACPI_TABLE_DSDT].next;
+
+ /* If table already loaded into namespace, just return */
+
+ if (table_desc->loaded_into_namespace) {
+ goto unlock_and_exit;
+ }
+
+ /* Now load the single DSDT */
+
+ status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
+ if (ACPI_SUCCESS (status)) {
+ table_desc->loaded_into_namespace = TRUE;
+ }
+ break;
+
+
+ case ACPI_TABLE_SSDT:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading %d SSDTs\n",
+ acpi_gbl_table_lists[ACPI_TABLE_SSDT].count));
+
+ /*
+ * Traverse list of SSDT tables
+ */
+ table_desc = acpi_gbl_table_lists[ACPI_TABLE_SSDT].next;
+ for (i = 0; i < acpi_gbl_table_lists[ACPI_TABLE_SSDT].count; i++) {
+ /*
+ * Only attempt to load table if it is not
+ * already loaded!
+ */
+ if (!table_desc->loaded_into_namespace) {
+ status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ table_desc->loaded_into_namespace = TRUE;
+ }
+
+ table_desc = table_desc->next;
+ }
+ break;
+
+
+ case ACPI_TABLE_PSDT:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Loading %d PSDTs\n",
+ acpi_gbl_table_lists[ACPI_TABLE_PSDT].count));
+
+ /*
+ * Traverse list of PSDT tables
+ */
+ table_desc = acpi_gbl_table_lists[ACPI_TABLE_PSDT].next;
+
+ for (i = 0; i < acpi_gbl_table_lists[ACPI_TABLE_PSDT].count; i++) {
+ /* Only attempt to load table if it is not already loaded! */
+
+ if (!table_desc->loaded_into_namespace) {
+ status = acpi_ns_load_table (table_desc, acpi_gbl_root_node);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+
+ table_desc->loaded_into_namespace = TRUE;
+ }
+
+ table_desc = table_desc->next;
+ }
+ break;
+
+
+ default:
+ status = AE_SUPPORT;
+ break;
+ }
+
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_TABLES);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_load_namespace
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load the name space from what ever is pointed to by DSDT.
+ * (DSDT points to either the BIOS or a buffer.)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_load_namespace (
+ void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_load_name_space");
+
+
+ /* There must be at least a DSDT installed */
+
+ if (acpi_gbl_DSDT == NULL) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "DSDT is not in memory\n"));
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ /*
+ * Load the namespace. The DSDT is required,
+ * but the SSDT and PSDT tables are optional.
+ */
+ status = acpi_ns_load_table_by_type (ACPI_TABLE_DSDT);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Ignore exceptions from these */
+
+ (void) acpi_ns_load_table_by_type (ACPI_TABLE_SSDT);
+ (void) acpi_ns_load_table_by_type (ACPI_TABLE_PSDT);
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT,
+ "ACPI Namespace successfully loaded at root %p\n",
+ acpi_gbl_root_node));
+
+ return_ACPI_STATUS (status);
+}
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_delete_subtree
+ *
+ * PARAMETERS: start_handle - Handle in namespace where search begins
+ *
+ * RETURNS Status
+ *
+ * DESCRIPTION: Walks the namespace starting at the given handle and deletes
+ * all objects, entries, and scopes in the entire subtree.
+ *
+ * Namespace/Interpreter should be locked or the subsystem should
+ * be in shutdown before this routine is called.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_delete_subtree (
+ acpi_handle start_handle)
+{
+ acpi_status status;
+ acpi_handle child_handle;
+ acpi_handle parent_handle;
+ acpi_handle next_child_handle;
+ acpi_handle dummy;
+ u32 level;
+
+
+ ACPI_FUNCTION_TRACE ("ns_delete_subtree");
+
+
+ parent_handle = start_handle;
+ child_handle = NULL;
+ level = 1;
+
+ /*
+ * Traverse the tree of objects until we bubble back up
+ * to where we started.
+ */
+ while (level > 0) {
+ /* Attempt to get the next object in this scope */
+
+ status = acpi_get_next_object (ACPI_TYPE_ANY, parent_handle,
+ child_handle, &next_child_handle);
+
+ child_handle = next_child_handle;
+
+ /* Did we get a new object? */
+
+ if (ACPI_SUCCESS (status)) {
+ /* Check if this object has any children */
+
+ if (ACPI_SUCCESS (acpi_get_next_object (ACPI_TYPE_ANY, child_handle,
+ NULL, &dummy))) {
+ /*
+ * There is at least one child of this object,
+ * visit the object
+ */
+ level++;
+ parent_handle = child_handle;
+ child_handle = NULL;
+ }
+ }
+ else {
+ /*
+ * No more children in this object, go back up to
+ * the object's parent
+ */
+ level--;
+
+ /* Delete all children now */
+
+ acpi_ns_delete_children (child_handle);
+
+ child_handle = parent_handle;
+ status = acpi_get_parent (parent_handle, &parent_handle);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ }
+
+ /* Now delete the starting object, and we are done */
+
+ acpi_ns_delete_node (child_handle);
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_unload_name_space
+ *
+ * PARAMETERS: Handle - Root of namespace subtree to be deleted
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Shrinks the namespace, typically in response to an undocking
+ * event. Deletes an entire subtree starting from (and
+ * including) the given handle.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_unload_namespace (
+ acpi_handle handle)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ns_unload_name_space");
+
+
+ /* Parameter validation */
+
+ if (!acpi_gbl_root_node) {
+ return_ACPI_STATUS (AE_NO_NAMESPACE);
+ }
+
+ if (!handle) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* This function does the real work */
+
+ status = acpi_ns_delete_subtree (handle);
+
+ return_ACPI_STATUS (status);
+}
+
+#endif /* ACPI_FUTURE_USAGE */
+
+#endif
+
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
new file mode 100644
index 000000000000..b6f8f910eff0
--- /dev/null
+++ b/drivers/acpi/namespace/nsnames.c
@@ -0,0 +1,265 @@
+/*******************************************************************************
+ *
+ * Module Name: nsnames - Name manipulation and search
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsnames")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_build_external_path
+ *
+ * PARAMETERS: Node - NS node whose pathname is needed
+ * Size - Size of the pathname
+ * *name_buffer - Where to return the pathname
+ *
+ * RETURN: Places the pathname into the name_buffer, in external format
+ * (name segments separated by path separators)
+ *
+ * DESCRIPTION: Generate a full pathaname
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_build_external_path (
+ struct acpi_namespace_node *node,
+ acpi_size size,
+ char *name_buffer)
+{
+ acpi_size index;
+ struct acpi_namespace_node *parent_node;
+
+
+ ACPI_FUNCTION_NAME ("ns_build_external_path");
+
+
+ /* Special case for root */
+
+ index = size - 1;
+ if (index < ACPI_NAME_SIZE) {
+ name_buffer[0] = AML_ROOT_PREFIX;
+ name_buffer[1] = 0;
+ return;
+ }
+
+ /* Store terminator byte, then build name backwards */
+
+ parent_node = node;
+ name_buffer[index] = 0;
+
+ while ((index > ACPI_NAME_SIZE) && (parent_node != acpi_gbl_root_node)) {
+ index -= ACPI_NAME_SIZE;
+
+ /* Put the name into the buffer */
+
+ ACPI_MOVE_32_TO_32 ((name_buffer + index), &parent_node->name);
+ parent_node = acpi_ns_get_parent_node (parent_node);
+
+ /* Prefix name with the path separator */
+
+ index--;
+ name_buffer[index] = ACPI_PATH_SEPARATOR;
+ }
+
+ /* Overwrite final separator with the root prefix character */
+
+ name_buffer[index] = AML_ROOT_PREFIX;
+
+ if (index != 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not construct pathname; index=%X, size=%X, Path=%s\n",
+ (u32) index, (u32) size, &name_buffer[size]));
+ }
+
+ return;
+}
+
+
+#ifdef ACPI_DEBUG_OUTPUT
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_external_pathname
+ *
+ * PARAMETERS: Node - NS node whose pathname is needed
+ *
+ * RETURN: Pointer to storage containing the fully qualified name of
+ * the node, In external format (name segments separated by path
+ * separators.)
+ *
+ * DESCRIPTION: Used for debug printing in acpi_ns_search_table().
+ *
+ ******************************************************************************/
+
+char *
+acpi_ns_get_external_pathname (
+ struct acpi_namespace_node *node)
+{
+ char *name_buffer;
+ acpi_size size;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ns_get_external_pathname", node);
+
+
+ /* Calculate required buffer size based on depth below root */
+
+ size = acpi_ns_get_pathname_length (node);
+
+ /* Allocate a buffer to be returned to caller */
+
+ name_buffer = ACPI_MEM_CALLOCATE (size);
+ if (!name_buffer) {
+ ACPI_REPORT_ERROR (("ns_get_table_pathname: allocation failure\n"));
+ return_PTR (NULL);
+ }
+
+ /* Build the path in the allocated buffer */
+
+ acpi_ns_build_external_path (node, size, name_buffer);
+ return_PTR (name_buffer);
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_pathname_length
+ *
+ * PARAMETERS: Node - Namespace node
+ *
+ * RETURN: Length of path, including prefix
+ *
+ * DESCRIPTION: Get the length of the pathname string for this node
+ *
+ ******************************************************************************/
+
+acpi_size
+acpi_ns_get_pathname_length (
+ struct acpi_namespace_node *node)
+{
+ acpi_size size;
+ struct acpi_namespace_node *next_node;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * Compute length of pathname as 5 * number of name segments.
+ * Go back up the parent tree to the root
+ */
+ size = 0;
+ next_node = node;
+
+ while (next_node && (next_node != acpi_gbl_root_node)) {
+ size += ACPI_PATH_SEGMENT_LENGTH;
+ next_node = acpi_ns_get_parent_node (next_node);
+ }
+
+ if (!size) {
+ size = 1; /* Root node case */
+ }
+
+ return (size + 1); /* +1 for null string terminator */
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_handle_to_pathname
+ *
+ * PARAMETERS: target_handle - Handle of named object whose name is
+ * to be found
+ * Buffer - Where the pathname is returned
+ *
+ * RETURN: Status, Buffer is filled with pathname if status is AE_OK
+ *
+ * DESCRIPTION: Build and return a full namespace pathname
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_handle_to_pathname (
+ acpi_handle target_handle,
+ struct acpi_buffer *buffer)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ acpi_size required_size;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ns_handle_to_pathname", target_handle);
+
+
+ node = acpi_ns_map_handle_to_node (target_handle);
+ if (!node) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Determine size required for the caller buffer */
+
+ required_size = acpi_ns_get_pathname_length (node);
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (buffer, required_size);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Build the path in the caller buffer */
+
+ acpi_ns_build_external_path (node, required_size, buffer->pointer);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%s [%X] \n",
+ (char *) buffer->pointer, (u32) required_size));
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
new file mode 100644
index 000000000000..4e41e66db61f
--- /dev/null
+++ b/drivers/acpi/namespace/nsobject.c
@@ -0,0 +1,461 @@
+/*******************************************************************************
+ *
+ * Module Name: nsobject - Utilities for objects attached to namespace
+ * table entries
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsobject")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_attach_object
+ *
+ * PARAMETERS: Node - Parent Node
+ * Object - Object to be attached
+ * Type - Type of object, or ACPI_TYPE_ANY if not
+ * known
+ *
+ * DESCRIPTION: Record the given object as the value associated with the
+ * name whose acpi_handle is passed. If Object is NULL
+ * and Type is ACPI_TYPE_ANY, set the name as having no value.
+ * Note: Future may require that the Node->Flags field be passed
+ * as a parameter.
+ *
+ * MUTEX: Assumes namespace is locked
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_attach_object (
+ struct acpi_namespace_node *node,
+ union acpi_operand_object *object,
+ acpi_object_type type)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *last_obj_desc;
+ acpi_object_type object_type = ACPI_TYPE_ANY;
+
+
+ ACPI_FUNCTION_TRACE ("ns_attach_object");
+
+
+ /*
+ * Parameter validation
+ */
+ if (!node) {
+ /* Invalid handle */
+
+ ACPI_REPORT_ERROR (("ns_attach_object: Null named_obj handle\n"));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (!object && (ACPI_TYPE_ANY != type)) {
+ /* Null object */
+
+ ACPI_REPORT_ERROR (("ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n"));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
+ /* Not a name handle */
+
+ ACPI_REPORT_ERROR (("ns_attach_object: Invalid handle %p [%s]\n",
+ node, acpi_ut_get_descriptor_name (node)));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Check if this object is already attached */
+
+ if (node->object == object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj %p already installed in name_obj %p\n",
+ object, node));
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* If null object, we will just install it */
+
+ if (!object) {
+ obj_desc = NULL;
+ object_type = ACPI_TYPE_ANY;
+ }
+
+ /*
+ * If the source object is a namespace Node with an attached object,
+ * we will use that (attached) object
+ */
+ else if ((ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) &&
+ ((struct acpi_namespace_node *) object)->object) {
+ /*
+ * Value passed is a name handle and that name has a
+ * non-null value. Use that name's value and type.
+ */
+ obj_desc = ((struct acpi_namespace_node *) object)->object;
+ object_type = ((struct acpi_namespace_node *) object)->type;
+ }
+
+ /*
+ * Otherwise, we will use the parameter object, but we must type
+ * it first
+ */
+ else {
+ obj_desc = (union acpi_operand_object *) object;
+
+ /* Use the given type */
+
+ object_type = type;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Installing %p into Node %p [%4.4s]\n",
+ obj_desc, node, acpi_ut_get_node_name (node)));
+
+ /* Detach an existing attached object if present */
+
+ if (node->object) {
+ acpi_ns_detach_object (node);
+ }
+
+ if (obj_desc) {
+ /*
+ * Must increment the new value's reference count
+ * (if it is an internal object)
+ */
+ acpi_ut_add_reference (obj_desc);
+
+ /*
+ * Handle objects with multiple descriptors - walk
+ * to the end of the descriptor list
+ */
+ last_obj_desc = obj_desc;
+ while (last_obj_desc->common.next_object) {
+ last_obj_desc = last_obj_desc->common.next_object;
+ }
+
+ /* Install the object at the front of the object list */
+
+ last_obj_desc->common.next_object = node->object;
+ }
+
+ node->type = (u8) object_type;
+ node->object = obj_desc;
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_detach_object
+ *
+ * PARAMETERS: Node - An node whose object will be detached
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Detach/delete an object associated with a namespace node.
+ * if the object is an allocated object, it is freed.
+ * Otherwise, the field is simply cleared.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_detach_object (
+ struct acpi_namespace_node *node)
+{
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE ("ns_detach_object");
+
+
+ obj_desc = node->object;
+
+ if (!obj_desc ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA)) {
+ return_VOID;
+ }
+
+ /* Clear the entry in all cases */
+
+ node->object = NULL;
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) {
+ node->object = obj_desc->common.next_object;
+ if (node->object &&
+ (ACPI_GET_OBJECT_TYPE (node->object) != ACPI_TYPE_LOCAL_DATA)) {
+ node->object = node->object->common.next_object;
+ }
+ }
+
+ /* Reset the node type to untyped */
+
+ node->type = ACPI_TYPE_ANY;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "Node %p [%4.4s] Object %p\n",
+ node, acpi_ut_get_node_name (node), obj_desc));
+
+ /* Remove one reference on the object (and all subobjects) */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_attached_object
+ *
+ * PARAMETERS: Node - Parent Node to be examined
+ *
+ * RETURN: Current value of the object field from the Node whose
+ * handle is passed
+ *
+ * DESCRIPTION: Obtain the object attached to a namespace node.
+ *
+ ******************************************************************************/
+
+union acpi_operand_object *
+acpi_ns_get_attached_object (
+ struct acpi_namespace_node *node)
+{
+ ACPI_FUNCTION_TRACE_PTR ("ns_get_attached_object", node);
+
+
+ if (!node) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Null Node ptr\n"));
+ return_PTR (NULL);
+ }
+
+ if (!node->object ||
+ ((ACPI_GET_DESCRIPTOR_TYPE (node->object) != ACPI_DESC_TYPE_OPERAND) &&
+ (ACPI_GET_DESCRIPTOR_TYPE (node->object) != ACPI_DESC_TYPE_NAMED)) ||
+ (ACPI_GET_OBJECT_TYPE (node->object) == ACPI_TYPE_LOCAL_DATA)) {
+ return_PTR (NULL);
+ }
+
+ return_PTR (node->object);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_secondary_object
+ *
+ * PARAMETERS: Node - Parent Node to be examined
+ *
+ * RETURN: Current value of the object field from the Node whose
+ * handle is passed.
+ *
+ * DESCRIPTION: Obtain a secondary object associated with a namespace node.
+ *
+ ******************************************************************************/
+
+union acpi_operand_object *
+acpi_ns_get_secondary_object (
+ union acpi_operand_object *obj_desc)
+{
+ ACPI_FUNCTION_TRACE_PTR ("ns_get_secondary_object", obj_desc);
+
+
+ if ((!obj_desc) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) ||
+ (!obj_desc->common.next_object) ||
+ (ACPI_GET_OBJECT_TYPE (obj_desc->common.next_object) == ACPI_TYPE_LOCAL_DATA)) {
+ return_PTR (NULL);
+ }
+
+ return_PTR (obj_desc->common.next_object);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_attach_data
+ *
+ * PARAMETERS: Node - Namespace node
+ * Handler - Handler to be associated with the data
+ * Data - Data to be attached
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Low-level attach data. Create and attach a Data object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_attach_data (
+ struct acpi_namespace_node *node,
+ acpi_object_handler handler,
+ void *data)
+{
+ union acpi_operand_object *prev_obj_desc;
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *data_desc;
+
+
+ /* We only allow one attachment per handler */
+
+ prev_obj_desc = NULL;
+ obj_desc = node->object;
+ while (obj_desc) {
+ if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) &&
+ (obj_desc->data.handler == handler)) {
+ return (AE_ALREADY_EXISTS);
+ }
+
+ prev_obj_desc = obj_desc;
+ obj_desc = obj_desc->common.next_object;
+ }
+
+ /* Create an internal object for the data */
+
+ data_desc = acpi_ut_create_internal_object (ACPI_TYPE_LOCAL_DATA);
+ if (!data_desc) {
+ return (AE_NO_MEMORY);
+ }
+
+ data_desc->data.handler = handler;
+ data_desc->data.pointer = data;
+
+ /* Install the data object */
+
+ if (prev_obj_desc) {
+ prev_obj_desc->common.next_object = data_desc;
+ }
+ else {
+ node->object = data_desc;
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_detach_data
+ *
+ * PARAMETERS: Node - Namespace node
+ * Handler - Handler associated with the data
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Low-level detach data. Delete the data node, but the caller
+ * is responsible for the actual data.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_detach_data (
+ struct acpi_namespace_node *node,
+ acpi_object_handler handler)
+{
+ union acpi_operand_object *obj_desc;
+ union acpi_operand_object *prev_obj_desc;
+
+
+ prev_obj_desc = NULL;
+ obj_desc = node->object;
+ while (obj_desc) {
+ if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) &&
+ (obj_desc->data.handler == handler)) {
+ if (prev_obj_desc) {
+ prev_obj_desc->common.next_object = obj_desc->common.next_object;
+ }
+ else {
+ node->object = obj_desc->common.next_object;
+ }
+
+ acpi_ut_remove_reference (obj_desc);
+ return (AE_OK);
+ }
+
+ prev_obj_desc = obj_desc;
+ obj_desc = obj_desc->common.next_object;
+ }
+
+ return (AE_NOT_FOUND);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_attached_data
+ *
+ * PARAMETERS: Node - Namespace node
+ * Handler - Handler associated with the data
+ * Data - Where the data is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Low level interface to obtain data previously associated with
+ * a namespace node.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_get_attached_data (
+ struct acpi_namespace_node *node,
+ acpi_object_handler handler,
+ void **data)
+{
+ union acpi_operand_object *obj_desc;
+
+
+ obj_desc = node->object;
+ while (obj_desc) {
+ if ((ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_LOCAL_DATA) &&
+ (obj_desc->data.handler == handler)) {
+ *data = obj_desc->data.pointer;
+ return (AE_OK);
+ }
+
+ obj_desc = obj_desc->common.next_object;
+ }
+
+ return (AE_NOT_FOUND);
+}
+
+
diff --git a/drivers/acpi/namespace/nsparse.c b/drivers/acpi/namespace/nsparse.c
new file mode 100644
index 000000000000..a0e13e8d3764
--- /dev/null
+++ b/drivers/acpi/namespace/nsparse.c
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ * Module Name: nsparse - namespace interface to AML parser
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/acdispat.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsparse")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: ns_one_complete_parse
+ *
+ * PARAMETERS: pass_number - 1 or 2
+ * table_desc - The table to be parsed.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform one complete parse of an ACPI/AML table.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_one_complete_parse (
+ u32 pass_number,
+ struct acpi_table_desc *table_desc)
+{
+ union acpi_parse_object *parse_root;
+ acpi_status status;
+ struct acpi_walk_state *walk_state;
+
+
+ ACPI_FUNCTION_TRACE ("ns_one_complete_parse");
+
+
+ /* Create and init a Root Node */
+
+ parse_root = acpi_ps_create_scope_op ();
+ if (!parse_root) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Create and initialize a new walk state */
+
+ walk_state = acpi_ds_create_walk_state (table_desc->table_id,
+ NULL, NULL, NULL);
+ if (!walk_state) {
+ acpi_ps_free_op (parse_root);
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ status = acpi_ds_init_aml_walk (walk_state, parse_root, NULL,
+ table_desc->aml_start, table_desc->aml_length,
+ NULL, pass_number);
+ if (ACPI_FAILURE (status)) {
+ acpi_ds_delete_walk_state (walk_state);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Parse the AML */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "*PARSE* pass %d parse\n", pass_number));
+ status = acpi_ps_parse_aml (walk_state);
+
+ acpi_ps_delete_parse_tree (parse_root);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_parse_table
+ *
+ * PARAMETERS: table_desc - An ACPI table descriptor for table to parse
+ * start_node - Where to enter the table into the namespace
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse AML within an ACPI table and return a tree of ops
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_parse_table (
+ struct acpi_table_desc *table_desc,
+ struct acpi_namespace_node *start_node)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ns_parse_table");
+
+
+ /*
+ * AML Parse, pass 1
+ *
+ * In this pass, we load most of the namespace. Control methods
+ * are not parsed until later. A parse tree is not created. Instead,
+ * each Parser Op subtree is deleted when it is finished. This saves
+ * a great deal of memory, and allows a small cache of parse objects
+ * to service the entire parse. The second pass of the parse then
+ * performs another complete parse of the AML..
+ */
+ status = acpi_ns_one_complete_parse (1, table_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * AML Parse, pass 2
+ *
+ * In this pass, we resolve forward references and other things
+ * that could not be completed during the first pass.
+ * Another complete parse of the AML is performed, but the
+ * overhead of this is compensated for by the fact that the
+ * parse objects are all cached.
+ */
+ status = acpi_ns_one_complete_parse (2, table_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
new file mode 100644
index 000000000000..0e6dea23603b
--- /dev/null
+++ b/drivers/acpi/namespace/nssearch.c
@@ -0,0 +1,381 @@
+/*******************************************************************************
+ *
+ * Module Name: nssearch - Namespace search
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nssearch")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_search_node
+ *
+ * PARAMETERS: *target_name - Ascii ACPI name to search for
+ * *Node - Starting node where search will begin
+ * Type - Object type to match
+ * **return_node - Where the matched Named obj is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Search a single level of the namespace. Performs a
+ * simple search of the specified level, and does not add
+ * entries or search parents.
+ *
+ *
+ * Named object lists are built (and subsequently dumped) in the
+ * order in which the names are encountered during the namespace load;
+ *
+ * All namespace searching is linear in this implementation, but
+ * could be easily modified to support any improved search
+ * algorithm. However, the linear search was chosen for simplicity
+ * and because the trees are small and the other interpreter
+ * execution overhead is relatively high.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_search_node (
+ u32 target_name,
+ struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_namespace_node **return_node)
+{
+ struct acpi_namespace_node *next_node;
+
+
+ ACPI_FUNCTION_TRACE ("ns_search_node");
+
+
+#ifdef ACPI_DEBUG_OUTPUT
+ if (ACPI_LV_NAMES & acpi_dbg_level) {
+ char *scope_name;
+
+ scope_name = acpi_ns_get_external_pathname (node);
+ if (scope_name) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Searching %s (%p) For [%4.4s] (%s)\n",
+ scope_name, node, (char *) &target_name,
+ acpi_ut_get_type_name (type)));
+
+ ACPI_MEM_FREE (scope_name);
+ }
+ }
+#endif
+
+ /*
+ * Search for name at this namespace level, which is to say that we
+ * must search for the name among the children of this object
+ */
+ next_node = node->child;
+ while (next_node) {
+ /* Check for match against the name */
+
+ if (next_node->name.integer == target_name) {
+ /* Resolve a control method alias if any */
+
+ if (acpi_ns_get_type (next_node) == ACPI_TYPE_LOCAL_METHOD_ALIAS) {
+ next_node = ACPI_CAST_PTR (struct acpi_namespace_node, next_node->object);
+ }
+
+ /*
+ * Found matching entry.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Name [%4.4s] (%s) %p found in scope [%4.4s] %p\n",
+ (char *) &target_name, acpi_ut_get_type_name (next_node->type),
+ next_node, acpi_ut_get_node_name (node), node));
+
+ *return_node = next_node;
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * The last entry in the list points back to the parent,
+ * so a flag is used to indicate the end-of-list
+ */
+ if (next_node->flags & ANOBJ_END_OF_PEER_LIST) {
+ /* Searched entire list, we are done */
+
+ break;
+ }
+
+ /* Didn't match name, move on to the next peer object */
+
+ next_node = next_node->peer;
+ }
+
+ /* Searched entire namespace level, not found */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Name [%4.4s] (%s) not found in search in scope [%4.4s] %p first child %p\n",
+ (char *) &target_name, acpi_ut_get_type_name (type),
+ acpi_ut_get_node_name (node), node, node->child));
+
+ return_ACPI_STATUS (AE_NOT_FOUND);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_search_parent_tree
+ *
+ * PARAMETERS: *target_name - Ascii ACPI name to search for
+ * *Node - Starting node where search will begin
+ * Type - Object type to match
+ * **return_node - Where the matched Node is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Called when a name has not been found in the current namespace
+ * level. Before adding it or giving up, ACPI scope rules require
+ * searching enclosing scopes in cases identified by acpi_ns_local().
+ *
+ * "A name is located by finding the matching name in the current
+ * name space, and then in the parent name space. If the parent
+ * name space does not contain the name, the search continues
+ * recursively until either the name is found or the name space
+ * does not have a parent (the root of the name space). This
+ * indicates that the name is not found" (From ACPI Specification,
+ * section 5.3)
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_search_parent_tree (
+ u32 target_name,
+ struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_namespace_node **return_node)
+{
+ acpi_status status;
+ struct acpi_namespace_node *parent_node;
+
+
+ ACPI_FUNCTION_TRACE ("ns_search_parent_tree");
+
+
+ parent_node = acpi_ns_get_parent_node (node);
+
+ /*
+ * If there is no parent (i.e., we are at the root) or type is "local",
+ * we won't be searching the parent tree.
+ */
+ if (!parent_node) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES, "[%4.4s] has no parent\n",
+ (char *) &target_name));
+ return_ACPI_STATUS (AE_NOT_FOUND);
+ }
+
+ if (acpi_ns_local (type)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "[%4.4s] type [%s] must be local to this scope (no parent search)\n",
+ (char *) &target_name, acpi_ut_get_type_name (type)));
+ return_ACPI_STATUS (AE_NOT_FOUND);
+ }
+
+ /* Search the parent tree */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "Searching parent [%4.4s] for [%4.4s]\n",
+ acpi_ut_get_node_name (parent_node), (char *) &target_name));
+
+ /*
+ * Search parents until target is found or we have backed up to the root
+ */
+ while (parent_node) {
+ /*
+ * Search parent scope. Use TYPE_ANY because we don't care about the
+ * object type at this point, we only care about the existence of
+ * the actual name we are searching for. Typechecking comes later.
+ */
+ status = acpi_ns_search_node (target_name, parent_node,
+ ACPI_TYPE_ANY, return_node);
+ if (ACPI_SUCCESS (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Not found here, go up another level
+ * (until we reach the root)
+ */
+ parent_node = acpi_ns_get_parent_node (parent_node);
+ }
+
+ /* Not found in parent tree */
+
+ return_ACPI_STATUS (AE_NOT_FOUND);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_search_and_enter
+ *
+ * PARAMETERS: target_name - Ascii ACPI name to search for (4 chars)
+ * walk_state - Current state of the walk
+ * *Node - Starting node where search will begin
+ * interpreter_mode - Add names only in ACPI_MODE_LOAD_PASS_x.
+ * Otherwise,search only.
+ * Type - Object type to match
+ * Flags - Flags describing the search restrictions
+ * **return_node - Where the Node is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Search for a name segment in a single namespace level,
+ * optionally adding it if it is not found. If the passed
+ * Type is not Any and the type previously stored in the
+ * entry was Any (i.e. unknown), update the stored type.
+ *
+ * In ACPI_IMODE_EXECUTE, search only.
+ * In other modes, search and add if not found.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_search_and_enter (
+ u32 target_name,
+ struct acpi_walk_state *walk_state,
+ struct acpi_namespace_node *node,
+ acpi_interpreter_mode interpreter_mode,
+ acpi_object_type type,
+ u32 flags,
+ struct acpi_namespace_node **return_node)
+{
+ acpi_status status;
+ struct acpi_namespace_node *new_node;
+
+
+ ACPI_FUNCTION_TRACE ("ns_search_and_enter");
+
+
+ /* Parameter validation */
+
+ if (!node || !target_name || !return_node) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null param: Node %p Name %X return_node %p\n",
+ node, target_name, return_node));
+
+ ACPI_REPORT_ERROR (("ns_search_and_enter: Null parameter\n"));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Name must consist of printable characters */
+
+ if (!acpi_ut_valid_acpi_name (target_name)) {
+ ACPI_REPORT_ERROR (("ns_search_and_enter: Bad character in ACPI Name: %X\n",
+ target_name));
+ return_ACPI_STATUS (AE_BAD_CHARACTER);
+ }
+
+ /* Try to find the name in the namespace level specified by the caller */
+
+ *return_node = ACPI_ENTRY_NOT_FOUND;
+ status = acpi_ns_search_node (target_name, node, type, return_node);
+ if (status != AE_NOT_FOUND) {
+ /*
+ * If we found it AND the request specifies that a find is an error,
+ * return the error
+ */
+ if ((status == AE_OK) &&
+ (flags & ACPI_NS_ERROR_IF_FOUND)) {
+ status = AE_ALREADY_EXISTS;
+ }
+
+ /*
+ * Either found it or there was an error
+ * -- finished either way
+ */
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * The name was not found. If we are NOT performing the first pass
+ * (name entry) of loading the namespace, search the parent tree (all the
+ * way to the root if necessary.) We don't want to perform the parent
+ * search when the namespace is actually being loaded. We want to perform
+ * the search when namespace references are being resolved (load pass 2)
+ * and during the execution phase.
+ */
+ if ((interpreter_mode != ACPI_IMODE_LOAD_PASS1) &&
+ (flags & ACPI_NS_SEARCH_PARENT)) {
+ /*
+ * Not found at this level - search parent tree according to the
+ * ACPI specification
+ */
+ status = acpi_ns_search_parent_tree (target_name, node, type, return_node);
+ if (ACPI_SUCCESS (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * In execute mode, just search, never add names. Exit now.
+ */
+ if (interpreter_mode == ACPI_IMODE_EXECUTE) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_NAMES,
+ "%4.4s Not found in %p [Not adding]\n",
+ (char *) &target_name, node));
+
+ return_ACPI_STATUS (AE_NOT_FOUND);
+ }
+
+ /* Create the new named object */
+
+ new_node = acpi_ns_create_node (target_name);
+ if (!new_node) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Install the new object into the parent's list of children */
+
+ acpi_ns_install_node (walk_state, node, new_node, type);
+ *return_node = new_node;
+
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
new file mode 100644
index 000000000000..75da76cc0b19
--- /dev/null
+++ b/drivers/acpi/namespace/nsutils.c
@@ -0,0 +1,1069 @@
+/******************************************************************************
+ *
+ * Module Name: nsutils - Utilities for accessing ACPI namespace, accessing
+ * parents and siblings and Scope manipulation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_report_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print warning message with full pathname
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_report_error (
+ char *module_name,
+ u32 line_number,
+ u32 component_id,
+ char *internal_name,
+ acpi_status lookup_status)
+{
+ acpi_status status;
+ char *name = NULL;
+
+
+ acpi_os_printf ("%8s-%04d: *** Error: Looking up ",
+ module_name, line_number);
+
+ if (lookup_status == AE_BAD_CHARACTER) {
+ /* There is a non-ascii character in the name */
+
+ acpi_os_printf ("[0x%4.4X] (NON-ASCII)\n",
+ *(ACPI_CAST_PTR (u32, internal_name)));
+ }
+ else {
+ /* Convert path to external format */
+
+ status = acpi_ns_externalize_name (ACPI_UINT32_MAX,
+ internal_name, NULL, &name);
+
+ /* Print target name */
+
+ if (ACPI_SUCCESS (status)) {
+ acpi_os_printf ("[%s]", name);
+ }
+ else {
+ acpi_os_printf ("[COULD NOT EXTERNALIZE NAME]");
+ }
+
+ if (name) {
+ ACPI_MEM_FREE (name);
+ }
+ }
+
+ acpi_os_printf (" in namespace, %s\n",
+ acpi_format_exception (lookup_status));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_report_method_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print warning message with full pathname
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_report_method_error (
+ char *module_name,
+ u32 line_number,
+ u32 component_id,
+ char *message,
+ struct acpi_namespace_node *prefix_node,
+ char *path,
+ acpi_status method_status)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node = prefix_node;
+
+
+ if (path) {
+ status = acpi_ns_get_node_by_path (path, prefix_node,
+ ACPI_NS_NO_UPSEARCH, &node);
+ if (ACPI_FAILURE (status)) {
+ acpi_os_printf ("report_method_error: Could not get node\n");
+ return;
+ }
+ }
+
+ acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number);
+ acpi_ns_print_node_pathname (node, message);
+ acpi_os_printf (", %s\n", acpi_format_exception (method_status));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_print_node_pathname
+ *
+ * PARAMETERS: Node - Object
+ * Msg - Prefix message
+ *
+ * DESCRIPTION: Print an object's full namespace pathname
+ * Manages allocation/freeing of a pathname buffer
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_print_node_pathname (
+ struct acpi_namespace_node *node,
+ char *msg)
+{
+ struct acpi_buffer buffer;
+ acpi_status status;
+
+
+ if (!node) {
+ acpi_os_printf ("[NULL NAME]");
+ return;
+ }
+
+ /* Convert handle to full pathname and print it (with supplied message) */
+
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+
+ status = acpi_ns_handle_to_pathname (node, &buffer);
+ if (ACPI_SUCCESS (status)) {
+ if (msg) {
+ acpi_os_printf ("%s ", msg);
+ }
+
+ acpi_os_printf ("[%s] (Node %p)", (char *) buffer.pointer, node);
+ ACPI_MEM_FREE (buffer.pointer);
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_valid_root_prefix
+ *
+ * PARAMETERS: Prefix - Character to be checked
+ *
+ * RETURN: TRUE if a valid prefix
+ *
+ * DESCRIPTION: Check if a character is a valid ACPI Root prefix
+ *
+ ******************************************************************************/
+
+u8
+acpi_ns_valid_root_prefix (
+ char prefix)
+{
+
+ return ((u8) (prefix == '\\'));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_valid_path_separator
+ *
+ * PARAMETERS: Sep - Character to be checked
+ *
+ * RETURN: TRUE if a valid path separator
+ *
+ * DESCRIPTION: Check if a character is a valid ACPI path separator
+ *
+ ******************************************************************************/
+
+u8
+acpi_ns_valid_path_separator (
+ char sep)
+{
+
+ return ((u8) (sep == '.'));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_type
+ *
+ * PARAMETERS: Handle - Parent Node to be examined
+ *
+ * RETURN: Type field from Node whose handle is passed
+ *
+ ******************************************************************************/
+
+acpi_object_type
+acpi_ns_get_type (
+ struct acpi_namespace_node *node)
+{
+ ACPI_FUNCTION_TRACE ("ns_get_type");
+
+
+ if (!node) {
+ ACPI_REPORT_WARNING (("ns_get_type: Null Node input pointer\n"));
+ return_VALUE (ACPI_TYPE_ANY);
+ }
+
+ return_VALUE ((acpi_object_type) node->type);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_local
+ *
+ * PARAMETERS: Type - A namespace object type
+ *
+ * RETURN: LOCAL if names must be found locally in objects of the
+ * passed type, 0 if enclosing scopes should be searched
+ *
+ ******************************************************************************/
+
+u32
+acpi_ns_local (
+ acpi_object_type type)
+{
+ ACPI_FUNCTION_TRACE ("ns_local");
+
+
+ if (!acpi_ut_valid_object_type (type)) {
+ /* Type code out of range */
+
+ ACPI_REPORT_WARNING (("ns_local: Invalid Object Type\n"));
+ return_VALUE (ACPI_NS_NORMAL);
+ }
+
+ return_VALUE ((u32) acpi_gbl_ns_properties[type] & ACPI_NS_LOCAL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_internal_name_length
+ *
+ * PARAMETERS: Info - Info struct initialized with the
+ * external name pointer.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Calculate the length of the internal (AML) namestring
+ * corresponding to the external (ASL) namestring.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_get_internal_name_length (
+ struct acpi_namestring_info *info)
+{
+ char *next_external_char;
+ u32 i;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ next_external_char = info->external_name;
+ info->num_carats = 0;
+ info->num_segments = 0;
+ info->fully_qualified = FALSE;
+
+ /*
+ * For the internal name, the required length is 4 bytes per segment, plus
+ * 1 each for root_prefix, multi_name_prefix_op, segment count, trailing null
+ * (which is not really needed, but no there's harm in putting it there)
+ *
+ * strlen() + 1 covers the first name_seg, which has no path separator
+ */
+ if (acpi_ns_valid_root_prefix (next_external_char[0])) {
+ info->fully_qualified = TRUE;
+ next_external_char++;
+ }
+ else {
+ /*
+ * Handle Carat prefixes
+ */
+ while (*next_external_char == '^') {
+ info->num_carats++;
+ next_external_char++;
+ }
+ }
+
+ /*
+ * Determine the number of ACPI name "segments" by counting the number of
+ * path separators within the string. Start with one segment since the
+ * segment count is [(# separators) + 1], and zero separators is ok.
+ */
+ if (*next_external_char) {
+ info->num_segments = 1;
+ for (i = 0; next_external_char[i]; i++) {
+ if (acpi_ns_valid_path_separator (next_external_char[i])) {
+ info->num_segments++;
+ }
+ }
+ }
+
+ info->length = (ACPI_NAME_SIZE * info->num_segments) +
+ 4 + info->num_carats;
+
+ info->next_external_char = next_external_char;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_build_internal_name
+ *
+ * PARAMETERS: Info - Info struct fully initialized
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Construct the internal (AML) namestring
+ * corresponding to the external (ASL) namestring.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_build_internal_name (
+ struct acpi_namestring_info *info)
+{
+ u32 num_segments = info->num_segments;
+ char *internal_name = info->internal_name;
+ char *external_name = info->next_external_char;
+ char *result = NULL;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_TRACE ("ns_build_internal_name");
+
+
+ /* Setup the correct prefixes, counts, and pointers */
+
+ if (info->fully_qualified) {
+ internal_name[0] = '\\';
+
+ if (num_segments <= 1) {
+ result = &internal_name[1];
+ }
+ else if (num_segments == 2) {
+ internal_name[1] = AML_DUAL_NAME_PREFIX;
+ result = &internal_name[2];
+ }
+ else {
+ internal_name[1] = AML_MULTI_NAME_PREFIX_OP;
+ internal_name[2] = (char) num_segments;
+ result = &internal_name[3];
+ }
+ }
+ else {
+ /*
+ * Not fully qualified.
+ * Handle Carats first, then append the name segments
+ */
+ i = 0;
+ if (info->num_carats) {
+ for (i = 0; i < info->num_carats; i++) {
+ internal_name[i] = '^';
+ }
+ }
+
+ if (num_segments <= 1) {
+ result = &internal_name[i];
+ }
+ else if (num_segments == 2) {
+ internal_name[i] = AML_DUAL_NAME_PREFIX;
+ result = &internal_name[(acpi_native_uint) (i+1)];
+ }
+ else {
+ internal_name[i] = AML_MULTI_NAME_PREFIX_OP;
+ internal_name[(acpi_native_uint) (i+1)] = (char) num_segments;
+ result = &internal_name[(acpi_native_uint) (i+2)];
+ }
+ }
+
+ /* Build the name (minus path separators) */
+
+ for (; num_segments; num_segments--) {
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ if (acpi_ns_valid_path_separator (*external_name) ||
+ (*external_name == 0)) {
+ /* Pad the segment with underscore(s) if segment is short */
+
+ result[i] = '_';
+ }
+ else {
+ /* Convert the character to uppercase and save it */
+
+ result[i] = (char) ACPI_TOUPPER ((int) *external_name);
+ external_name++;
+ }
+ }
+
+ /* Now we must have a path separator, or the pathname is bad */
+
+ if (!acpi_ns_valid_path_separator (*external_name) &&
+ (*external_name != 0)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Move on the next segment */
+
+ external_name++;
+ result += ACPI_NAME_SIZE;
+ }
+
+ /* Terminate the string */
+
+ *result = 0;
+
+ if (info->fully_qualified) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (abs) \"\\%s\"\n",
+ internal_name, internal_name));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Returning [%p] (rel) \"%s\"\n",
+ internal_name, internal_name));
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_internalize_name
+ *
+ * PARAMETERS: *external_name - External representation of name
+ * **Converted Name - Where to return the resulting
+ * internal represention of the name
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an external representation (e.g. "\_PR_.CPU0")
+ * to internal form (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
+ *
+ *******************************************************************************/
+
+acpi_status
+acpi_ns_internalize_name (
+ char *external_name,
+ char **converted_name)
+{
+ char *internal_name;
+ struct acpi_namestring_info info;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ns_internalize_name");
+
+
+ if ((!external_name) ||
+ (*external_name == 0) ||
+ (!converted_name)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Get the length of the new internal name */
+
+ info.external_name = external_name;
+ acpi_ns_get_internal_name_length (&info);
+
+ /* We need a segment to store the internal name */
+
+ internal_name = ACPI_MEM_CALLOCATE (info.length);
+ if (!internal_name) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Build the name */
+
+ info.internal_name = internal_name;
+ status = acpi_ns_build_internal_name (&info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_MEM_FREE (internal_name);
+ return_ACPI_STATUS (status);
+ }
+
+ *converted_name = internal_name;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_externalize_name
+ *
+ * PARAMETERS: *internal_name - Internal representation of name
+ * **converted_name - Where to return the resulting
+ * external representation of name
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
+ * to its external form (e.g. "\_PR_.CPU0")
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_externalize_name (
+ u32 internal_name_length,
+ char *internal_name,
+ u32 *converted_name_length,
+ char **converted_name)
+{
+ acpi_native_uint names_index = 0;
+ acpi_native_uint num_segments = 0;
+ acpi_native_uint required_length;
+ acpi_native_uint prefix_length = 0;
+ acpi_native_uint i = 0;
+ acpi_native_uint j = 0;
+
+
+ ACPI_FUNCTION_TRACE ("ns_externalize_name");
+
+
+ if (!internal_name_length ||
+ !internal_name ||
+ !converted_name) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Check for a prefix (one '\' | one or more '^').
+ */
+ switch (internal_name[0]) {
+ case '\\':
+ prefix_length = 1;
+ break;
+
+ case '^':
+ for (i = 0; i < internal_name_length; i++) {
+ if (internal_name[i] == '^') {
+ prefix_length = i + 1;
+ }
+ else {
+ break;
+ }
+ }
+
+ if (i == internal_name_length) {
+ prefix_length = i;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * Check for object names. Note that there could be 0-255 of these
+ * 4-byte elements.
+ */
+ if (prefix_length < internal_name_length) {
+ switch (internal_name[prefix_length]) {
+ case AML_MULTI_NAME_PREFIX_OP:
+
+ /* <count> 4-byte names */
+
+ names_index = prefix_length + 2;
+ num_segments = (acpi_native_uint) (u8)
+ internal_name[(acpi_native_uint) (prefix_length + 1)];
+ break;
+
+ case AML_DUAL_NAME_PREFIX:
+
+ /* Two 4-byte names */
+
+ names_index = prefix_length + 1;
+ num_segments = 2;
+ break;
+
+ case 0:
+
+ /* null_name */
+
+ names_index = 0;
+ num_segments = 0;
+ break;
+
+ default:
+
+ /* one 4-byte name */
+
+ names_index = prefix_length;
+ num_segments = 1;
+ break;
+ }
+ }
+
+ /*
+ * Calculate the length of converted_name, which equals the length
+ * of the prefix, length of all object names, length of any required
+ * punctuation ('.') between object names, plus the NULL terminator.
+ */
+ required_length = prefix_length + (4 * num_segments) +
+ ((num_segments > 0) ? (num_segments - 1) : 0) + 1;
+
+ /*
+ * Check to see if we're still in bounds. If not, there's a problem
+ * with internal_name (invalid format).
+ */
+ if (required_length > internal_name_length) {
+ ACPI_REPORT_ERROR (("ns_externalize_name: Invalid internal name\n"));
+ return_ACPI_STATUS (AE_BAD_PATHNAME);
+ }
+
+ /*
+ * Build converted_name
+ */
+ *converted_name = ACPI_MEM_CALLOCATE (required_length);
+ if (!(*converted_name)) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ j = 0;
+
+ for (i = 0; i < prefix_length; i++) {
+ (*converted_name)[j++] = internal_name[i];
+ }
+
+ if (num_segments > 0) {
+ for (i = 0; i < num_segments; i++) {
+ if (i > 0) {
+ (*converted_name)[j++] = '.';
+ }
+
+ (*converted_name)[j++] = internal_name[names_index++];
+ (*converted_name)[j++] = internal_name[names_index++];
+ (*converted_name)[j++] = internal_name[names_index++];
+ (*converted_name)[j++] = internal_name[names_index++];
+ }
+ }
+
+ if (converted_name_length) {
+ *converted_name_length = (u32) required_length;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_map_handle_to_node
+ *
+ * PARAMETERS: Handle - Handle to be converted to an Node
+ *
+ * RETURN: A Name table entry pointer
+ *
+ * DESCRIPTION: Convert a namespace handle to a real Node
+ *
+ * Note: Real integer handles allow for more verification
+ * and keep all pointers within this subsystem.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *
+acpi_ns_map_handle_to_node (
+ acpi_handle handle)
+{
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * Simple implementation.
+ */
+ if (!handle) {
+ return (NULL);
+ }
+
+ if (handle == ACPI_ROOT_OBJECT) {
+ return (acpi_gbl_root_node);
+ }
+
+ /* We can at least attempt to verify the handle */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (handle) != ACPI_DESC_TYPE_NAMED) {
+ return (NULL);
+ }
+
+ return ((struct acpi_namespace_node *) handle);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_convert_entry_to_handle
+ *
+ * PARAMETERS: Node - Node to be converted to a Handle
+ *
+ * RETURN: A user handle
+ *
+ * DESCRIPTION: Convert a real Node to a namespace handle
+ *
+ ******************************************************************************/
+
+acpi_handle
+acpi_ns_convert_entry_to_handle (
+ struct acpi_namespace_node *node)
+{
+
+
+ /*
+ * Simple implementation for now;
+ */
+ return ((acpi_handle) node);
+
+
+/* ---------------------------------------------------
+
+ if (!Node)
+ {
+ return (NULL);
+ }
+
+ if (Node == acpi_gbl_root_node)
+ {
+ return (ACPI_ROOT_OBJECT);
+ }
+
+
+ return ((acpi_handle) Node);
+------------------------------------------------------*/
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_terminate
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: free memory allocated for table storage.
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_terminate (void)
+{
+ union acpi_operand_object *obj_desc;
+
+
+ ACPI_FUNCTION_TRACE ("ns_terminate");
+
+
+ /*
+ * 1) Free the entire namespace -- all nodes and objects
+ *
+ * Delete all object descriptors attached to namepsace nodes
+ */
+ acpi_ns_delete_namespace_subtree (acpi_gbl_root_node);
+
+ /* Detach any objects attached to the root */
+
+ obj_desc = acpi_ns_get_attached_object (acpi_gbl_root_node);
+ if (obj_desc) {
+ acpi_ns_detach_object (acpi_gbl_root_node);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Namespace freed\n"));
+
+ /*
+ * 2) Now we can delete the ACPI tables
+ */
+ acpi_tb_delete_all_tables ();
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "ACPI Tables freed\n"));
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_opens_scope
+ *
+ * PARAMETERS: Type - A valid namespace type
+ *
+ * RETURN: NEWSCOPE if the passed type "opens a name scope" according
+ * to the ACPI specification, else 0
+ *
+ ******************************************************************************/
+
+u32
+acpi_ns_opens_scope (
+ acpi_object_type type)
+{
+ ACPI_FUNCTION_TRACE_STR ("ns_opens_scope", acpi_ut_get_type_name (type));
+
+
+ if (!acpi_ut_valid_object_type (type)) {
+ /* type code out of range */
+
+ ACPI_REPORT_WARNING (("ns_opens_scope: Invalid Object Type %X\n", type));
+ return_VALUE (ACPI_NS_NORMAL);
+ }
+
+ return_VALUE (((u32) acpi_gbl_ns_properties[type]) & ACPI_NS_NEWSCOPE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_node_by_path
+ *
+ * PARAMETERS: *Pathname - Name to be found, in external (ASL) format. The
+ * \ (backslash) and ^ (carat) prefixes, and the
+ * . (period) to separate segments are supported.
+ * start_node - Root of subtree to be searched, or NS_ALL for the
+ * root of the name space. If Name is fully
+ * qualified (first s8 is '\'), the passed value
+ * of Scope will not be accessed.
+ * Flags - Used to indicate whether to perform upsearch or
+ * not.
+ * return_node - Where the Node is returned
+ *
+ * DESCRIPTION: Look up a name relative to a given scope and return the
+ * corresponding Node. NOTE: Scope can be null.
+ *
+ * MUTEX: Locks namespace
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_get_node_by_path (
+ char *pathname,
+ struct acpi_namespace_node *start_node,
+ u32 flags,
+ struct acpi_namespace_node **return_node)
+{
+ union acpi_generic_state scope_info;
+ acpi_status status;
+ char *internal_path = NULL;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ns_get_node_by_path", pathname);
+
+
+ if (pathname) {
+ /* Convert path to internal representation */
+
+ status = acpi_ns_internalize_name (pathname, &internal_path);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Must lock namespace during lookup */
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Setup lookup scope (search starting point) */
+
+ scope_info.scope.node = start_node;
+
+ /* Lookup the name in the namespace */
+
+ status = acpi_ns_lookup (&scope_info, internal_path,
+ ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ (flags | ACPI_NS_DONT_OPEN_SCOPE),
+ NULL, return_node);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s, %s\n",
+ internal_path, acpi_format_exception (status)));
+ }
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+
+cleanup:
+ /* Cleanup */
+ if (internal_path) {
+ ACPI_MEM_FREE (internal_path);
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_find_parent_name
+ *
+ * PARAMETERS: *child_node - Named Obj whose name is to be found
+ *
+ * RETURN: The ACPI name
+ *
+ * DESCRIPTION: Search for the given obj in its parent scope and return the
+ * name segment, or "????" if the parent name can't be found
+ * (which "should not happen").
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_name
+acpi_ns_find_parent_name (
+ struct acpi_namespace_node *child_node)
+{
+ struct acpi_namespace_node *parent_node;
+
+
+ ACPI_FUNCTION_TRACE ("ns_find_parent_name");
+
+
+ if (child_node) {
+ /* Valid entry. Get the parent Node */
+
+ parent_node = acpi_ns_get_parent_node (child_node);
+ if (parent_node) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Parent of %p [%4.4s] is %p [%4.4s]\n",
+ child_node, acpi_ut_get_node_name (child_node),
+ parent_node, acpi_ut_get_node_name (parent_node)));
+
+ if (parent_node->name.integer) {
+ return_VALUE ((acpi_name) parent_node->name.integer);
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Unable to find parent of %p (%4.4s)\n",
+ child_node, acpi_ut_get_node_name (child_node)));
+ }
+
+ return_VALUE (ACPI_UNKNOWN_NAME);
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_parent_node
+ *
+ * PARAMETERS: Node - Current table entry
+ *
+ * RETURN: Parent entry of the given entry
+ *
+ * DESCRIPTION: Obtain the parent entry for a given entry in the namespace.
+ *
+ ******************************************************************************/
+
+
+struct acpi_namespace_node *
+acpi_ns_get_parent_node (
+ struct acpi_namespace_node *node)
+{
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (!node) {
+ return (NULL);
+ }
+
+ /*
+ * Walk to the end of this peer list. The last entry is marked with a flag
+ * and the peer pointer is really a pointer back to the parent. This saves
+ * putting a parent back pointer in each and every named object!
+ */
+ while (!(node->flags & ANOBJ_END_OF_PEER_LIST)) {
+ node = node->peer;
+ }
+
+
+ return (node->peer);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_next_valid_node
+ *
+ * PARAMETERS: Node - Current table entry
+ *
+ * RETURN: Next valid Node in the linked node list. NULL if no more valid
+ * nodes.
+ *
+ * DESCRIPTION: Find the next valid node within a name table.
+ * Useful for implementing NULL-end-of-list loops.
+ *
+ ******************************************************************************/
+
+
+struct acpi_namespace_node *
+acpi_ns_get_next_valid_node (
+ struct acpi_namespace_node *node)
+{
+
+ /* If we are at the end of this peer list, return NULL */
+
+ if (node->flags & ANOBJ_END_OF_PEER_LIST) {
+ return NULL;
+ }
+
+ /* Otherwise just return the next peer */
+
+ return (node->peer);
+}
+
+
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
new file mode 100644
index 000000000000..4de2444df300
--- /dev/null
+++ b/drivers/acpi/namespace/nswalk.c
@@ -0,0 +1,289 @@
+/******************************************************************************
+ *
+ * Module Name: nswalk - Functions for walking the ACPI namespace
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nswalk")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_next_node
+ *
+ * PARAMETERS: Type - Type of node to be searched for
+ * parent_node - Parent node whose children we are
+ * getting
+ * child_node - Previous child that was found.
+ * The NEXT child will be returned
+ *
+ * RETURN: struct acpi_namespace_node - Pointer to the NEXT child or NULL if
+ * none is found.
+ *
+ * DESCRIPTION: Return the next peer node within the namespace. If Handle
+ * is valid, Scope is ignored. Otherwise, the first node
+ * within Scope is returned.
+ *
+ ******************************************************************************/
+
+struct acpi_namespace_node *
+acpi_ns_get_next_node (
+ acpi_object_type type,
+ struct acpi_namespace_node *parent_node,
+ struct acpi_namespace_node *child_node)
+{
+ struct acpi_namespace_node *next_node = NULL;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (!child_node) {
+ /* It's really the parent's _scope_ that we want */
+
+ if (parent_node->child) {
+ next_node = parent_node->child;
+ }
+ }
+
+ else {
+ /* Start search at the NEXT node */
+
+ next_node = acpi_ns_get_next_valid_node (child_node);
+ }
+
+ /* If any type is OK, we are done */
+
+ if (type == ACPI_TYPE_ANY) {
+ /* next_node is NULL if we are at the end-of-list */
+
+ return (next_node);
+ }
+
+ /* Must search for the node -- but within this scope only */
+
+ while (next_node) {
+ /* If type matches, we are done */
+
+ if (next_node->type == type) {
+ return (next_node);
+ }
+
+ /* Otherwise, move on to the next node */
+
+ next_node = acpi_ns_get_next_valid_node (next_node);
+ }
+
+ /* Not found */
+
+ return (NULL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_walk_namespace
+ *
+ * PARAMETERS: Type - acpi_object_type to search for
+ * start_node - Handle in namespace where search begins
+ * max_depth - Depth to which search is to reach
+ * unlock_before_callback- Whether to unlock the NS before invoking
+ * the callback routine
+ * user_function - Called when an object of "Type" is found
+ * Context - Passed to user function
+ * return_value - from the user_function if terminated early.
+ * Otherwise, returns NULL.
+ * RETURNS: Status
+ *
+ * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
+ * starting (and ending) at the node specified by start_handle.
+ * The user_function is called whenever a node that matches
+ * the type parameter is found. If the user function returns
+ * a non-zero value, the search is terminated immediately and this
+ * value is returned to the caller.
+ *
+ * The point of this procedure is to provide a generic namespace
+ * walk routine that can be called from multiple places to
+ * provide multiple services; the User Function can be tailored
+ * to each task, whether it is a print function, a compare
+ * function, etc.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ns_walk_namespace (
+ acpi_object_type type,
+ acpi_handle start_node,
+ u32 max_depth,
+ u8 unlock_before_callback,
+ acpi_walk_callback user_function,
+ void *context,
+ void **return_value)
+{
+ acpi_status status;
+ acpi_status mutex_status;
+ struct acpi_namespace_node *child_node;
+ struct acpi_namespace_node *parent_node;
+ acpi_object_type child_type;
+ u32 level;
+
+
+ ACPI_FUNCTION_TRACE ("ns_walk_namespace");
+
+
+ /* Special case for the namespace Root Node */
+
+ if (start_node == ACPI_ROOT_OBJECT) {
+ start_node = acpi_gbl_root_node;
+ }
+
+ /* Null child means "get first node" */
+
+ parent_node = start_node;
+ child_node = NULL;
+ child_type = ACPI_TYPE_ANY;
+ level = 1;
+
+ /*
+ * Traverse the tree of nodes until we bubble back up to where we
+ * started. When Level is zero, the loop is done because we have
+ * bubbled up to (and passed) the original parent handle (start_entry)
+ */
+ while (level > 0) {
+ /* Get the next node in this scope. Null if not found */
+
+ status = AE_OK;
+ child_node = acpi_ns_get_next_node (ACPI_TYPE_ANY, parent_node, child_node);
+ if (child_node) {
+ /*
+ * Found node, Get the type if we are not
+ * searching for ANY
+ */
+ if (type != ACPI_TYPE_ANY) {
+ child_type = child_node->type;
+ }
+
+ if (child_type == type) {
+ /*
+ * Found a matching node, invoke the user
+ * callback function
+ */
+ if (unlock_before_callback) {
+ mutex_status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (mutex_status)) {
+ return_ACPI_STATUS (mutex_status);
+ }
+ }
+
+ status = user_function (child_node, level,
+ context, return_value);
+
+ if (unlock_before_callback) {
+ mutex_status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (mutex_status)) {
+ return_ACPI_STATUS (mutex_status);
+ }
+ }
+
+ switch (status) {
+ case AE_OK:
+ case AE_CTRL_DEPTH:
+
+ /* Just keep going */
+ break;
+
+ case AE_CTRL_TERMINATE:
+
+ /* Exit now, with OK status */
+
+ return_ACPI_STATUS (AE_OK);
+
+ default:
+
+ /* All others are valid exceptions */
+
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Depth first search:
+ * Attempt to go down another level in the namespace
+ * if we are allowed to. Don't go any further if we
+ * have reached the caller specified maximum depth
+ * or if the user function has specified that the
+ * maximum depth has been reached.
+ */
+ if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
+ if (acpi_ns_get_next_node (ACPI_TYPE_ANY, child_node, NULL)) {
+ /*
+ * There is at least one child of this
+ * node, visit the onde
+ */
+ level++;
+ parent_node = child_node;
+ child_node = NULL;
+ }
+ }
+ }
+ else {
+ /*
+ * No more children of this node (acpi_ns_get_next_node
+ * failed), go back upwards in the namespace tree to
+ * the node's parent.
+ */
+ level--;
+ child_node = parent_node;
+ parent_node = acpi_ns_get_parent_node (parent_node);
+ }
+ }
+
+ /* Complete walk, not terminated by user function */
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
new file mode 100644
index 000000000000..1dc995586cbe
--- /dev/null
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -0,0 +1,764 @@
+/*******************************************************************************
+ *
+ * Module Name: nsxfeval - Public interfaces to the ACPI subsystem
+ * ACPI Object evaluation interfaces
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsxfeval")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_evaluate_object_typed
+ *
+ * PARAMETERS: Handle - Object handle (optional)
+ * *Pathname - Object pathname (optional)
+ * **external_params - List of parameters to pass to method,
+ * terminated by NULL. May be NULL
+ * if no parameters are being passed.
+ * *return_buffer - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ * return_type - Expected type of return object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find and evaluate the given object, passing the given
+ * parameters if necessary. One of "Handle" or "Pathname" must
+ * be valid (non-null)
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_evaluate_object_typed (
+ acpi_handle handle,
+ acpi_string pathname,
+ struct acpi_object_list *external_params,
+ struct acpi_buffer *return_buffer,
+ acpi_object_type return_type)
+{
+ acpi_status status;
+ u8 must_free = FALSE;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_evaluate_object_typed");
+
+
+ /* Return buffer must be valid */
+
+ if (!return_buffer) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (return_buffer->length == ACPI_ALLOCATE_BUFFER) {
+ must_free = TRUE;
+ }
+
+ /* Evaluate the object */
+
+ status = acpi_evaluate_object (handle, pathname, external_params, return_buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Type ANY means "don't care" */
+
+ if (return_type == ACPI_TYPE_ANY) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ if (return_buffer->length == 0) {
+ /* Error because caller specifically asked for a return value */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "No return value\n"));
+
+ return_ACPI_STATUS (AE_NULL_OBJECT);
+ }
+
+ /* Examine the object type returned from evaluate_object */
+
+ if (((union acpi_object *) return_buffer->pointer)->type == return_type) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Return object type does not match requested type */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Incorrect return type [%s] requested [%s]\n",
+ acpi_ut_get_type_name (((union acpi_object *) return_buffer->pointer)->type),
+ acpi_ut_get_type_name (return_type)));
+
+ if (must_free) {
+ /* Caller used ACPI_ALLOCATE_BUFFER, free the return buffer */
+
+ acpi_os_free (return_buffer->pointer);
+ return_buffer->pointer = NULL;
+ }
+
+ return_buffer->length = 0;
+ return_ACPI_STATUS (AE_TYPE);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_evaluate_object
+ *
+ * PARAMETERS: Handle - Object handle (optional)
+ * Pathname - Object pathname (optional)
+ * external_params - List of parameters to pass to method,
+ * terminated by NULL. May be NULL
+ * if no parameters are being passed.
+ * return_buffer - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find and evaluate the given object, passing the given
+ * parameters if necessary. One of "Handle" or "Pathname" must
+ * be valid (non-null)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_evaluate_object (
+ acpi_handle handle,
+ acpi_string pathname,
+ struct acpi_object_list *external_params,
+ struct acpi_buffer *return_buffer)
+{
+ acpi_status status;
+ acpi_status status2;
+ struct acpi_parameter_info info;
+ acpi_size buffer_space_needed;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_evaluate_object");
+
+
+ info.node = handle;
+ info.parameters = NULL;
+ info.return_object = NULL;
+ info.parameter_type = ACPI_PARAM_ARGS;
+
+ /*
+ * If there are parameters to be passed to the object
+ * (which must be a control method), the external objects
+ * must be converted to internal objects
+ */
+ if (external_params && external_params->count) {
+ /*
+ * Allocate a new parameter block for the internal objects
+ * Add 1 to count to allow for null terminated internal list
+ */
+ info.parameters = ACPI_MEM_CALLOCATE (
+ ((acpi_size) external_params->count + 1) *
+ sizeof (void *));
+ if (!info.parameters) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Convert each external object in the list to an
+ * internal object
+ */
+ for (i = 0; i < external_params->count; i++) {
+ status = acpi_ut_copy_eobject_to_iobject (&external_params->pointer[i],
+ &info.parameters[i]);
+ if (ACPI_FAILURE (status)) {
+ acpi_ut_delete_internal_object_list (info.parameters);
+ return_ACPI_STATUS (status);
+ }
+ }
+ info.parameters[external_params->count] = NULL;
+ }
+
+
+ /*
+ * Three major cases:
+ * 1) Fully qualified pathname
+ * 2) No handle, not fully qualified pathname (error)
+ * 3) Valid handle
+ */
+ if ((pathname) &&
+ (acpi_ns_valid_root_prefix (pathname[0]))) {
+ /*
+ * The path is fully qualified, just evaluate by name
+ */
+ status = acpi_ns_evaluate_by_name (pathname, &info);
+ }
+ else if (!handle) {
+ /*
+ * A handle is optional iff a fully qualified pathname
+ * is specified. Since we've already handled fully
+ * qualified names above, this is an error
+ */
+ if (!pathname) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Both Handle and Pathname are NULL\n"));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Handle is NULL and Pathname is relative\n"));
+ }
+
+ status = AE_BAD_PARAMETER;
+ }
+ else {
+ /*
+ * We get here if we have a handle -- and if we have a
+ * pathname it is relative. The handle will be validated
+ * in the lower procedures
+ */
+ if (!pathname) {
+ /*
+ * The null pathname case means the handle is for
+ * the actual object to be evaluated
+ */
+ status = acpi_ns_evaluate_by_handle (&info);
+ }
+ else {
+ /*
+ * Both a Handle and a relative Pathname
+ */
+ status = acpi_ns_evaluate_relative (pathname, &info);
+ }
+ }
+
+
+ /*
+ * If we are expecting a return value, and all went well above,
+ * copy the return value to an external object.
+ */
+ if (return_buffer) {
+ if (!info.return_object) {
+ return_buffer->length = 0;
+ }
+ else {
+ if (ACPI_GET_DESCRIPTOR_TYPE (info.return_object) == ACPI_DESC_TYPE_NAMED) {
+ /*
+ * If we received a NS Node as a return object, this means that
+ * the object we are evaluating has nothing interesting to
+ * return (such as a mutex, etc.) We return an error because
+ * these types are essentially unsupported by this interface.
+ * We don't check up front because this makes it easier to add
+ * support for various types at a later date if necessary.
+ */
+ status = AE_TYPE;
+ info.return_object = NULL; /* No need to delete a NS Node */
+ return_buffer->length = 0;
+ }
+
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * Find out how large a buffer is needed
+ * to contain the returned object
+ */
+ status = acpi_ut_get_object_size (info.return_object,
+ &buffer_space_needed);
+ if (ACPI_SUCCESS (status)) {
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed);
+ if (ACPI_FAILURE (status)) {
+ /*
+ * Caller's buffer is too small or a new one can't be allocated
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Needed buffer size %X, %s\n",
+ (u32) buffer_space_needed,
+ acpi_format_exception (status)));
+ }
+ else {
+ /*
+ * We have enough space for the object, build it
+ */
+ status = acpi_ut_copy_iobject_to_eobject (info.return_object,
+ return_buffer);
+ }
+ }
+ }
+ }
+ }
+
+ if (info.return_object) {
+ /*
+ * Delete the internal return object. NOTE: Interpreter
+ * must be locked to avoid race condition.
+ */
+ status2 = acpi_ex_enter_interpreter ();
+ if (ACPI_SUCCESS (status2)) {
+ /*
+ * Delete the internal return object. (Or at least
+ * decrement the reference count by one)
+ */
+ acpi_ut_remove_reference (info.return_object);
+ acpi_ex_exit_interpreter ();
+ }
+ }
+
+ /*
+ * Free the input parameter list (if we created one),
+ */
+ if (info.parameters) {
+ /* Free the allocated parameter block */
+
+ acpi_ut_delete_internal_object_list (info.parameters);
+ }
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_evaluate_object);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_walk_namespace
+ *
+ * PARAMETERS: Type - acpi_object_type to search for
+ * start_object - Handle in namespace where search begins
+ * max_depth - Depth to which search is to reach
+ * user_function - Called when an object of "Type" is found
+ * Context - Passed to user function
+ * return_value - Location where return value of
+ * user_function is put if terminated early
+ *
+ * RETURNS Return value from the user_function if terminated early.
+ * Otherwise, returns NULL.
+ *
+ * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
+ * starting (and ending) at the object specified by start_handle.
+ * The user_function is called whenever an object that matches
+ * the type parameter is found. If the user function returns
+ * a non-zero value, the search is terminated immediately and this
+ * value is returned to the caller.
+ *
+ * The point of this procedure is to provide a generic namespace
+ * walk routine that can be called from multiple places to
+ * provide multiple services; the User Function can be tailored
+ * to each task, whether it is a print function, a compare
+ * function, etc.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_walk_namespace (
+ acpi_object_type type,
+ acpi_handle start_object,
+ u32 max_depth,
+ acpi_walk_callback user_function,
+ void *context,
+ void **return_value)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_walk_namespace");
+
+
+ /* Parameter validation */
+
+ if ((type > ACPI_TYPE_EXTERNAL_MAX) ||
+ (!max_depth) ||
+ (!user_function)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Lock the namespace around the walk.
+ * The namespace will be unlocked/locked around each call
+ * to the user function - since this function
+ * must be allowed to make Acpi calls itself.
+ */
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK,
+ user_function, context, return_value);
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_walk_namespace);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_get_device_callback
+ *
+ * PARAMETERS: Callback from acpi_get_device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Takes callbacks from walk_namespace and filters out all non-
+ * present devices, or if they specified a HID, it filters based
+ * on that.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ns_get_device_callback (
+ acpi_handle obj_handle,
+ u32 nesting_level,
+ void *context,
+ void **return_value)
+{
+ struct acpi_get_devices_info *info = context;
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ u32 flags;
+ struct acpi_device_id hid;
+ struct acpi_compatible_id_list *cid;
+ acpi_native_uint i;
+
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ node = acpi_ns_map_handle_to_node (obj_handle);
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ if (!node) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Run _STA to determine if device is present */
+
+ status = acpi_ut_execute_STA (node, &flags);
+ if (ACPI_FAILURE (status)) {
+ return (AE_CTRL_DEPTH);
+ }
+
+ if (!(flags & 0x01)) {
+ /* Don't return at the device or children of the device if not there */
+
+ return (AE_CTRL_DEPTH);
+ }
+
+ /* Filter based on device HID & CID */
+
+ if (info->hid != NULL) {
+ status = acpi_ut_execute_HID (node, &hid);
+ if (status == AE_NOT_FOUND) {
+ return (AE_OK);
+ }
+ else if (ACPI_FAILURE (status)) {
+ return (AE_CTRL_DEPTH);
+ }
+
+ if (ACPI_STRNCMP (hid.value, info->hid, sizeof (hid.value)) != 0) {
+ /* Get the list of Compatible IDs */
+
+ status = acpi_ut_execute_CID (node, &cid);
+ if (status == AE_NOT_FOUND) {
+ return (AE_OK);
+ }
+ else if (ACPI_FAILURE (status)) {
+ return (AE_CTRL_DEPTH);
+ }
+
+ /* Walk the CID list */
+
+ for (i = 0; i < cid->count; i++) {
+ if (ACPI_STRNCMP (cid->id[i].value, info->hid,
+ sizeof (struct acpi_compatible_id)) != 0) {
+ ACPI_MEM_FREE (cid);
+ return (AE_OK);
+ }
+ }
+ ACPI_MEM_FREE (cid);
+ }
+ }
+
+ status = info->user_function (obj_handle, nesting_level, info->context, return_value);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_devices
+ *
+ * PARAMETERS: HID - HID to search for. Can be NULL.
+ * user_function - Called when a matching object is found
+ * Context - Passed to user function
+ * return_value - Location where return value of
+ * user_function is put if terminated early
+ *
+ * RETURNS Return value from the user_function if terminated early.
+ * Otherwise, returns NULL.
+ *
+ * DESCRIPTION: Performs a modified depth-first walk of the namespace tree,
+ * starting (and ending) at the object specified by start_handle.
+ * The user_function is called whenever an object of type
+ * Device is found. If the user function returns
+ * a non-zero value, the search is terminated immediately and this
+ * value is returned to the caller.
+ *
+ * This is a wrapper for walk_namespace, but the callback performs
+ * additional filtering. Please see acpi_get_device_callback.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_devices (
+ char *HID,
+ acpi_walk_callback user_function,
+ void *context,
+ void **return_value)
+{
+ acpi_status status;
+ struct acpi_get_devices_info info;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_devices");
+
+
+ /* Parameter validation */
+
+ if (!user_function) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We're going to call their callback from OUR callback, so we need
+ * to know what it is, and their context parameter.
+ */
+ info.context = context;
+ info.user_function = user_function;
+ info.hid = HID;
+
+ /*
+ * Lock the namespace around the walk.
+ * The namespace will be unlocked/locked around each call
+ * to the user function - since this function
+ * must be allowed to make Acpi calls itself.
+ */
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ns_walk_namespace (ACPI_TYPE_DEVICE,
+ ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+ ACPI_NS_WALK_UNLOCK,
+ acpi_ns_get_device_callback, &info,
+ return_value);
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_devices);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_attach_data
+ *
+ * PARAMETERS: obj_handle - Namespace node
+ * Handler - Handler for this attachment
+ * Data - Pointer to data to be attached
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Attach arbitrary data and handler to a namespace node.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_attach_data (
+ acpi_handle obj_handle,
+ acpi_object_handler handler,
+ void *data)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ /* Parameter validation */
+
+ if (!obj_handle ||
+ !handler ||
+ !data) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Convert and validate the handle */
+
+ node = acpi_ns_map_handle_to_node (obj_handle);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ns_attach_data (node, handler, data);
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_detach_data
+ *
+ * PARAMETERS: obj_handle - Namespace node handle
+ * Handler - Handler used in call to acpi_attach_data
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Remove data that was previously attached to a node.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_detach_data (
+ acpi_handle obj_handle,
+ acpi_object_handler handler)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ /* Parameter validation */
+
+ if (!obj_handle ||
+ !handler) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Convert and validate the handle */
+
+ node = acpi_ns_map_handle_to_node (obj_handle);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ns_detach_data (node, handler);
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_data
+ *
+ * PARAMETERS: obj_handle - Namespace node
+ * Handler - Handler used in call to attach_data
+ * Data - Where the data is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieve data that was previously attached to a namespace node.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_data (
+ acpi_handle obj_handle,
+ acpi_object_handler handler,
+ void **data)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ /* Parameter validation */
+
+ if (!obj_handle ||
+ !handler ||
+ !data) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Convert and validate the handle */
+
+ node = acpi_ns_map_handle_to_node (obj_handle);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ns_get_attached_data (node, handler, data);
+
+unlock_and_exit:
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+
+
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
new file mode 100644
index 000000000000..f2405efd1b9a
--- /dev/null
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -0,0 +1,369 @@
+/******************************************************************************
+ *
+ * Module Name: nsxfname - Public interfaces to the ACPI subsystem
+ * ACPI Namespace oriented interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsxfname")
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_handle
+ *
+ * PARAMETERS: Parent - Object to search under (search scope).
+ * path_name - Pointer to an asciiz string containing the
+ * name
+ * ret_handle - Where the return handle is placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine will search for a caller specified name in the
+ * name space. The caller can restrict the search region by
+ * specifying a non NULL parent. The parent value is itself a
+ * namespace handle.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_handle (
+ acpi_handle parent,
+ acpi_string pathname,
+ acpi_handle *ret_handle)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node = NULL;
+ struct acpi_namespace_node *prefix_node = NULL;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Parameter Validation */
+
+ if (!ret_handle || !pathname) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Convert a parent handle to a prefix node */
+
+ if (parent) {
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ prefix_node = acpi_ns_map_handle_to_node (parent);
+ if (!prefix_node) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ }
+
+ /* Special case for root, since we can't search for it */
+
+ if (ACPI_STRCMP (pathname, ACPI_NS_ROOT_PATH) == 0) {
+ *ret_handle = acpi_ns_convert_entry_to_handle (acpi_gbl_root_node);
+ return (AE_OK);
+ }
+
+ /*
+ * Find the Node and convert to a handle
+ */
+ status = acpi_ns_get_node_by_path (pathname, prefix_node, ACPI_NS_NO_UPSEARCH,
+ &node);
+
+ *ret_handle = NULL;
+ if (ACPI_SUCCESS (status)) {
+ *ret_handle = acpi_ns_convert_entry_to_handle (node);
+ }
+
+ return (status);
+}
+EXPORT_SYMBOL(acpi_get_handle);
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_name
+ *
+ * PARAMETERS: Handle - Handle to be converted to a pathname
+ * name_type - Full pathname or single segment
+ * Buffer - Buffer for returned path
+ *
+ * RETURN: Pointer to a string containing the fully qualified Name.
+ *
+ * DESCRIPTION: This routine returns the fully qualified name associated with
+ * the Handle parameter. This and the acpi_pathname_to_handle are
+ * complementary functions.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_name (
+ acpi_handle handle,
+ u32 name_type,
+ struct acpi_buffer *buffer)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+
+
+ /* Parameter validation */
+
+ if (name_type > ACPI_NAME_TYPE_MAX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_validate_buffer (buffer);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ if (name_type == ACPI_FULL_PATHNAME) {
+ /* Get the full pathname (From the namespace root) */
+
+ status = acpi_ns_handle_to_pathname (handle, buffer);
+ return (status);
+ }
+
+ /*
+ * Wants the single segment ACPI name.
+ * Validate handle and convert to a namespace Node
+ */
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ node = acpi_ns_map_handle_to_node (handle);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (buffer, ACPI_PATH_SEGMENT_LENGTH);
+ if (ACPI_FAILURE (status)) {
+ goto unlock_and_exit;
+ }
+
+ /* Just copy the ACPI name from the Node and zero terminate it */
+
+ ACPI_STRNCPY (buffer->pointer, acpi_ut_get_node_name (node),
+ ACPI_NAME_SIZE);
+ ((char *) buffer->pointer) [ACPI_NAME_SIZE] = 0;
+ status = AE_OK;
+
+
+unlock_and_exit:
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+EXPORT_SYMBOL(acpi_get_name);
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_object_info
+ *
+ * PARAMETERS: Handle - Object Handle
+ * Info - Where the info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Returns information about an object as gleaned from the
+ * namespace node and possibly by running several standard
+ * control methods (Such as in the case of a device.)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_object_info (
+ acpi_handle handle,
+ struct acpi_buffer *buffer)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ struct acpi_device_info *info;
+ struct acpi_device_info *return_info;
+ struct acpi_compatible_id_list *cid_list = NULL;
+ acpi_size size;
+
+
+ /* Parameter validation */
+
+ if (!handle || !buffer) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_validate_buffer (buffer);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_device_info));
+ if (!info) {
+ return (AE_NO_MEMORY);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ node = acpi_ns_map_handle_to_node (handle);
+ if (!node) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ goto cleanup;
+ }
+
+ /* Init return structure */
+
+ size = sizeof (struct acpi_device_info);
+
+ info->type = node->type;
+ info->name = node->name.integer;
+ info->valid = 0;
+
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* If not a device, we are all done */
+
+ if (info->type == ACPI_TYPE_DEVICE) {
+ /*
+ * Get extra info for ACPI Devices objects only:
+ * Run the Device _HID, _UID, _CID, _STA, _ADR and _sx_d methods.
+ *
+ * Note: none of these methods are required, so they may or may
+ * not be present for this device. The Info->Valid bitfield is used
+ * to indicate which methods were found and ran successfully.
+ */
+
+ /* Execute the Device._HID method */
+
+ status = acpi_ut_execute_HID (node, &info->hardware_id);
+ if (ACPI_SUCCESS (status)) {
+ info->valid |= ACPI_VALID_HID;
+ }
+
+ /* Execute the Device._UID method */
+
+ status = acpi_ut_execute_UID (node, &info->unique_id);
+ if (ACPI_SUCCESS (status)) {
+ info->valid |= ACPI_VALID_UID;
+ }
+
+ /* Execute the Device._CID method */
+
+ status = acpi_ut_execute_CID (node, &cid_list);
+ if (ACPI_SUCCESS (status)) {
+ size += ((acpi_size) cid_list->count - 1) *
+ sizeof (struct acpi_compatible_id);
+ info->valid |= ACPI_VALID_CID;
+ }
+
+ /* Execute the Device._STA method */
+
+ status = acpi_ut_execute_STA (node, &info->current_status);
+ if (ACPI_SUCCESS (status)) {
+ info->valid |= ACPI_VALID_STA;
+ }
+
+ /* Execute the Device._ADR method */
+
+ status = acpi_ut_evaluate_numeric_object (METHOD_NAME__ADR, node,
+ &info->address);
+ if (ACPI_SUCCESS (status)) {
+ info->valid |= ACPI_VALID_ADR;
+ }
+
+ /* Execute the Device._sx_d methods */
+
+ status = acpi_ut_execute_sxds (node, info->highest_dstates);
+ if (ACPI_SUCCESS (status)) {
+ info->valid |= ACPI_VALID_SXDS;
+ }
+ }
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (buffer, size);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Populate the return buffer */
+
+ return_info = buffer->pointer;
+ ACPI_MEMCPY (return_info, info, sizeof (struct acpi_device_info));
+
+ if (cid_list) {
+ ACPI_MEMCPY (&return_info->compatibility_id, cid_list, cid_list->size);
+ }
+
+
+cleanup:
+ ACPI_MEM_FREE (info);
+ if (cid_list) {
+ ACPI_MEM_FREE (cid_list);
+ }
+ return (status);
+}
+EXPORT_SYMBOL(acpi_get_object_info);
+
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
new file mode 100644
index 000000000000..19acf32674b9
--- /dev/null
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -0,0 +1,262 @@
+/*******************************************************************************
+ *
+ * Module Name: nsxfobj - Public interfaces to the ACPI subsystem
+ * ACPI Object oriented interfaces
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_NAMESPACE
+ ACPI_MODULE_NAME ("nsxfobj")
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_type
+ *
+ * PARAMETERS: Handle - Handle of object whose type is desired
+ * *ret_type - Where the type will be placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine returns the type associatd with a particular handle
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_type (
+ acpi_handle handle,
+ acpi_object_type *ret_type)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ /* Parameter Validation */
+
+ if (!ret_type) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Special case for the predefined Root Node
+ * (return type ANY)
+ */
+ if (handle == ACPI_ROOT_OBJECT) {
+ *ret_type = ACPI_TYPE_ANY;
+ return (AE_OK);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Convert and validate the handle */
+
+ node = acpi_ns_map_handle_to_node (handle);
+ if (!node) {
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (AE_BAD_PARAMETER);
+ }
+
+ *ret_type = node->type;
+
+
+ status = acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+EXPORT_SYMBOL(acpi_get_type);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_parent
+ *
+ * PARAMETERS: Handle - Handle of object whose parent is desired
+ * ret_handle - Where the parent handle will be placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Returns a handle to the parent of the object represented by
+ * Handle.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_parent (
+ acpi_handle handle,
+ acpi_handle *ret_handle)
+{
+ struct acpi_namespace_node *node;
+ acpi_status status;
+
+
+ if (!ret_handle) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Special case for the predefined Root Node (no parent) */
+
+ if (handle == ACPI_ROOT_OBJECT) {
+ return (AE_NULL_ENTRY);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* Convert and validate the handle */
+
+ node = acpi_ns_map_handle_to_node (handle);
+ if (!node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Get the parent entry */
+
+ *ret_handle =
+ acpi_ns_convert_entry_to_handle (acpi_ns_get_parent_node (node));
+
+ /* Return exception if parent is null */
+
+ if (!acpi_ns_get_parent_node (node)) {
+ status = AE_NULL_ENTRY;
+ }
+
+
+unlock_and_exit:
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+EXPORT_SYMBOL(acpi_get_parent);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_next_object
+ *
+ * PARAMETERS: Type - Type of object to be searched for
+ * Parent - Parent object whose children we are getting
+ * last_child - Previous child that was found.
+ * The NEXT child will be returned
+ * ret_handle - Where handle to the next object is placed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return the next peer object within the namespace. If Handle is
+ * valid, Scope is ignored. Otherwise, the first object within
+ * Scope is returned.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_next_object (
+ acpi_object_type type,
+ acpi_handle parent,
+ acpi_handle child,
+ acpi_handle *ret_handle)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ struct acpi_namespace_node *parent_node = NULL;
+ struct acpi_namespace_node *child_node = NULL;
+
+
+ /* Parameter validation */
+
+ if (type > ACPI_TYPE_EXTERNAL_MAX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_NAMESPACE);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ /* If null handle, use the parent */
+
+ if (!child) {
+ /* Start search at the beginning of the specified scope */
+
+ parent_node = acpi_ns_map_handle_to_node (parent);
+ if (!parent_node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ }
+ else {
+ /* Non-null handle, ignore the parent */
+ /* Convert and validate the handle */
+
+ child_node = acpi_ns_map_handle_to_node (child);
+ if (!child_node) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+ }
+
+ /* Internal function does the real work */
+
+ node = acpi_ns_get_next_node (type, parent_node, child_node);
+ if (!node) {
+ status = AE_NOT_FOUND;
+ goto unlock_and_exit;
+ }
+
+ if (ret_handle) {
+ *ret_handle = acpi_ns_convert_entry_to_handle (node);
+ }
+
+
+unlock_and_exit:
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
+ return (status);
+}
+EXPORT_SYMBOL(acpi_get_next_object);
+
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
new file mode 100644
index 000000000000..a82834b32752
--- /dev/null
+++ b/drivers/acpi/numa.c
@@ -0,0 +1,213 @@
+/*
+ * acpi_numa.c - ACPI NUMA support
+ *
+ * Copyright (C) 2002 Takayoshi Kochi <t-kochi@bq.jp.nec.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/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acmacros.h>
+
+#define ACPI_NUMA 0x80000000
+#define _COMPONENT ACPI_NUMA
+ ACPI_MODULE_NAME ("numa")
+
+extern int __init acpi_table_parse_madt_family (enum acpi_table_id id, unsigned long madt_size, int entry_id, acpi_madt_entry_handler handler, unsigned int max_entries);
+
+void __init
+acpi_table_print_srat_entry (
+ acpi_table_entry_header *header)
+{
+
+ ACPI_FUNCTION_NAME ("acpi_table_print_srat_entry");
+
+ if (!header)
+ return;
+
+ switch (header->type) {
+
+ case ACPI_SRAT_PROCESSOR_AFFINITY:
+#ifdef ACPI_DEBUG_OUTPUT
+ {
+ struct acpi_table_processor_affinity *p =
+ (struct acpi_table_processor_affinity*) header;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
+ p->apic_id, p->lsapic_eid, p->proximity_domain,
+ p->flags.enabled?"enabled":"disabled"));
+ }
+#endif /* ACPI_DEBUG_OUTPUT */
+ break;
+
+ case ACPI_SRAT_MEMORY_AFFINITY:
+#ifdef ACPI_DEBUG_OUTPUT
+ {
+ struct acpi_table_memory_affinity *p =
+ (struct acpi_table_memory_affinity*) header;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
+ p->base_addr_hi, p->base_addr_lo, p->length_hi, p->length_lo,
+ p->memory_type, p->proximity_domain,
+ p->flags.enabled ? "enabled" : "disabled",
+ p->flags.hot_pluggable ? " hot-pluggable" : ""));
+ }
+#endif /* ACPI_DEBUG_OUTPUT */
+ break;
+
+ default:
+ printk(KERN_WARNING PREFIX "Found unsupported SRAT entry (type = 0x%x)\n",
+ header->type);
+ break;
+ }
+}
+
+
+static int __init
+acpi_parse_slit (unsigned long phys_addr, unsigned long size)
+{
+ struct acpi_table_slit *slit;
+ u32 localities;
+
+ if (!phys_addr || !size)
+ return -EINVAL;
+
+ slit = (struct acpi_table_slit *) __va(phys_addr);
+
+ /* downcast just for %llu vs %lu for i386/ia64 */
+ localities = (u32) slit->localities;
+
+ acpi_numa_slit_init(slit);
+
+ return 0;
+}
+
+
+static int __init
+acpi_parse_processor_affinity (
+ acpi_table_entry_header *header,
+ const unsigned long end)
+{
+ struct acpi_table_processor_affinity *processor_affinity;
+
+ processor_affinity = (struct acpi_table_processor_affinity*) header;
+ if (!processor_affinity)
+ return -EINVAL;
+
+ acpi_table_print_srat_entry(header);
+
+ /* let architecture-dependent part to do it */
+ acpi_numa_processor_affinity_init(processor_affinity);
+
+ return 0;
+}
+
+
+static int __init
+acpi_parse_memory_affinity (
+ acpi_table_entry_header *header,
+ const unsigned long end)
+{
+ struct acpi_table_memory_affinity *memory_affinity;
+
+ memory_affinity = (struct acpi_table_memory_affinity*) header;
+ if (!memory_affinity)
+ return -EINVAL;
+
+ acpi_table_print_srat_entry(header);
+
+ /* let architecture-dependent part to do it */
+ acpi_numa_memory_affinity_init(memory_affinity);
+
+ return 0;
+}
+
+
+static int __init
+acpi_parse_srat (unsigned long phys_addr, unsigned long size)
+{
+ struct acpi_table_srat *srat;
+
+ if (!phys_addr || !size)
+ return -EINVAL;
+
+ srat = (struct acpi_table_srat *) __va(phys_addr);
+
+ return 0;
+}
+
+
+int __init
+acpi_table_parse_srat (
+ enum acpi_srat_entry_id id,
+ acpi_madt_entry_handler handler,
+ unsigned int max_entries)
+{
+ return acpi_table_parse_madt_family(ACPI_SRAT, sizeof(struct acpi_table_srat),
+ id, handler, max_entries);
+}
+
+
+int __init
+acpi_numa_init(void)
+{
+ int result;
+
+ /* SRAT: Static Resource Affinity Table */
+ result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat);
+
+ if (result > 0) {
+ result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
+ acpi_parse_processor_affinity,
+ NR_CPUS);
+ result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY,
+ acpi_parse_memory_affinity,
+ NR_NODE_MEMBLKS); // IA64 specific
+ }
+
+ /* SLIT: System Locality Information Table */
+ result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit);
+
+ acpi_numa_arch_fixup();
+ return 0;
+}
+
+int
+acpi_get_pxm(acpi_handle h)
+{
+ unsigned long pxm;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_handle phandle = h;
+
+ do {
+ handle = phandle;
+ status = acpi_evaluate_integer(handle, "_PXM", NULL, &pxm);
+ if (ACPI_SUCCESS(status))
+ return (int)pxm;
+ status = acpi_get_parent(handle, &phandle);
+ } while(ACPI_SUCCESS(status));
+ return -1;
+}
+EXPORT_SYMBOL(acpi_get_pxm);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
new file mode 100644
index 000000000000..5a9128de6226
--- /dev/null
+++ b/drivers/acpi/osl.c
@@ -0,0 +1,1162 @@
+/*
+ * acpi_osl.c - OS-dependent functions ($Revision: 83 $)
+ *
+ * Copyright (C) 2000 Andrew Henroid
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kmod.h>
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/nmi.h>
+#include <acpi/acpi.h>
+#include <asm/io.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/processor.h>
+#include <asm/uaccess.h>
+
+#include <linux/efi.h>
+
+
+#define _COMPONENT ACPI_OS_SERVICES
+ACPI_MODULE_NAME ("osl")
+
+#define PREFIX "ACPI: "
+
+struct acpi_os_dpc
+{
+ acpi_osd_exec_callback function;
+ void *context;
+};
+
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+#include CONFIG_ACPI_CUSTOM_DSDT_FILE
+#endif
+
+#ifdef ENABLE_DEBUGGER
+#include <linux/kdb.h>
+
+/* stuff for debugger support */
+int acpi_in_debugger;
+EXPORT_SYMBOL(acpi_in_debugger);
+
+extern char line_buf[80];
+#endif /*ENABLE_DEBUGGER*/
+
+static unsigned int acpi_irq_irq;
+static acpi_osd_handler acpi_irq_handler;
+static void *acpi_irq_context;
+static struct workqueue_struct *kacpid_wq;
+
+acpi_status
+acpi_os_initialize(void)
+{
+ return AE_OK;
+}
+
+acpi_status
+acpi_os_initialize1(void)
+{
+ /*
+ * Initialize PCI configuration space access, as we'll need to access
+ * it while walking the namespace (bus 0 and root bridges w/ _BBNs).
+ */
+#ifdef CONFIG_ACPI_PCI
+ if (!raw_pci_ops) {
+ printk(KERN_ERR PREFIX "Access to PCI configuration space unavailable\n");
+ return AE_NULL_ENTRY;
+ }
+#endif
+ kacpid_wq = create_singlethread_workqueue("kacpid");
+ BUG_ON(!kacpid_wq);
+
+ return AE_OK;
+}
+
+acpi_status
+acpi_os_terminate(void)
+{
+ if (acpi_irq_handler) {
+ acpi_os_remove_interrupt_handler(acpi_irq_irq,
+ acpi_irq_handler);
+ }
+
+ destroy_workqueue(kacpid_wq);
+
+ return AE_OK;
+}
+
+void
+acpi_os_printf(const char *fmt,...)
+{
+ va_list args;
+ va_start(args, fmt);
+ acpi_os_vprintf(fmt, args);
+ va_end(args);
+}
+EXPORT_SYMBOL(acpi_os_printf);
+
+void
+acpi_os_vprintf(const char *fmt, va_list args)
+{
+ static char buffer[512];
+
+ vsprintf(buffer, fmt, args);
+
+#ifdef ENABLE_DEBUGGER
+ if (acpi_in_debugger) {
+ kdb_printf("%s", buffer);
+ } else {
+ printk("%s", buffer);
+ }
+#else
+ printk("%s", buffer);
+#endif
+}
+
+void *
+acpi_os_allocate(acpi_size size)
+{
+ return kmalloc(size, GFP_KERNEL);
+}
+
+void
+acpi_os_free(void *ptr)
+{
+ kfree(ptr);
+}
+EXPORT_SYMBOL(acpi_os_free);
+
+acpi_status
+acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
+{
+ if (efi_enabled) {
+ addr->pointer_type = ACPI_PHYSICAL_POINTER;
+ if (efi.acpi20)
+ addr->pointer.physical =
+ (acpi_physical_address) virt_to_phys(efi.acpi20);
+ else if (efi.acpi)
+ addr->pointer.physical =
+ (acpi_physical_address) virt_to_phys(efi.acpi);
+ else {
+ printk(KERN_ERR PREFIX "System description tables not found\n");
+ return AE_NOT_FOUND;
+ }
+ } else {
+ if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
+ printk(KERN_ERR PREFIX "System description tables not found\n");
+ return AE_NOT_FOUND;
+ }
+ }
+
+ return AE_OK;
+}
+
+acpi_status
+acpi_os_map_memory(acpi_physical_address phys, acpi_size size, void __iomem **virt)
+{
+ if (efi_enabled) {
+ if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
+ *virt = (void __iomem *) phys_to_virt(phys);
+ } else {
+ *virt = ioremap(phys, size);
+ }
+ } else {
+ if (phys > ULONG_MAX) {
+ printk(KERN_ERR PREFIX "Cannot map memory that high\n");
+ return AE_BAD_PARAMETER;
+ }
+ /*
+ * ioremap checks to ensure this is in reserved space
+ */
+ *virt = ioremap((unsigned long) phys, size);
+ }
+
+ if (!*virt)
+ return AE_NO_MEMORY;
+
+ return AE_OK;
+}
+
+void
+acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
+{
+ iounmap(virt);
+}
+
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_os_get_physical_address(void *virt, acpi_physical_address *phys)
+{
+ if(!phys || !virt)
+ return AE_BAD_PARAMETER;
+
+ *phys = virt_to_phys(virt);
+
+ return AE_OK;
+}
+#endif
+
+#define ACPI_MAX_OVERRIDE_LEN 100
+
+static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
+
+acpi_status
+acpi_os_predefined_override (const struct acpi_predefined_names *init_val,
+ acpi_string *new_val)
+{
+ if (!init_val || !new_val)
+ return AE_BAD_PARAMETER;
+
+ *new_val = NULL;
+ if (!memcmp (init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
+ printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n",
+ acpi_os_name);
+ *new_val = acpi_os_name;
+ }
+
+ return AE_OK;
+}
+
+acpi_status
+acpi_os_table_override (struct acpi_table_header *existing_table,
+ struct acpi_table_header **new_table)
+{
+ if (!existing_table || !new_table)
+ return AE_BAD_PARAMETER;
+
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
+ if (strncmp(existing_table->signature, "DSDT", 4) == 0)
+ *new_table = (struct acpi_table_header*)AmlCode;
+ else
+ *new_table = NULL;
+#else
+ *new_table = NULL;
+#endif
+ return AE_OK;
+}
+
+static irqreturn_t
+acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ return (*acpi_irq_handler)(acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
+}
+
+acpi_status
+acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, void *context)
+{
+ unsigned int irq;
+
+ /*
+ * Ignore the GSI from the core, and use the value in our copy of the
+ * FADT. It may not be the same if an interrupt source override exists
+ * for the SCI.
+ */
+ gsi = acpi_fadt.sci_int;
+ if (acpi_gsi_to_irq(gsi, &irq) < 0) {
+ printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
+ gsi);
+ return AE_OK;
+ }
+
+ acpi_irq_handler = handler;
+ acpi_irq_context = context;
+ if (request_irq(irq, acpi_irq, SA_SHIRQ, "acpi", acpi_irq)) {
+ printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
+ return AE_NOT_ACQUIRED;
+ }
+ acpi_irq_irq = irq;
+
+ return AE_OK;
+}
+
+acpi_status
+acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
+{
+ if (irq) {
+ free_irq(irq, acpi_irq);
+ acpi_irq_handler = NULL;
+ acpi_irq_irq = 0;
+ }
+
+ return AE_OK;
+}
+
+/*
+ * Running in interpreter thread context, safe to sleep
+ */
+
+void
+acpi_os_sleep(acpi_integer ms)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(((signed long) ms * HZ) / 1000);
+}
+EXPORT_SYMBOL(acpi_os_sleep);
+
+void
+acpi_os_stall(u32 us)
+{
+ while (us) {
+ u32 delay = 1000;
+
+ if (delay > us)
+ delay = us;
+ udelay(delay);
+ touch_nmi_watchdog();
+ us -= delay;
+ }
+}
+EXPORT_SYMBOL(acpi_os_stall);
+
+/*
+ * Support ACPI 3.0 AML Timer operand
+ * Returns 64-bit free-running, monotonically increasing timer
+ * with 100ns granularity
+ */
+u64
+acpi_os_get_timer (void)
+{
+ static u64 t;
+
+#ifdef CONFIG_HPET
+ /* TBD: use HPET if available */
+#endif
+
+#ifdef CONFIG_X86_PM_TIMER
+ /* TBD: default to PM timer if HPET was not available */
+#endif
+ if (!t)
+ printk(KERN_ERR PREFIX "acpi_os_get_timer() TBD\n");
+
+ return ++t;
+}
+
+acpi_status
+acpi_os_read_port(
+ acpi_io_address port,
+ u32 *value,
+ u32 width)
+{
+ u32 dummy;
+
+ if (!value)
+ value = &dummy;
+
+ switch (width)
+ {
+ case 8:
+ *(u8*) value = inb(port);
+ break;
+ case 16:
+ *(u16*) value = inw(port);
+ break;
+ case 32:
+ *(u32*) value = inl(port);
+ break;
+ default:
+ BUG();
+ }
+
+ return AE_OK;
+}
+EXPORT_SYMBOL(acpi_os_read_port);
+
+acpi_status
+acpi_os_write_port(
+ acpi_io_address port,
+ u32 value,
+ u32 width)
+{
+ switch (width)
+ {
+ case 8:
+ outb(value, port);
+ break;
+ case 16:
+ outw(value, port);
+ break;
+ case 32:
+ outl(value, port);
+ break;
+ default:
+ BUG();
+ }
+
+ return AE_OK;
+}
+EXPORT_SYMBOL(acpi_os_write_port);
+
+acpi_status
+acpi_os_read_memory(
+ acpi_physical_address phys_addr,
+ u32 *value,
+ u32 width)
+{
+ u32 dummy;
+ void __iomem *virt_addr;
+ int iomem = 0;
+
+ if (efi_enabled) {
+ if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+ /* HACK ALERT! We can use readb/w/l on real memory too.. */
+ virt_addr = (void __iomem *) phys_to_virt(phys_addr);
+ } else {
+ iomem = 1;
+ virt_addr = ioremap(phys_addr, width);
+ }
+ } else
+ virt_addr = (void __iomem *) phys_to_virt(phys_addr);
+ if (!value)
+ value = &dummy;
+
+ switch (width) {
+ case 8:
+ *(u8*) value = readb(virt_addr);
+ break;
+ case 16:
+ *(u16*) value = readw(virt_addr);
+ break;
+ case 32:
+ *(u32*) value = readl(virt_addr);
+ break;
+ default:
+ BUG();
+ }
+
+ if (efi_enabled) {
+ if (iomem)
+ iounmap(virt_addr);
+ }
+
+ return AE_OK;
+}
+
+acpi_status
+acpi_os_write_memory(
+ acpi_physical_address phys_addr,
+ u32 value,
+ u32 width)
+{
+ void __iomem *virt_addr;
+ int iomem = 0;
+
+ if (efi_enabled) {
+ if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
+ /* HACK ALERT! We can use writeb/w/l on real memory too */
+ virt_addr = (void __iomem *) phys_to_virt(phys_addr);
+ } else {
+ iomem = 1;
+ virt_addr = ioremap(phys_addr, width);
+ }
+ } else
+ virt_addr = (void __iomem *) phys_to_virt(phys_addr);
+
+ switch (width) {
+ case 8:
+ writeb(value, virt_addr);
+ break;
+ case 16:
+ writew(value, virt_addr);
+ break;
+ case 32:
+ writel(value, virt_addr);
+ break;
+ default:
+ BUG();
+ }
+
+ if (iomem)
+ iounmap(virt_addr);
+
+ return AE_OK;
+}
+
+#ifdef CONFIG_ACPI_PCI
+
+acpi_status
+acpi_os_read_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, void *value, u32 width)
+{
+ int result, size;
+
+ if (!value)
+ return AE_BAD_PARAMETER;
+
+ switch (width) {
+ case 8:
+ size = 1;
+ break;
+ case 16:
+ size = 2;
+ break;
+ case 32:
+ size = 4;
+ break;
+ default:
+ return AE_ERROR;
+ }
+
+ BUG_ON(!raw_pci_ops);
+
+ result = raw_pci_ops->read(pci_id->segment, pci_id->bus,
+ PCI_DEVFN(pci_id->device, pci_id->function),
+ reg, size, value);
+
+ return (result ? AE_ERROR : AE_OK);
+}
+EXPORT_SYMBOL(acpi_os_read_pci_configuration);
+
+acpi_status
+acpi_os_write_pci_configuration (struct acpi_pci_id *pci_id, u32 reg, acpi_integer value, u32 width)
+{
+ int result, size;
+
+ switch (width) {
+ case 8:
+ size = 1;
+ break;
+ case 16:
+ size = 2;
+ break;
+ case 32:
+ size = 4;
+ break;
+ default:
+ return AE_ERROR;
+ }
+
+ BUG_ON(!raw_pci_ops);
+
+ result = raw_pci_ops->write(pci_id->segment, pci_id->bus,
+ PCI_DEVFN(pci_id->device, pci_id->function),
+ reg, size, value);
+
+ return (result ? AE_ERROR : AE_OK);
+}
+
+/* TODO: Change code to take advantage of driver model more */
+static void
+acpi_os_derive_pci_id_2 (
+ acpi_handle rhandle, /* upper bound */
+ acpi_handle chandle, /* current node */
+ struct acpi_pci_id **id,
+ int *is_bridge,
+ u8 *bus_number)
+{
+ acpi_handle handle;
+ struct acpi_pci_id *pci_id = *id;
+ acpi_status status;
+ unsigned long temp;
+ acpi_object_type type;
+ u8 tu8;
+
+ acpi_get_parent(chandle, &handle);
+ if (handle != rhandle) {
+ acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge, bus_number);
+
+ status = acpi_get_type(handle, &type);
+ if ( (ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE) )
+ return;
+
+ status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &temp);
+ if (ACPI_SUCCESS(status)) {
+ pci_id->device = ACPI_HIWORD (ACPI_LODWORD (temp));
+ pci_id->function = ACPI_LOWORD (ACPI_LODWORD (temp));
+
+ if (*is_bridge)
+ pci_id->bus = *bus_number;
+
+ /* any nicer way to get bus number of bridge ? */
+ status = acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8, 8);
+ if (ACPI_SUCCESS(status) &&
+ ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) {
+ status = acpi_os_read_pci_configuration(pci_id, 0x18, &tu8, 8);
+ if (!ACPI_SUCCESS(status)) {
+ /* Certainly broken... FIX ME */
+ return;
+ }
+ *is_bridge = 1;
+ pci_id->bus = tu8;
+ status = acpi_os_read_pci_configuration(pci_id, 0x19, &tu8, 8);
+ if (ACPI_SUCCESS(status)) {
+ *bus_number = tu8;
+ }
+ } else
+ *is_bridge = 0;
+ }
+ }
+}
+
+void
+acpi_os_derive_pci_id (
+ acpi_handle rhandle, /* upper bound */
+ acpi_handle chandle, /* current node */
+ struct acpi_pci_id **id)
+{
+ int is_bridge = 1;
+ u8 bus_number = (*id)->bus;
+
+ acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
+}
+
+#else /*!CONFIG_ACPI_PCI*/
+
+acpi_status
+acpi_os_write_pci_configuration (
+ struct acpi_pci_id *pci_id,
+ u32 reg,
+ acpi_integer value,
+ u32 width)
+{
+ return AE_SUPPORT;
+}
+
+acpi_status
+acpi_os_read_pci_configuration (
+ struct acpi_pci_id *pci_id,
+ u32 reg,
+ void *value,
+ u32 width)
+{
+ return AE_SUPPORT;
+}
+
+void
+acpi_os_derive_pci_id (
+ acpi_handle rhandle, /* upper bound */
+ acpi_handle chandle, /* current node */
+ struct acpi_pci_id **id)
+{
+}
+
+#endif /*CONFIG_ACPI_PCI*/
+
+static void
+acpi_os_execute_deferred (
+ void *context)
+{
+ struct acpi_os_dpc *dpc = NULL;
+
+ ACPI_FUNCTION_TRACE ("os_execute_deferred");
+
+ dpc = (struct acpi_os_dpc *) context;
+ if (!dpc) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
+ return_VOID;
+ }
+
+ dpc->function(dpc->context);
+
+ kfree(dpc);
+
+ return_VOID;
+}
+
+acpi_status
+acpi_os_queue_for_execution(
+ u32 priority,
+ acpi_osd_exec_callback function,
+ void *context)
+{
+ acpi_status status = AE_OK;
+ struct acpi_os_dpc *dpc;
+ struct work_struct *task;
+
+ ACPI_FUNCTION_TRACE ("os_queue_for_execution");
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Scheduling function [%p(%p)] for deferred execution.\n", function, context));
+
+ if (!function)
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+ /*
+ * Allocate/initialize DPC structure. Note that this memory will be
+ * freed by the callee. The kernel handles the tq_struct list in a
+ * way that allows us to also free its memory inside the callee.
+ * Because we may want to schedule several tasks with different
+ * parameters we can't use the approach some kernel code uses of
+ * having a static tq_struct.
+ * We can save time and code by allocating the DPC and tq_structs
+ * from the same memory.
+ */
+
+ dpc = kmalloc(sizeof(struct acpi_os_dpc)+sizeof(struct work_struct), GFP_ATOMIC);
+ if (!dpc)
+ return_ACPI_STATUS (AE_NO_MEMORY);
+
+ dpc->function = function;
+ dpc->context = context;
+
+ task = (void *)(dpc+1);
+ INIT_WORK(task, acpi_os_execute_deferred, (void*)dpc);
+
+ if (!queue_work(kacpid_wq, task)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to queue_work() failed.\n"));
+ kfree(dpc);
+ status = AE_ERROR;
+ }
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_os_queue_for_execution);
+
+void
+acpi_os_wait_events_complete(
+ void *context)
+{
+ flush_workqueue(kacpid_wq);
+}
+EXPORT_SYMBOL(acpi_os_wait_events_complete);
+
+/*
+ * Allocate the memory for a spinlock and initialize it.
+ */
+acpi_status
+acpi_os_create_lock (
+ acpi_handle *out_handle)
+{
+ spinlock_t *lock_ptr;
+
+ ACPI_FUNCTION_TRACE ("os_create_lock");
+
+ lock_ptr = acpi_os_allocate(sizeof(spinlock_t));
+
+ spin_lock_init(lock_ptr);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Creating spinlock[%p].\n", lock_ptr));
+
+ *out_handle = lock_ptr;
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*
+ * Deallocate the memory for a spinlock.
+ */
+void
+acpi_os_delete_lock (
+ acpi_handle handle)
+{
+ ACPI_FUNCTION_TRACE ("os_create_lock");
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Deleting spinlock[%p].\n", handle));
+
+ acpi_os_free(handle);
+
+ return_VOID;
+}
+
+/*
+ * Acquire a spinlock.
+ *
+ * handle is a pointer to the spinlock_t.
+ * flags is *not* the result of save_flags - it is an ACPI-specific flag variable
+ * that indicates whether we are at interrupt level.
+ */
+void
+acpi_os_acquire_lock (
+ acpi_handle handle,
+ u32 flags)
+{
+ ACPI_FUNCTION_TRACE ("os_acquire_lock");
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Acquiring spinlock[%p] from %s level\n", handle,
+ ((flags & ACPI_NOT_ISR) ? "non-interrupt" : "interrupt")));
+
+ if (flags & ACPI_NOT_ISR)
+ ACPI_DISABLE_IRQS();
+
+ spin_lock((spinlock_t *)handle);
+
+ return_VOID;
+}
+
+
+/*
+ * Release a spinlock. See above.
+ */
+void
+acpi_os_release_lock (
+ acpi_handle handle,
+ u32 flags)
+{
+ ACPI_FUNCTION_TRACE ("os_release_lock");
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Releasing spinlock[%p] from %s level\n", handle,
+ ((flags & ACPI_NOT_ISR) ? "non-interrupt" : "interrupt")));
+
+ spin_unlock((spinlock_t *)handle);
+
+ if (flags & ACPI_NOT_ISR)
+ ACPI_ENABLE_IRQS();
+
+ return_VOID;
+}
+
+
+acpi_status
+acpi_os_create_semaphore(
+ u32 max_units,
+ u32 initial_units,
+ acpi_handle *handle)
+{
+ struct semaphore *sem = NULL;
+
+ ACPI_FUNCTION_TRACE ("os_create_semaphore");
+
+ sem = acpi_os_allocate(sizeof(struct semaphore));
+ if (!sem)
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ memset(sem, 0, sizeof(struct semaphore));
+
+ sema_init(sem, initial_units);
+
+ *handle = (acpi_handle*)sem;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n", *handle, initial_units));
+
+ return_ACPI_STATUS (AE_OK);
+}
+EXPORT_SYMBOL(acpi_os_create_semaphore);
+
+
+/*
+ * TODO: A better way to delete semaphores? Linux doesn't have a
+ * 'delete_semaphore()' function -- may result in an invalid
+ * pointer dereference for non-synchronized consumers. Should
+ * we at least check for blocked threads and signal/cancel them?
+ */
+
+acpi_status
+acpi_os_delete_semaphore(
+ acpi_handle handle)
+{
+ struct semaphore *sem = (struct semaphore*) handle;
+
+ ACPI_FUNCTION_TRACE ("os_delete_semaphore");
+
+ if (!sem)
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle));
+
+ acpi_os_free(sem); sem = NULL;
+
+ return_ACPI_STATUS (AE_OK);
+}
+EXPORT_SYMBOL(acpi_os_delete_semaphore);
+
+
+/*
+ * TODO: The kernel doesn't have a 'down_timeout' function -- had to
+ * improvise. The process is to sleep for one scheduler quantum
+ * until the semaphore becomes available. Downside is that this
+ * may result in starvation for timeout-based waits when there's
+ * lots of semaphore activity.
+ *
+ * TODO: Support for units > 1?
+ */
+acpi_status
+acpi_os_wait_semaphore(
+ acpi_handle handle,
+ u32 units,
+ u16 timeout)
+{
+ acpi_status status = AE_OK;
+ struct semaphore *sem = (struct semaphore*)handle;
+ int ret = 0;
+
+ ACPI_FUNCTION_TRACE ("os_wait_semaphore");
+
+ if (!sem || (units < 1))
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+ if (units > 1)
+ return_ACPI_STATUS (AE_SUPPORT);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout));
+
+ if (in_atomic())
+ timeout = 0;
+
+ switch (timeout)
+ {
+ /*
+ * No Wait:
+ * --------
+ * A zero timeout value indicates that we shouldn't wait - just
+ * acquire the semaphore if available otherwise return AE_TIME
+ * (a.k.a. 'would block').
+ */
+ case 0:
+ if(down_trylock(sem))
+ status = AE_TIME;
+ break;
+
+ /*
+ * Wait Indefinitely:
+ * ------------------
+ */
+ case ACPI_WAIT_FOREVER:
+ down(sem);
+ break;
+
+ /*
+ * Wait w/ Timeout:
+ * ----------------
+ */
+ default:
+ // TODO: A better timeout algorithm?
+ {
+ int i = 0;
+ static const int quantum_ms = 1000/HZ;
+
+ ret = down_trylock(sem);
+ for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(1);
+ ret = down_trylock(sem);
+ }
+
+ if (ret != 0)
+ status = AE_TIME;
+ }
+ break;
+ }
+
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Failed to acquire semaphore[%p|%d|%d], %s\n",
+ handle, units, timeout, acpi_format_exception(status)));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Acquired semaphore[%p|%d|%d]\n", handle, units, timeout));
+ }
+
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_os_wait_semaphore);
+
+
+/*
+ * TODO: Support for units > 1?
+ */
+acpi_status
+acpi_os_signal_semaphore(
+ acpi_handle handle,
+ u32 units)
+{
+ struct semaphore *sem = (struct semaphore *) handle;
+
+ ACPI_FUNCTION_TRACE ("os_signal_semaphore");
+
+ if (!sem || (units < 1))
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+
+ if (units > 1)
+ return_ACPI_STATUS (AE_SUPPORT);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle, units));
+
+ up(sem);
+
+ return_ACPI_STATUS (AE_OK);
+}
+EXPORT_SYMBOL(acpi_os_signal_semaphore);
+
+#ifdef ACPI_FUTURE_USAGE
+u32
+acpi_os_get_line(char *buffer)
+{
+
+#ifdef ENABLE_DEBUGGER
+ if (acpi_in_debugger) {
+ u32 chars;
+
+ kdb_read(buffer, sizeof(line_buf));
+
+ /* remove the CR kdb includes */
+ chars = strlen(buffer) - 1;
+ buffer[chars] = '\0';
+ }
+#endif
+
+ return 0;
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+/* Assumes no unreadable holes inbetween */
+u8
+acpi_os_readable(void *ptr, acpi_size len)
+{
+#if defined(__i386__) || defined(__x86_64__)
+ char tmp;
+ return !__get_user(tmp, (char __user *)ptr) && !__get_user(tmp, (char __user *)ptr + len - 1);
+#endif
+ return 1;
+}
+
+#ifdef ACPI_FUTURE_USAGE
+u8
+acpi_os_writable(void *ptr, acpi_size len)
+{
+ /* could do dummy write (racy) or a kernel page table lookup.
+ The later may be difficult at early boot when kmap doesn't work yet. */
+ return 1;
+}
+#endif
+
+u32
+acpi_os_get_thread_id (void)
+{
+ if (!in_atomic())
+ return current->pid;
+
+ return 0;
+}
+
+acpi_status
+acpi_os_signal (
+ u32 function,
+ void *info)
+{
+ switch (function)
+ {
+ case ACPI_SIGNAL_FATAL:
+ printk(KERN_ERR PREFIX "Fatal opcode executed\n");
+ break;
+ case ACPI_SIGNAL_BREAKPOINT:
+ /*
+ * AML Breakpoint
+ * ACPI spec. says to treat it as a NOP unless
+ * you are debugging. So if/when we integrate
+ * AML debugger into the kernel debugger its
+ * hook will go here. But until then it is
+ * not useful to print anything on breakpoints.
+ */
+ break;
+ default:
+ break;
+ }
+
+ return AE_OK;
+}
+EXPORT_SYMBOL(acpi_os_signal);
+
+static int __init
+acpi_os_name_setup(char *str)
+{
+ char *p = acpi_os_name;
+ int count = ACPI_MAX_OVERRIDE_LEN-1;
+
+ if (!str || !*str)
+ return 0;
+
+ for (; count-- && str && *str; str++) {
+ if (isalnum(*str) || *str == ' ' || *str == ':')
+ *p++ = *str;
+ else if (*str == '\'' || *str == '"')
+ continue;
+ else
+ break;
+ }
+ *p = 0;
+
+ return 1;
+
+}
+
+__setup("acpi_os_name=", acpi_os_name_setup);
+
+/*
+ * _OSI control
+ * empty string disables _OSI
+ * TBD additional string adds to _OSI
+ */
+static int __init
+acpi_osi_setup(char *str)
+{
+ if (str == NULL || *str == '\0') {
+ printk(KERN_INFO PREFIX "_OSI method disabled\n");
+ acpi_gbl_create_osi_method = FALSE;
+ } else
+ {
+ /* TBD */
+ printk(KERN_ERR PREFIX "_OSI additional string ignored -- %s\n", str);
+ }
+
+ return 1;
+}
+
+__setup("acpi_osi=", acpi_osi_setup);
+
+/* enable serialization to combat AE_ALREADY_EXISTS errors */
+static int __init
+acpi_serialize_setup(char *str)
+{
+ printk(KERN_INFO PREFIX "serialize enabled\n");
+
+ acpi_gbl_all_methods_serialized = TRUE;
+
+ return 1;
+}
+
+__setup("acpi_serialize", acpi_serialize_setup);
+
+/*
+ * Wake and Run-Time GPES are expected to be separate.
+ * We disable wake-GPEs at run-time to prevent spurious
+ * interrupts.
+ *
+ * However, if a system exists that shares Wake and
+ * Run-time events on the same GPE this flag is available
+ * to tell Linux to keep the wake-time GPEs enabled at run-time.
+ */
+static int __init
+acpi_wake_gpes_always_on_setup(char *str)
+{
+ printk(KERN_INFO PREFIX "wake GPEs not disabled\n");
+
+ acpi_gbl_leave_wake_gpes_disabled = FALSE;
+
+ return 1;
+}
+
+__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
+
+/*
+ * max_cstate is defined in the base kernel so modules can
+ * change it w/o depending on the state of the processor module.
+ */
+unsigned int max_cstate = ACPI_PROCESSOR_MAX_POWER;
+
+
+EXPORT_SYMBOL(max_cstate);
diff --git a/drivers/acpi/parser/Makefile b/drivers/acpi/parser/Makefile
new file mode 100644
index 000000000000..bbdd286c660d
--- /dev/null
+++ b/drivers/acpi/parser/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := psargs.o psparse.o pstree.o pswalk.o \
+ psopcode.o psscope.o psutils.o psxface.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
new file mode 100644
index 000000000000..b5d98895f6a8
--- /dev/null
+++ b/drivers/acpi/parser/psargs.c
@@ -0,0 +1,746 @@
+/******************************************************************************
+ *
+ * Module Name: psargs - Parse AML opcode arguments
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("psargs")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_package_length
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Decoded package length. On completion, the AML pointer points
+ * past the length byte or bytes.
+ *
+ * DESCRIPTION: Decode and return a package length field
+ *
+ ******************************************************************************/
+
+u32
+acpi_ps_get_next_package_length (
+ struct acpi_parse_state *parser_state)
+{
+ u32 encoded_length;
+ u32 length = 0;
+
+
+ ACPI_FUNCTION_TRACE ("ps_get_next_package_length");
+
+
+ encoded_length = (u32) ACPI_GET8 (parser_state->aml);
+ parser_state->aml++;
+
+
+ switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */ {
+ case 0: /* 1-byte encoding (bits 0-5) */
+
+ length = (encoded_length & 0x3F);
+ break;
+
+
+ case 1: /* 2-byte encoding (next byte + bits 0-3) */
+
+ length = ((ACPI_GET8 (parser_state->aml) << 04) |
+ (encoded_length & 0x0F));
+ parser_state->aml++;
+ break;
+
+
+ case 2: /* 3-byte encoding (next 2 bytes + bits 0-3) */
+
+ length = ((ACPI_GET8 (parser_state->aml + 1) << 12) |
+ (ACPI_GET8 (parser_state->aml) << 04) |
+ (encoded_length & 0x0F));
+ parser_state->aml += 2;
+ break;
+
+
+ case 3: /* 4-byte encoding (next 3 bytes + bits 0-3) */
+
+ length = ((ACPI_GET8 (parser_state->aml + 2) << 20) |
+ (ACPI_GET8 (parser_state->aml + 1) << 12) |
+ (ACPI_GET8 (parser_state->aml) << 04) |
+ (encoded_length & 0x0F));
+ parser_state->aml += 3;
+ break;
+
+ default:
+
+ /* Can't get here, only 2 bits / 4 cases */
+ break;
+ }
+
+ return_VALUE (length);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_package_end
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Pointer to end-of-package +1
+ *
+ * DESCRIPTION: Get next package length and return a pointer past the end of
+ * the package. Consumes the package length field
+ *
+ ******************************************************************************/
+
+u8 *
+acpi_ps_get_next_package_end (
+ struct acpi_parse_state *parser_state)
+{
+ u8 *start = parser_state->aml;
+ acpi_native_uint length;
+
+
+ ACPI_FUNCTION_TRACE ("ps_get_next_package_end");
+
+
+ /* Function below changes parser_state->Aml */
+
+ length = (acpi_native_uint) acpi_ps_get_next_package_length (parser_state);
+
+ return_PTR (start + length); /* end of package */
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_namestring
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Pointer to the start of the name string (pointer points into
+ * the AML.
+ *
+ * DESCRIPTION: Get next raw namestring within the AML stream. Handles all name
+ * prefix characters. Set parser state to point past the string.
+ * (Name is consumed from the AML.)
+ *
+ ******************************************************************************/
+
+char *
+acpi_ps_get_next_namestring (
+ struct acpi_parse_state *parser_state)
+{
+ u8 *start = parser_state->aml;
+ u8 *end = parser_state->aml;
+
+
+ ACPI_FUNCTION_TRACE ("ps_get_next_namestring");
+
+
+ /* Handle multiple prefix characters */
+
+ while (acpi_ps_is_prefix_char (ACPI_GET8 (end))) {
+ /* Include prefix '\\' or '^' */
+
+ end++;
+ }
+
+ /* Decode the path */
+
+ switch (ACPI_GET8 (end)) {
+ case 0:
+
+ /* null_name */
+
+ if (end == start) {
+ start = NULL;
+ }
+ end++;
+ break;
+
+ case AML_DUAL_NAME_PREFIX:
+
+ /* Two name segments */
+
+ end += 1 + (2 * ACPI_NAME_SIZE);
+ break;
+
+ case AML_MULTI_NAME_PREFIX_OP:
+
+ /* Multiple name segments, 4 chars each */
+
+ end += 2 + ((acpi_size) ACPI_GET8 (end + 1) * ACPI_NAME_SIZE);
+ break;
+
+ default:
+
+ /* Single name segment */
+
+ end += ACPI_NAME_SIZE;
+ break;
+ }
+
+ parser_state->aml = (u8*) end;
+ return_PTR ((char *) start);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_namepath
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ * Arg - Where the namepath will be stored
+ * arg_count - If the namepath points to a control method
+ * the method's argument is returned here.
+ * method_call - Whether the namepath can possibly be the
+ * start of a method call
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get next name (if method call, return # of required args).
+ * Names are looked up in the internal namespace to determine
+ * if the name represents a control method. If a method
+ * is found, the number of arguments to the method is returned.
+ * This information is critical for parsing to continue correctly.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_get_next_namepath (
+ struct acpi_walk_state *walk_state,
+ struct acpi_parse_state *parser_state,
+ union acpi_parse_object *arg,
+ u8 method_call)
+{
+ char *path;
+ union acpi_parse_object *name_op;
+ acpi_status status = AE_OK;
+ union acpi_operand_object *method_desc;
+ struct acpi_namespace_node *node;
+ union acpi_generic_state scope_info;
+
+
+ ACPI_FUNCTION_TRACE ("ps_get_next_namepath");
+
+
+ path = acpi_ps_get_next_namestring (parser_state);
+
+ /* Null path case is allowed */
+
+ if (path) {
+ /*
+ * Lookup the name in the internal namespace
+ */
+ scope_info.scope.node = NULL;
+ node = parser_state->start_node;
+ if (node) {
+ scope_info.scope.node = node;
+ }
+
+ /*
+ * Lookup object. We don't want to add anything new to the namespace
+ * here, however. So we use MODE_EXECUTE. Allow searching of the
+ * parent tree, but don't open a new scope -- we just want to lookup the
+ * object (MUST BE mode EXECUTE to perform upsearch)
+ */
+ status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node);
+ if (ACPI_SUCCESS (status) && method_call) {
+ if (node->type == ACPI_TYPE_METHOD) {
+ /*
+ * This name is actually a control method invocation
+ */
+ method_desc = acpi_ns_get_attached_object (node);
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "Control Method - %p Desc %p Path=%p\n",
+ node, method_desc, path));
+
+ name_op = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP);
+ if (!name_op) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Change arg into a METHOD CALL and attach name to it */
+
+ acpi_ps_init_op (arg, AML_INT_METHODCALL_OP);
+ name_op->common.value.name = path;
+
+ /* Point METHODCALL/NAME to the METHOD Node */
+
+ name_op->common.node = node;
+ acpi_ps_append_arg (arg, name_op);
+
+ if (!method_desc) {
+ ACPI_REPORT_ERROR ((
+ "ps_get_next_namepath: Control Method %p has no attached object\n",
+ node));
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "Control Method - %p Args %X\n",
+ node, method_desc->method.param_count));
+
+ /* Get the number of arguments to expect */
+
+ walk_state->arg_count = method_desc->method.param_count;
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Else this is normal named object reference.
+ * Just init the NAMEPATH object with the pathname.
+ * (See code below)
+ */
+ }
+
+ if (ACPI_FAILURE (status)) {
+ /*
+ * 1) Any error other than NOT_FOUND is always severe
+ * 2) NOT_FOUND is only important if we are executing a method.
+ * 3) If executing a cond_ref_of opcode, NOT_FOUND is ok.
+ */
+ if ((((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) &&
+ (status == AE_NOT_FOUND) &&
+ (walk_state->op->common.aml_opcode != AML_COND_REF_OF_OP)) ||
+
+ (status != AE_NOT_FOUND)) {
+ ACPI_REPORT_NSERROR (path, status);
+
+ acpi_os_printf ("search_node %p start_node %p return_node %p\n",
+ scope_info.scope.node, parser_state->start_node, node);
+
+
+ }
+ else {
+ /*
+ * We got a NOT_FOUND during table load or we encountered
+ * a cond_ref_of(x) where the target does not exist.
+ * -- either case is ok
+ */
+ status = AE_OK;
+ }
+ }
+ }
+
+ /*
+ * Regardless of success/failure above,
+ * Just initialize the Op with the pathname.
+ */
+ acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP);
+ arg->common.value.name = path;
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_simple_arg
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ * arg_type - The argument type (AML_*_ARG)
+ * Arg - Where the argument is returned
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Get the next simple argument (constant, string, or namestring)
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_get_next_simple_arg (
+ struct acpi_parse_state *parser_state,
+ u32 arg_type,
+ union acpi_parse_object *arg)
+{
+
+ ACPI_FUNCTION_TRACE_U32 ("ps_get_next_simple_arg", arg_type);
+
+
+ switch (arg_type) {
+ case ARGP_BYTEDATA:
+
+ acpi_ps_init_op (arg, AML_BYTE_OP);
+ arg->common.value.integer = (u32) ACPI_GET8 (parser_state->aml);
+ parser_state->aml++;
+ break;
+
+
+ case ARGP_WORDDATA:
+
+ acpi_ps_init_op (arg, AML_WORD_OP);
+
+ /* Get 2 bytes from the AML stream */
+
+ ACPI_MOVE_16_TO_32 (&arg->common.value.integer, parser_state->aml);
+ parser_state->aml += 2;
+ break;
+
+
+ case ARGP_DWORDDATA:
+
+ acpi_ps_init_op (arg, AML_DWORD_OP);
+
+ /* Get 4 bytes from the AML stream */
+
+ ACPI_MOVE_32_TO_32 (&arg->common.value.integer, parser_state->aml);
+ parser_state->aml += 4;
+ break;
+
+
+ case ARGP_QWORDDATA:
+
+ acpi_ps_init_op (arg, AML_QWORD_OP);
+
+ /* Get 8 bytes from the AML stream */
+
+ ACPI_MOVE_64_TO_64 (&arg->common.value.integer, parser_state->aml);
+ parser_state->aml += 8;
+ break;
+
+
+ case ARGP_CHARLIST:
+
+ acpi_ps_init_op (arg, AML_STRING_OP);
+ arg->common.value.string = (char *) parser_state->aml;
+
+ while (ACPI_GET8 (parser_state->aml) != '\0') {
+ parser_state->aml++;
+ }
+ parser_state->aml++;
+ break;
+
+
+ case ARGP_NAME:
+ case ARGP_NAMESTRING:
+
+ acpi_ps_init_op (arg, AML_INT_NAMEPATH_OP);
+ arg->common.value.name = acpi_ps_get_next_namestring (parser_state);
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("Invalid arg_type %X\n", arg_type));
+ break;
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_field
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: A newly allocated FIELD op
+ *
+ * DESCRIPTION: Get next field (named_field, reserved_field, or access_field)
+ *
+ ******************************************************************************/
+
+union acpi_parse_object *
+acpi_ps_get_next_field (
+ struct acpi_parse_state *parser_state)
+{
+ u32 aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml,
+ parser_state->aml_start);
+ union acpi_parse_object *field;
+ u16 opcode;
+ u32 name;
+
+
+ ACPI_FUNCTION_TRACE ("ps_get_next_field");
+
+
+ /* determine field type */
+
+ switch (ACPI_GET8 (parser_state->aml)) {
+ default:
+
+ opcode = AML_INT_NAMEDFIELD_OP;
+ break;
+
+ case 0x00:
+
+ opcode = AML_INT_RESERVEDFIELD_OP;
+ parser_state->aml++;
+ break;
+
+ case 0x01:
+
+ opcode = AML_INT_ACCESSFIELD_OP;
+ parser_state->aml++;
+ break;
+ }
+
+
+ /* Allocate a new field op */
+
+ field = acpi_ps_alloc_op (opcode);
+ if (!field) {
+ return_PTR (NULL);
+ }
+
+ field->common.aml_offset = aml_offset;
+
+ /* Decode the field type */
+
+ switch (opcode) {
+ case AML_INT_NAMEDFIELD_OP:
+
+ /* Get the 4-character name */
+
+ ACPI_MOVE_32_TO_32 (&name, parser_state->aml);
+ acpi_ps_set_name (field, name);
+ parser_state->aml += ACPI_NAME_SIZE;
+
+ /* Get the length which is encoded as a package length */
+
+ field->common.value.size = acpi_ps_get_next_package_length (parser_state);
+ break;
+
+
+ case AML_INT_RESERVEDFIELD_OP:
+
+ /* Get the length which is encoded as a package length */
+
+ field->common.value.size = acpi_ps_get_next_package_length (parser_state);
+ break;
+
+
+ case AML_INT_ACCESSFIELD_OP:
+
+ /*
+ * Get access_type and access_attrib and merge into the field Op
+ * access_type is first operand, access_attribute is second
+ */
+ field->common.value.integer = (ACPI_GET8 (parser_state->aml) << 8);
+ parser_state->aml++;
+ field->common.value.integer |= ACPI_GET8 (parser_state->aml);
+ parser_state->aml++;
+ break;
+
+ default:
+
+ /* Opcode was set in previous switch */
+ break;
+ }
+
+ return_PTR (field);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_next_arg
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ * arg_type - The argument type (AML_*_ARG)
+ * arg_count - If the argument points to a control method
+ * the method's argument is returned here.
+ *
+ * RETURN: Status, and an op object containing the next argument.
+ *
+ * DESCRIPTION: Get next argument (including complex list arguments that require
+ * pushing the parser stack)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_get_next_arg (
+ struct acpi_walk_state *walk_state,
+ struct acpi_parse_state *parser_state,
+ u32 arg_type,
+ union acpi_parse_object **return_arg)
+{
+ union acpi_parse_object *arg = NULL;
+ union acpi_parse_object *prev = NULL;
+ union acpi_parse_object *field;
+ u32 subop;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_get_next_arg", parser_state);
+
+
+ switch (arg_type) {
+ case ARGP_BYTEDATA:
+ case ARGP_WORDDATA:
+ case ARGP_DWORDDATA:
+ case ARGP_CHARLIST:
+ case ARGP_NAME:
+ case ARGP_NAMESTRING:
+
+ /* constants, strings, and namestrings are all the same size */
+
+ arg = acpi_ps_alloc_op (AML_BYTE_OP);
+ if (!arg) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+ acpi_ps_get_next_simple_arg (parser_state, arg_type, arg);
+ break;
+
+
+ case ARGP_PKGLENGTH:
+
+ /* Package length, nothing returned */
+
+ parser_state->pkg_end = acpi_ps_get_next_package_end (parser_state);
+ break;
+
+
+ case ARGP_FIELDLIST:
+
+ if (parser_state->aml < parser_state->pkg_end) {
+ /* Non-empty list */
+
+ while (parser_state->aml < parser_state->pkg_end) {
+ field = acpi_ps_get_next_field (parser_state);
+ if (!field) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ if (prev) {
+ prev->common.next = field;
+ }
+ else {
+ arg = field;
+ }
+
+ prev = field;
+ }
+
+ /* Skip to End of byte data */
+
+ parser_state->aml = parser_state->pkg_end;
+ }
+ break;
+
+
+ case ARGP_BYTELIST:
+
+ if (parser_state->aml < parser_state->pkg_end) {
+ /* Non-empty list */
+
+ arg = acpi_ps_alloc_op (AML_INT_BYTELIST_OP);
+ if (!arg) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Fill in bytelist data */
+
+ arg->common.value.size = (u32) ACPI_PTR_DIFF (parser_state->pkg_end,
+ parser_state->aml);
+ arg->named.data = parser_state->aml;
+
+ /* Skip to End of byte data */
+
+ parser_state->aml = parser_state->pkg_end;
+ }
+ break;
+
+
+ case ARGP_TARGET:
+ case ARGP_SUPERNAME:
+ case ARGP_SIMPLENAME:
+
+ subop = acpi_ps_peek_opcode (parser_state);
+ if (subop == 0 ||
+ acpi_ps_is_leading_char (subop) ||
+ acpi_ps_is_prefix_char (subop)) {
+ /* null_name or name_string */
+
+ arg = acpi_ps_alloc_op (AML_INT_NAMEPATH_OP);
+ if (!arg) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ status = acpi_ps_get_next_namepath (walk_state, parser_state, arg, 0);
+ }
+ else {
+ /* single complex argument, nothing returned */
+
+ walk_state->arg_count = 1;
+ }
+ break;
+
+
+ case ARGP_DATAOBJ:
+ case ARGP_TERMARG:
+
+ /* single complex argument, nothing returned */
+
+ walk_state->arg_count = 1;
+ break;
+
+
+ case ARGP_DATAOBJLIST:
+ case ARGP_TERMLIST:
+ case ARGP_OBJLIST:
+
+ if (parser_state->aml < parser_state->pkg_end) {
+ /* non-empty list of variable arguments, nothing returned */
+
+ walk_state->arg_count = ACPI_VAR_ARGS;
+ }
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("Invalid arg_type: %X\n", arg_type));
+ status = AE_AML_OPERAND_TYPE;
+ break;
+ }
+
+ *return_arg = arg;
+ return_ACPI_STATUS (status);
+}
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
new file mode 100644
index 000000000000..03e33fedc11a
--- /dev/null
+++ b/drivers/acpi/parser/psopcode.c
@@ -0,0 +1,778 @@
+/******************************************************************************
+ *
+ * Module Name: psopcode - Parser/Interpreter opcode information table
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("psopcode")
+
+
+#define _UNK 0x6B
+/*
+ * Reserved ASCII characters. Do not use any of these for
+ * internal opcodes, since they are used to differentiate
+ * name strings from AML opcodes
+ */
+#define _ASC 0x6C
+#define _NAM 0x6C
+#define _PFX 0x6D
+#define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */
+
+#define MAX_EXTENDED_OPCODE 0x88
+#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1)
+#define MAX_INTERNAL_OPCODE
+#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1)
+
+
+/*******************************************************************************
+ *
+ * NAME: acpi_gbl_aml_op_info
+ *
+ * DESCRIPTION: Opcode table. Each entry contains <opcode, type, name, operands>
+ * The name is a simple ascii string, the operand specifier is an
+ * ascii string with one letter per operand. The letter specifies
+ * the operand type.
+ *
+ ******************************************************************************/
+
+
+/*
+ * All AML opcodes and the parse-time arguments for each. Used by the AML parser Each list is compressed
+ * into a 32-bit number and stored in the master opcode table at the end of this file.
+ */
+
+
+#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA)
+#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME)
+#define ARGP_ARG0 ARG_NONE
+#define ARGP_ARG1 ARG_NONE
+#define ARGP_ARG2 ARG_NONE
+#define ARGP_ARG3 ARG_NONE
+#define ARGP_ARG4 ARG_NONE
+#define ARGP_ARG5 ARG_NONE
+#define ARGP_ARG6 ARG_NONE
+#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BREAK_OP ARG_NONE
+#define ARGP_BREAK_POINT_OP ARG_NONE
+#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST)
+#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA)
+#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME)
+#define ARGP_CONTINUE_OP ARG_NONE
+#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME)
+#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_DEBUG_OP ARG_NONE
+#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET)
+#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA)
+#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST)
+#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME)
+#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG)
+#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME)
+#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LOCAL0 ARG_NONE
+#define ARGP_LOCAL1 ARG_NONE
+#define ARGP_LOCAL2 ARG_NONE
+#define ARGP_LOCAL3 ARG_NONE
+#define ARGP_LOCAL4 ARG_NONE
+#define ARGP_LOCAL5 ARG_NONE
+#define ARGP_LOCAL6 ARG_NONE
+#define ARGP_LOCAL7 ARG_NONE
+#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST)
+#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA)
+#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ)
+#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_NOOP_OP ARG_NONE
+#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_ONE_OP ARG_NONE
+#define ARGP_ONES_OP ARG_NONE
+#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST)
+#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST)
+#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST)
+#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA)
+#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_REVISION_OP ARG_NONE
+#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST)
+#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME)
+#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST)
+#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_TIMER_OP ARG_NONE
+#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST)
+#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA)
+#define ARGP_ZERO_OP ARG_NONE
+
+
+/*
+ * All AML opcodes and the runtime arguments for each. Used by the AML interpreter Each list is compressed
+ * into a 32-bit number and stored in the master opcode table at the end of this file.
+ *
+ * (Used by prep_operands procedure and the ASL Compiler)
+ */
+
+
+#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER)
+#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE
+#define ARGI_ARG0 ARG_NONE
+#define ARGI_ARG1 ARG_NONE
+#define ARGI_ARG2 ARG_NONE
+#define ARGI_ARG3 ARG_NONE
+#define ARGI_ARG4 ARG_NONE
+#define ARGI_ARG5 ARG_NONE
+#define ARGI_ARG6 ARG_NONE
+#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BREAK_OP ARG_NONE
+#define ARGI_BREAK_POINT_OP ARG_NONE
+#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_BYTE_OP ARGI_INVALID_OPCODE
+#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE
+#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF)
+#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF)
+#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF)
+#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE
+#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET)
+#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_FIELD_OP ARGI_LIST4 (ARGI_BUFFER, ARGI_INTEGER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_QWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_WORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_DATA_REGION_OP ARGI_LIST3 (ARGI_STRING, ARGI_STRING, ARGI_STRING)
+#define ARGI_DEBUG_OP ARG_NONE
+#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING)
+#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE
+#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF)
+#define ARGI_DWORD_OP ARGI_INVALID_OPCODE
+#define ARGI_ELSE_OP ARGI_INVALID_OPCODE
+#define ARGI_EVENT_OP ARGI_INVALID_OPCODE
+#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_IF_OP ARGI_INVALID_OPCODE
+#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#define ARGI_INDEX_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_INDEX_OP ARGI_LIST3 (ARGI_COMPLEXOBJ, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_LAND_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_LEQUAL_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA)
+#define ARGI_LGREATER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA)
+#define ARGI_LGREATEREQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LLESS_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA)
+#define ARGI_LLESSEQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LNOT_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_LNOTEQUAL_OP ARGI_INVALID_OPCODE
+#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF)
+#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE)
+#define ARGI_LOCAL0 ARG_NONE
+#define ARGI_LOCAL1 ARG_NONE
+#define ARGI_LOCAL2 ARG_NONE
+#define ARGI_LOCAL3 ARG_NONE
+#define ARGI_LOCAL4 ARG_NONE
+#define ARGI_LOCAL5 ARG_NONE
+#define ARGI_LOCAL6 ARG_NONE
+#define ARGI_LOCAL7 ARG_NONE
+#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER)
+#define ARGI_METHOD_OP ARGI_INVALID_OPCODE
+#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE
+#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE
+#define ARGI_NAME_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE
+#define ARGI_NOOP_OP ARG_NONE
+#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER)
+#define ARGI_ONE_OP ARG_NONE
+#define ARGI_ONES_OP ARG_NONE
+#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE
+#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE
+#define ARGI_QWORD_OP ARGI_INVALID_OPCODE
+#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF)
+#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX)
+#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_RETURN_OP ARGI_INVALID_OPCODE
+#define ARGI_REVISION_OP ARG_NONE
+#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE
+#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT)
+#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE
+#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF)
+#define ARGI_STRING_OP ARGI_INVALID_OPCODE
+#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE
+#define ARGI_TIMER_OP ARG_NONE
+#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
+#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET)
+#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE)
+#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE)
+#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER)
+#define ARGI_WHILE_OP ARGI_INVALID_OPCODE
+#define ARGI_WORD_OP ARGI_INVALID_OPCODE
+#define ARGI_ZERO_OP ARG_NONE
+
+
+/*
+ * Summary of opcode types/flags
+ */
+
+/******************************************************************************
+
+ Opcodes that have associated namespace objects (AML_NSOBJECT flag)
+
+ AML_SCOPE_OP
+ AML_DEVICE_OP
+ AML_THERMAL_ZONE_OP
+ AML_METHOD_OP
+ AML_POWER_RES_OP
+ AML_PROCESSOR_OP
+ AML_FIELD_OP
+ AML_INDEX_FIELD_OP
+ AML_BANK_FIELD_OP
+ AML_NAME_OP
+ AML_ALIAS_OP
+ AML_MUTEX_OP
+ AML_EVENT_OP
+ AML_REGION_OP
+ AML_CREATE_FIELD_OP
+ AML_CREATE_BIT_FIELD_OP
+ AML_CREATE_BYTE_FIELD_OP
+ AML_CREATE_WORD_FIELD_OP
+ AML_CREATE_DWORD_FIELD_OP
+ AML_CREATE_QWORD_FIELD_OP
+ AML_INT_NAMEDFIELD_OP
+ AML_INT_METHODCALL_OP
+ AML_INT_NAMEPATH_OP
+
+ Opcodes that are "namespace" opcodes (AML_NSOPCODE flag)
+
+ AML_SCOPE_OP
+ AML_DEVICE_OP
+ AML_THERMAL_ZONE_OP
+ AML_METHOD_OP
+ AML_POWER_RES_OP
+ AML_PROCESSOR_OP
+ AML_FIELD_OP
+ AML_INDEX_FIELD_OP
+ AML_BANK_FIELD_OP
+ AML_NAME_OP
+ AML_ALIAS_OP
+ AML_MUTEX_OP
+ AML_EVENT_OP
+ AML_REGION_OP
+ AML_INT_NAMEDFIELD_OP
+
+ Opcodes that have an associated namespace node (AML_NSNODE flag)
+
+ AML_SCOPE_OP
+ AML_DEVICE_OP
+ AML_THERMAL_ZONE_OP
+ AML_METHOD_OP
+ AML_POWER_RES_OP
+ AML_PROCESSOR_OP
+ AML_NAME_OP
+ AML_ALIAS_OP
+ AML_MUTEX_OP
+ AML_EVENT_OP
+ AML_REGION_OP
+ AML_CREATE_FIELD_OP
+ AML_CREATE_BIT_FIELD_OP
+ AML_CREATE_BYTE_FIELD_OP
+ AML_CREATE_WORD_FIELD_OP
+ AML_CREATE_DWORD_FIELD_OP
+ AML_CREATE_QWORD_FIELD_OP
+ AML_INT_NAMEDFIELD_OP
+ AML_INT_METHODCALL_OP
+ AML_INT_NAMEPATH_OP
+
+ Opcodes that define named ACPI objects (AML_NAMED flag)
+
+ AML_SCOPE_OP
+ AML_DEVICE_OP
+ AML_THERMAL_ZONE_OP
+ AML_METHOD_OP
+ AML_POWER_RES_OP
+ AML_PROCESSOR_OP
+ AML_NAME_OP
+ AML_ALIAS_OP
+ AML_MUTEX_OP
+ AML_EVENT_OP
+ AML_REGION_OP
+ AML_INT_NAMEDFIELD_OP
+
+ Opcodes that contain executable AML as part of the definition that
+ must be deferred until needed
+
+ AML_METHOD_OP
+ AML_VAR_PACKAGE_OP
+ AML_CREATE_FIELD_OP
+ AML_CREATE_BIT_FIELD_OP
+ AML_CREATE_BYTE_FIELD_OP
+ AML_CREATE_WORD_FIELD_OP
+ AML_CREATE_DWORD_FIELD_OP
+ AML_CREATE_QWORD_FIELD_OP
+ AML_REGION_OP
+ AML_BUFFER_OP
+
+ Field opcodes
+
+ AML_CREATE_FIELD_OP
+ AML_FIELD_OP
+ AML_INDEX_FIELD_OP
+ AML_BANK_FIELD_OP
+
+ Field "Create" opcodes
+
+ AML_CREATE_FIELD_OP
+ AML_CREATE_BIT_FIELD_OP
+ AML_CREATE_BYTE_FIELD_OP
+ AML_CREATE_WORD_FIELD_OP
+ AML_CREATE_DWORD_FIELD_OP
+ AML_CREATE_QWORD_FIELD_OP
+
+******************************************************************************/
+
+
+/*
+ * Master Opcode information table. A summary of everything we know about each opcode, all in one place.
+ */
+
+
+const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] =
+{
+/*! [Begin] no source code translation */
+/* Index Name Parser Args Interpreter Args ObjectType Class Type Flags */
+
+/* 00 */ ACPI_OP ("Zero", ARGP_ZERO_OP, ARGI_ZERO_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+/* 01 */ ACPI_OP ("One", ARGP_ONE_OP, ARGI_ONE_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+/* 02 */ ACPI_OP ("Alias", ARGP_ALIAS_OP, ARGI_ALIAS_OP, ACPI_TYPE_LOCAL_ALIAS, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 03 */ ACPI_OP ("Name", ARGP_NAME_OP, ARGI_NAME_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 04 */ ACPI_OP ("ByteConst", ARGP_BYTE_OP, ARGI_BYTE_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT),
+/* 05 */ ACPI_OP ("WordConst", ARGP_WORD_OP, ARGI_WORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT),
+/* 06 */ ACPI_OP ("DwordConst", ARGP_DWORD_OP, ARGI_DWORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT),
+/* 07 */ ACPI_OP ("String", ARGP_STRING_OP, ARGI_STRING_OP, ACPI_TYPE_STRING, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT),
+/* 08 */ ACPI_OP ("Scope", ARGP_SCOPE_OP, ARGI_SCOPE_OP, ACPI_TYPE_LOCAL_SCOPE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 09 */ ACPI_OP ("Buffer", ARGP_BUFFER_OP, ARGI_BUFFER_OP, ACPI_TYPE_BUFFER, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
+/* 0A */ ACPI_OP ("Package", ARGP_PACKAGE_OP, ARGI_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER | AML_CONSTANT),
+/* 0B */ ACPI_OP ("Method", ARGP_METHOD_OP, ARGI_METHOD_OP, ACPI_TYPE_METHOD, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER),
+/* 0C */ ACPI_OP ("Local0", ARGP_LOCAL0, ARGI_LOCAL0, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 0D */ ACPI_OP ("Local1", ARGP_LOCAL1, ARGI_LOCAL1, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 0E */ ACPI_OP ("Local2", ARGP_LOCAL2, ARGI_LOCAL2, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 0F */ ACPI_OP ("Local3", ARGP_LOCAL3, ARGI_LOCAL3, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 10 */ ACPI_OP ("Local4", ARGP_LOCAL4, ARGI_LOCAL4, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 11 */ ACPI_OP ("Local5", ARGP_LOCAL5, ARGI_LOCAL5, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 12 */ ACPI_OP ("Local6", ARGP_LOCAL6, ARGI_LOCAL6, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 13 */ ACPI_OP ("Local7", ARGP_LOCAL7, ARGI_LOCAL7, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LOCAL_VARIABLE, 0),
+/* 14 */ ACPI_OP ("Arg0", ARGP_ARG0, ARGI_ARG0, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0),
+/* 15 */ ACPI_OP ("Arg1", ARGP_ARG1, ARGI_ARG1, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0),
+/* 16 */ ACPI_OP ("Arg2", ARGP_ARG2, ARGI_ARG2, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0),
+/* 17 */ ACPI_OP ("Arg3", ARGP_ARG3, ARGI_ARG3, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0),
+/* 18 */ ACPI_OP ("Arg4", ARGP_ARG4, ARGI_ARG4, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0),
+/* 19 */ ACPI_OP ("Arg5", ARGP_ARG5, ARGI_ARG5, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0),
+/* 1A */ ACPI_OP ("Arg6", ARGP_ARG6, ARGI_ARG6, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_METHOD_ARGUMENT, 0),
+/* 1B */ ACPI_OP ("Store", ARGP_STORE_OP, ARGI_STORE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
+/* 1C */ ACPI_OP ("RefOf", ARGP_REF_OF_OP, ARGI_REF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R),
+/* 1D */ ACPI_OP ("Add", ARGP_ADD_OP, ARGI_ADD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 1E */ ACPI_OP ("Concatenate", ARGP_CONCAT_OP, ARGI_CONCAT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+/* 1F */ ACPI_OP ("Subtract", ARGP_SUBTRACT_OP, ARGI_SUBTRACT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 20 */ ACPI_OP ("Increment", ARGP_INCREMENT_OP, ARGI_INCREMENT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+/* 21 */ ACPI_OP ("Decrement", ARGP_DECREMENT_OP, ARGI_DECREMENT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+/* 22 */ ACPI_OP ("Multiply", ARGP_MULTIPLY_OP, ARGI_MULTIPLY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 23 */ ACPI_OP ("Divide", ARGP_DIVIDE_OP, ARGI_DIVIDE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_2T_1R, AML_FLAGS_EXEC_2A_2T_1R | AML_CONSTANT),
+/* 24 */ ACPI_OP ("ShiftLeft", ARGP_SHIFT_LEFT_OP, ARGI_SHIFT_LEFT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 25 */ ACPI_OP ("ShiftRight", ARGP_SHIFT_RIGHT_OP, ARGI_SHIFT_RIGHT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 26 */ ACPI_OP ("And", ARGP_BIT_AND_OP, ARGI_BIT_AND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 27 */ ACPI_OP ("NAnd", ARGP_BIT_NAND_OP, ARGI_BIT_NAND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 28 */ ACPI_OP ("Or", ARGP_BIT_OR_OP, ARGI_BIT_OR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 29 */ ACPI_OP ("NOr", ARGP_BIT_NOR_OP, ARGI_BIT_NOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 2A */ ACPI_OP ("XOr", ARGP_BIT_XOR_OP, ARGI_BIT_XOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_MATH | AML_CONSTANT),
+/* 2B */ ACPI_OP ("Not", ARGP_BIT_NOT_OP, ARGI_BIT_NOT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 2C */ ACPI_OP ("FindSetLeftBit", ARGP_FIND_SET_LEFT_BIT_OP, ARGI_FIND_SET_LEFT_BIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 2D */ ACPI_OP ("FindSetRightBit", ARGP_FIND_SET_RIGHT_BIT_OP,ARGI_FIND_SET_RIGHT_BIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 2E */ ACPI_OP ("DerefOf", ARGP_DEREF_OF_OP, ARGI_DEREF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R),
+/* 2F */ ACPI_OP ("Notify", ARGP_NOTIFY_OP, ARGI_NOTIFY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_0R, AML_FLAGS_EXEC_2A_0T_0R),
+/* 30 */ ACPI_OP ("SizeOf", ARGP_SIZE_OF_OP, ARGI_SIZE_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
+/* 31 */ ACPI_OP ("Index", ARGP_INDEX_OP, ARGI_INDEX_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R),
+/* 32 */ ACPI_OP ("Match", ARGP_MATCH_OP, ARGI_MATCH_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R | AML_CONSTANT),
+/* 33 */ ACPI_OP ("CreateDWordField", ARGP_CREATE_DWORD_FIELD_OP,ARGI_CREATE_DWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
+/* 34 */ ACPI_OP ("CreateWordField", ARGP_CREATE_WORD_FIELD_OP, ARGI_CREATE_WORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
+/* 35 */ ACPI_OP ("CreateByteField", ARGP_CREATE_BYTE_FIELD_OP, ARGI_CREATE_BYTE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
+/* 36 */ ACPI_OP ("CreateBitField", ARGP_CREATE_BIT_FIELD_OP, ARGI_CREATE_BIT_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
+/* 37 */ ACPI_OP ("ObjectType", ARGP_TYPE_OP, ARGI_TYPE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_NO_OPERAND_RESOLVE),
+/* 38 */ ACPI_OP ("LAnd", ARGP_LAND_OP, ARGI_LAND_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
+/* 39 */ ACPI_OP ("LOr", ARGP_LOR_OP, ARGI_LOR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL_NUMERIC | AML_CONSTANT),
+/* 3A */ ACPI_OP ("LNot", ARGP_LNOT_OP, ARGI_LNOT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_1R, AML_FLAGS_EXEC_1A_0T_1R | AML_CONSTANT),
+/* 3B */ ACPI_OP ("LEqual", ARGP_LEQUAL_OP, ARGI_LEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+/* 3C */ ACPI_OP ("LGreater", ARGP_LGREATER_OP, ARGI_LGREATER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+/* 3D */ ACPI_OP ("LLess", ARGP_LLESS_OP, ARGI_LLESS_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R | AML_LOGICAL | AML_CONSTANT),
+/* 3E */ ACPI_OP ("If", ARGP_IF_OP, ARGI_IF_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+/* 3F */ ACPI_OP ("Else", ARGP_ELSE_OP, ARGI_ELSE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+/* 40 */ ACPI_OP ("While", ARGP_WHILE_OP, ARGI_WHILE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+/* 41 */ ACPI_OP ("Noop", ARGP_NOOP_OP, ARGI_NOOP_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+/* 42 */ ACPI_OP ("Return", ARGP_RETURN_OP, ARGI_RETURN_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, AML_HAS_ARGS),
+/* 43 */ ACPI_OP ("Break", ARGP_BREAK_OP, ARGI_BREAK_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+/* 44 */ ACPI_OP ("BreakPoint", ARGP_BREAK_POINT_OP, ARGI_BREAK_POINT_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+/* 45 */ ACPI_OP ("Ones", ARGP_ONES_OP, ARGI_ONES_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, AML_CONSTANT),
+
+/* Prefixed opcodes (Two-byte opcodes with a prefix op) */
+
+/* 46 */ ACPI_OP ("Mutex", ARGP_MUTEX_OP, ARGI_MUTEX_OP, ACPI_TYPE_MUTEX, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 47 */ ACPI_OP ("Event", ARGP_EVENT_OP, ARGI_EVENT_OP, ACPI_TYPE_EVENT, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ),
+/* 48 */ ACPI_OP ("CondRefOf", ARGP_COND_REF_OF_OP, ARGI_COND_REF_OF_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
+/* 49 */ ACPI_OP ("CreateField", ARGP_CREATE_FIELD_OP, ARGI_CREATE_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_FIELD | AML_CREATE),
+/* 4A */ ACPI_OP ("Load", ARGP_LOAD_OP, ARGI_LOAD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_0R, AML_FLAGS_EXEC_1A_1T_0R),
+/* 4B */ ACPI_OP ("Stall", ARGP_STALL_OP, ARGI_STALL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+/* 4C */ ACPI_OP ("Sleep", ARGP_SLEEP_OP, ARGI_SLEEP_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+/* 4D */ ACPI_OP ("Acquire", ARGP_ACQUIRE_OP, ARGI_ACQUIRE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R),
+/* 4E */ ACPI_OP ("Signal", ARGP_SIGNAL_OP, ARGI_SIGNAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+/* 4F */ ACPI_OP ("Wait", ARGP_WAIT_OP, ARGI_WAIT_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_0T_1R, AML_FLAGS_EXEC_2A_0T_1R),
+/* 50 */ ACPI_OP ("Reset", ARGP_RESET_OP, ARGI_RESET_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+/* 51 */ ACPI_OP ("Release", ARGP_RELEASE_OP, ARGI_RELEASE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+/* 52 */ ACPI_OP ("FromBCD", ARGP_FROM_BCD_OP, ARGI_FROM_BCD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 53 */ ACPI_OP ("ToBCD", ARGP_TO_BCD_OP, ARGI_TO_BCD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 54 */ ACPI_OP ("Unload", ARGP_UNLOAD_OP, ARGI_UNLOAD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_0T_0R, AML_FLAGS_EXEC_1A_0T_0R),
+/* 55 */ ACPI_OP ("Revision", ARGP_REVISION_OP, ARGI_REVISION_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0),
+/* 56 */ ACPI_OP ("Debug", ARGP_DEBUG_OP, ARGI_DEBUG_OP, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_CONSTANT, 0),
+/* 57 */ ACPI_OP ("Fatal", ARGP_FATAL_OP, ARGI_FATAL_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_0T_0R, AML_FLAGS_EXEC_3A_0T_0R),
+/* 58 */ ACPI_OP ("OperationRegion", ARGP_REGION_OP, ARGI_REGION_OP, ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_COMPLEX, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED | AML_DEFER),
+/* 59 */ ACPI_OP ("Field", ARGP_FIELD_OP, ARGI_FIELD_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
+/* 5A */ ACPI_OP ("Device", ARGP_DEVICE_OP, ARGI_DEVICE_OP, ACPI_TYPE_DEVICE, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 5B */ ACPI_OP ("Processor", ARGP_PROCESSOR_OP, ARGI_PROCESSOR_OP, ACPI_TYPE_PROCESSOR, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 5C */ ACPI_OP ("PowerResource", ARGP_POWER_RES_OP, ARGI_POWER_RES_OP, ACPI_TYPE_POWER, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 5D */ ACPI_OP ("ThermalZone", ARGP_THERMAL_ZONE_OP, ARGI_THERMAL_ZONE_OP, ACPI_TYPE_THERMAL, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 5E */ ACPI_OP ("IndexField", ARGP_INDEX_FIELD_OP, ARGI_INDEX_FIELD_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
+/* 5F */ ACPI_OP ("BankField", ARGP_BANK_FIELD_OP, ARGI_BANK_FIELD_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_FIELD),
+
+/* Internal opcodes that map to invalid AML opcodes */
+
+/* 60 */ ACPI_OP ("LNotEqual", ARGP_LNOTEQUAL_OP, ARGI_LNOTEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
+/* 61 */ ACPI_OP ("LLessEqual", ARGP_LLESSEQUAL_OP, ARGI_LLESSEQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
+/* 62 */ ACPI_OP ("LGreaterEqual", ARGP_LGREATEREQUAL_OP, ARGI_LGREATEREQUAL_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_HAS_ARGS | AML_CONSTANT),
+/* 63 */ ACPI_OP ("-NamePath-", ARGP_NAMEPATH_OP, ARGI_NAMEPATH_OP, ACPI_TYPE_LOCAL_REFERENCE, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_NSOBJECT | AML_NSNODE ),
+/* 64 */ ACPI_OP ("-MethodCall-", ARGP_METHODCALL_OP, ARGI_METHODCALL_OP, ACPI_TYPE_METHOD, AML_CLASS_METHOD_CALL, AML_TYPE_METHOD_CALL, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE),
+/* 65 */ ACPI_OP ("-ByteList-", ARGP_BYTELIST_OP, ARGI_BYTELIST_OP, ACPI_TYPE_ANY, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, 0),
+/* 66 */ ACPI_OP ("-ReservedField-", ARGP_RESERVEDFIELD_OP, ARGI_RESERVEDFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+/* 67 */ ACPI_OP ("-NamedField-", ARGP_NAMEDFIELD_OP, ARGI_NAMEDFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED ),
+/* 68 */ ACPI_OP ("-AccessField-", ARGP_ACCESSFIELD_OP, ARGI_ACCESSFIELD_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+/* 69 */ ACPI_OP ("-StaticString", ARGP_STATICSTRING_OP, ARGI_STATICSTRING_OP, ACPI_TYPE_ANY, AML_CLASS_INTERNAL, AML_TYPE_BOGUS, 0),
+/* 6A */ ACPI_OP ("-Return Value-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_RETURN_VALUE, AML_TYPE_RETURN, AML_HAS_ARGS | AML_HAS_RETVAL),
+/* 6B */ ACPI_OP ("-UNKNOWN_OP-", ARG_NONE, ARG_NONE, ACPI_TYPE_INVALID, AML_CLASS_UNKNOWN, AML_TYPE_BOGUS, AML_HAS_ARGS),
+/* 6C */ ACPI_OP ("-ASCII_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_ASCII, AML_TYPE_BOGUS, AML_HAS_ARGS),
+/* 6D */ ACPI_OP ("-PREFIX_ONLY-", ARG_NONE, ARG_NONE, ACPI_TYPE_ANY, AML_CLASS_PREFIX, AML_TYPE_BOGUS, AML_HAS_ARGS),
+
+/* ACPI 2.0 opcodes */
+
+/* 6E */ ACPI_OP ("QwordConst", ARGP_QWORD_OP, ARGI_QWORD_OP, ACPI_TYPE_INTEGER, AML_CLASS_ARGUMENT, AML_TYPE_LITERAL, AML_CONSTANT),
+/* 6F */ ACPI_OP ("Package /*Var*/", ARGP_VAR_PACKAGE_OP, ARGI_VAR_PACKAGE_OP, ACPI_TYPE_PACKAGE, AML_CLASS_CREATE, AML_TYPE_CREATE_OBJECT, AML_HAS_ARGS | AML_DEFER),
+/* 70 */ ACPI_OP ("ConcatenateResTemplate", ARGP_CONCAT_RES_OP, ARGI_CONCAT_RES_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+/* 71 */ ACPI_OP ("Mod", ARGP_MOD_OP, ARGI_MOD_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+/* 72 */ ACPI_OP ("CreateQWordField", ARGP_CREATE_QWORD_FIELD_OP,ARGI_CREATE_QWORD_FIELD_OP, ACPI_TYPE_BUFFER_FIELD, AML_CLASS_CREATE, AML_TYPE_CREATE_FIELD, AML_HAS_ARGS | AML_NSOBJECT | AML_NSNODE | AML_DEFER | AML_CREATE),
+/* 73 */ ACPI_OP ("ToBuffer", ARGP_TO_BUFFER_OP, ARGI_TO_BUFFER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 74 */ ACPI_OP ("ToDecimalString", ARGP_TO_DEC_STR_OP, ARGI_TO_DEC_STR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 75 */ ACPI_OP ("ToHexString", ARGP_TO_HEX_STR_OP, ARGI_TO_HEX_STR_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 76 */ ACPI_OP ("ToInteger", ARGP_TO_INTEGER_OP, ARGI_TO_INTEGER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R | AML_CONSTANT),
+/* 77 */ ACPI_OP ("ToString", ARGP_TO_STRING_OP, ARGI_TO_STRING_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_2A_1T_1R, AML_FLAGS_EXEC_2A_1T_1R | AML_CONSTANT),
+/* 78 */ ACPI_OP ("CopyObject", ARGP_COPY_OP, ARGI_COPY_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_1A_1T_1R, AML_FLAGS_EXEC_1A_1T_1R),
+/* 79 */ ACPI_OP ("Mid", ARGP_MID_OP, ARGI_MID_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_3A_1T_1R, AML_FLAGS_EXEC_3A_1T_1R | AML_CONSTANT),
+/* 7A */ ACPI_OP ("Continue", ARGP_CONTINUE_OP, ARGI_CONTINUE_OP, ACPI_TYPE_ANY, AML_CLASS_CONTROL, AML_TYPE_CONTROL, 0),
+/* 7B */ ACPI_OP ("LoadTable", ARGP_LOAD_TABLE_OP, ARGI_LOAD_TABLE_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_6A_0T_1R, AML_FLAGS_EXEC_6A_0T_1R),
+/* 7C */ ACPI_OP ("DataTableRegion", ARGP_DATA_REGION_OP, ARGI_DATA_REGION_OP, ACPI_TYPE_REGION, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_SIMPLE, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE | AML_NAMED),
+/* 7D */ ACPI_OP ("[EvalSubTree]", ARGP_SCOPE_OP, ARGI_SCOPE_OP, ACPI_TYPE_ANY, AML_CLASS_NAMED_OBJECT, AML_TYPE_NAMED_NO_OBJ, AML_HAS_ARGS | AML_NSOBJECT | AML_NSOPCODE | AML_NSNODE),
+
+/* ACPI 3.0 opcodes */
+
+/* 7E */ ACPI_OP ("Timer", ARGP_TIMER_OP, ARGI_TIMER_OP, ACPI_TYPE_ANY, AML_CLASS_EXECUTE, AML_TYPE_EXEC_0A_0T_1R, AML_FLAGS_EXEC_0A_0T_1R)
+
+/*! [End] no source code translation !*/
+};
+
+/*
+ * This table is directly indexed by the opcodes, and returns an
+ * index into the table above
+ */
+static const u8 acpi_gbl_short_op_index[256] =
+{
+/* 0 1 2 3 4 5 6 7 */
+/* 8 9 A B C D E F */
+/* 0x00 */ 0x00, 0x01, _UNK, _UNK, _UNK, _UNK, 0x02, _UNK,
+/* 0x08 */ 0x03, _UNK, 0x04, 0x05, 0x06, 0x07, 0x6E, _UNK,
+/* 0x10 */ 0x08, 0x09, 0x0a, 0x6F, 0x0b, _UNK, _UNK, _UNK,
+/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x20 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x28 */ _UNK, _UNK, _UNK, _UNK, _UNK, 0x63, _PFX, _PFX,
+/* 0x30 */ 0x67, 0x66, 0x68, 0x65, 0x69, 0x64, 0x6A, 0x7D,
+/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x40 */ _UNK, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x48 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x50 */ _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC, _ASC,
+/* 0x58 */ _ASC, _ASC, _ASC, _UNK, _PFX, _UNK, _PFX, _ASC,
+/* 0x60 */ 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13,
+/* 0x68 */ 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, _UNK,
+/* 0x70 */ 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22,
+/* 0x78 */ 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
+/* 0x80 */ 0x2b, 0x2c, 0x2d, 0x2e, 0x70, 0x71, 0x2f, 0x30,
+/* 0x88 */ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x72,
+/* 0x90 */ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x73, 0x74,
+/* 0x98 */ 0x75, 0x76, _UNK, _UNK, 0x77, 0x78, 0x79, 0x7A,
+/* 0xA0 */ 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x60, 0x61,
+/* 0xA8 */ 0x62, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xB8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xC8 */ _UNK, _UNK, _UNK, _UNK, 0x44, _UNK, _UNK, _UNK,
+/* 0xD0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xD8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xE8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF0 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0xF8 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x45,
+};
+
+/*
+ * This table is indexed by the second opcode of the extended opcode
+ * pair. It returns an index into the opcode table (acpi_gbl_aml_op_info)
+ */
+static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] =
+{
+/* 0 1 2 3 4 5 6 7 */
+/* 8 9 A B C D E F */
+/* 0x00 */ _UNK, 0x46, 0x47, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x08 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x10 */ _UNK, _UNK, 0x48, 0x49, _UNK, _UNK, _UNK, _UNK,
+/* 0x18 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, 0x7B,
+/* 0x20 */ 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
+/* 0x28 */ 0x52, 0x53, 0x54, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x30 */ 0x55, 0x56, 0x57, 0x7e, _UNK, _UNK, _UNK, _UNK,
+/* 0x38 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x40 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x48 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x50 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x58 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x60 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x68 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x70 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x78 */ _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK, _UNK,
+/* 0x80 */ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+/* 0x88 */ 0x7C,
+};
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_opcode_info
+ *
+ * PARAMETERS: Opcode - The AML opcode
+ *
+ * RETURN: A pointer to the info about the opcode. NULL if the opcode was
+ * not found in the table.
+ *
+ * DESCRIPTION: Find AML opcode description based on the opcode.
+ * NOTE: This procedure must ALWAYS return a valid pointer!
+ *
+ ******************************************************************************/
+
+const struct acpi_opcode_info *
+acpi_ps_get_opcode_info (
+ u16 opcode)
+{
+ ACPI_FUNCTION_NAME ("ps_get_opcode_info");
+
+
+ /*
+ * Detect normal 8-bit opcode or extended 16-bit opcode
+ */
+ switch ((u8) (opcode >> 8)) {
+ case 0:
+
+ /* Simple (8-bit) opcode: 0-255, can't index beyond table */
+
+ return (&acpi_gbl_aml_op_info [acpi_gbl_short_op_index [(u8) opcode]]);
+
+ case AML_EXTOP:
+
+ /* Extended (16-bit, prefix+opcode) opcode */
+
+ if (((u8) opcode) <= MAX_EXTENDED_OPCODE) {
+ return (&acpi_gbl_aml_op_info [acpi_gbl_long_op_index [(u8) opcode]]);
+ }
+
+ /* Else fall through to error case below */
+ /*lint -fallthrough */
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown AML opcode [%4.4X]\n", opcode));
+ break;
+ }
+
+
+ /* Default is "unknown opcode" */
+
+ return (&acpi_gbl_aml_op_info [_UNK]);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_opcode_name
+ *
+ * PARAMETERS: Opcode - The AML opcode
+ *
+ * RETURN: A pointer to the name of the opcode (ASCII String)
+ * Note: Never returns NULL.
+ *
+ * DESCRIPTION: Translate an opcode into a human-readable string
+ *
+ ******************************************************************************/
+
+char *
+acpi_ps_get_opcode_name (
+ u16 opcode)
+{
+#if defined(ACPI_DISASSEMBLER) || defined (ACPI_DEBUG_OUTPUT)
+
+ const struct acpi_opcode_info *op;
+
+
+ op = acpi_ps_get_opcode_info (opcode);
+
+ /* Always guaranteed to return a valid pointer */
+
+ return (op->name);
+
+#else
+ return ("AE_NOT_CONFIGURED");
+
+#endif
+}
+
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
new file mode 100644
index 000000000000..e79edb53cb3b
--- /dev/null
+++ b/drivers/acpi/parser/psparse.c
@@ -0,0 +1,1266 @@
+/******************************************************************************
+ *
+ * Module Name: psparse - Parser top level AML parse routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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.
+ */
+
+
+/*
+ * Parse the AML and build an operation tree as most interpreters,
+ * like Perl, do. Parsing is done by hand rather than with a YACC
+ * generated parser to tightly constrain stack and dynamic memory
+ * usage. At the same time, parsing is kept flexible and the code
+ * fairly compact by parsing based on a list of AML opcode
+ * templates in aml_op_info[]
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/acparser.h>
+#include <acpi/acdispat.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acinterp.h>
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("psparse")
+
+
+static u32 acpi_gbl_depth = 0;
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_opcode_size
+ *
+ * PARAMETERS: Opcode - An AML opcode
+ *
+ * RETURN: Size of the opcode, in bytes (1 or 2)
+ *
+ * DESCRIPTION: Get the size of the current opcode.
+ *
+ ******************************************************************************/
+
+u32
+acpi_ps_get_opcode_size (
+ u32 opcode)
+{
+
+ /* Extended (2-byte) opcode if > 255 */
+
+ if (opcode > 0x00FF) {
+ return (2);
+ }
+
+ /* Otherwise, just a single byte opcode */
+
+ return (1);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_peek_opcode
+ *
+ * PARAMETERS: parser_state - A parser state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
+ *
+ ******************************************************************************/
+
+u16
+acpi_ps_peek_opcode (
+ struct acpi_parse_state *parser_state)
+{
+ u8 *aml;
+ u16 opcode;
+
+
+ aml = parser_state->aml;
+ opcode = (u16) ACPI_GET8 (aml);
+
+
+ if (opcode == AML_EXTOP) {
+ /* Extended opcode */
+
+ aml++;
+ opcode = (u16) ((opcode << 8) | ACPI_GET8 (aml));
+ }
+
+ return (opcode);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_complete_this_op
+ *
+ * PARAMETERS: walk_state - Current State
+ * Op - Op to complete
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Perform any cleanup at the completion of an Op.
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_complete_this_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op)
+{
+ union acpi_parse_object *prev;
+ union acpi_parse_object *next;
+ const struct acpi_opcode_info *parent_info;
+ union acpi_parse_object *replacement_op = NULL;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_complete_this_op", op);
+
+
+ /* Check for null Op, can happen if AML code is corrupt */
+
+ if (!op) {
+ return_VOID;
+ }
+
+ /* Delete this op and the subtree below it if asked to */
+
+ if (((walk_state->parse_flags & ACPI_PARSE_TREE_MASK) != ACPI_PARSE_DELETE_TREE) ||
+ (walk_state->op_info->class == AML_CLASS_ARGUMENT)) {
+ return_VOID;
+ }
+
+ /* Make sure that we only delete this subtree */
+
+ if (op->common.parent) {
+ /*
+ * Check if we need to replace the operator and its subtree
+ * with a return value op (placeholder op)
+ */
+ parent_info = acpi_ps_get_opcode_info (op->common.parent->common.aml_opcode);
+
+ switch (parent_info->class) {
+ case AML_CLASS_CONTROL:
+ break;
+
+ case AML_CLASS_CREATE:
+
+ /*
+ * These opcodes contain term_arg operands. The current
+ * op must be replaced by a placeholder return op
+ */
+ replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
+ if (!replacement_op) {
+ goto cleanup;
+ }
+ break;
+
+ case AML_CLASS_NAMED_OBJECT:
+
+ /*
+ * These opcodes contain term_arg operands. The current
+ * op must be replaced by a placeholder return op
+ */
+ if ((op->common.parent->common.aml_opcode == AML_REGION_OP) ||
+ (op->common.parent->common.aml_opcode == AML_DATA_REGION_OP) ||
+ (op->common.parent->common.aml_opcode == AML_BUFFER_OP) ||
+ (op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.parent->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
+ replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
+ if (!replacement_op) {
+ goto cleanup;
+ }
+ }
+
+ if ((op->common.parent->common.aml_opcode == AML_NAME_OP) &&
+ (walk_state->descending_callback != acpi_ds_exec_begin_op)) {
+ if ((op->common.aml_opcode == AML_BUFFER_OP) ||
+ (op->common.aml_opcode == AML_PACKAGE_OP) ||
+ (op->common.aml_opcode == AML_VAR_PACKAGE_OP)) {
+ replacement_op = acpi_ps_alloc_op (op->common.aml_opcode);
+ if (!replacement_op) {
+ goto cleanup;
+ }
+
+ replacement_op->named.data = op->named.data;
+ replacement_op->named.length = op->named.length;
+ }
+ }
+ break;
+
+ default:
+ replacement_op = acpi_ps_alloc_op (AML_INT_RETURN_VALUE_OP);
+ if (!replacement_op) {
+ goto cleanup;
+ }
+ }
+
+ /* We must unlink this op from the parent tree */
+
+ prev = op->common.parent->common.value.arg;
+ if (prev == op) {
+ /* This op is the first in the list */
+
+ if (replacement_op) {
+ replacement_op->common.parent = op->common.parent;
+ replacement_op->common.value.arg = NULL;
+ replacement_op->common.node = op->common.node;
+ op->common.parent->common.value.arg = replacement_op;
+ replacement_op->common.next = op->common.next;
+ }
+ else {
+ op->common.parent->common.value.arg = op->common.next;
+ }
+ }
+
+ /* Search the parent list */
+
+ else while (prev) {
+ /* Traverse all siblings in the parent's argument list */
+
+ next = prev->common.next;
+ if (next == op) {
+ if (replacement_op) {
+ replacement_op->common.parent = op->common.parent;
+ replacement_op->common.value.arg = NULL;
+ replacement_op->common.node = op->common.node;
+ prev->common.next = replacement_op;
+ replacement_op->common.next = op->common.next;
+ next = NULL;
+ }
+ else {
+ prev->common.next = op->common.next;
+ next = NULL;
+ }
+ }
+
+ prev = next;
+ }
+ }
+
+
+cleanup:
+
+ /* Now we can actually delete the subtree rooted at op */
+
+ acpi_ps_delete_parse_tree (op);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_next_parse_state
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Update the parser state based upon the return exception from
+ * the parser callback.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_next_parse_state (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ acpi_status callback_status)
+{
+ struct acpi_parse_state *parser_state = &walk_state->parser_state;
+ acpi_status status = AE_CTRL_PENDING;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_next_parse_state", op);
+
+
+ switch (callback_status) {
+ case AE_CTRL_TERMINATE:
+
+ /*
+ * A control method was terminated via a RETURN statement.
+ * The walk of this method is complete.
+ */
+ parser_state->aml = parser_state->aml_end;
+ status = AE_CTRL_TERMINATE;
+ break;
+
+
+ case AE_CTRL_BREAK:
+
+ parser_state->aml = walk_state->aml_last_while;
+ walk_state->control_state->common.value = FALSE;
+ status = AE_CTRL_BREAK;
+ break;
+
+ case AE_CTRL_CONTINUE:
+
+
+ parser_state->aml = walk_state->aml_last_while;
+ status = AE_CTRL_CONTINUE;
+ break;
+
+ case AE_CTRL_PENDING:
+
+ parser_state->aml = walk_state->aml_last_while;
+ break;
+
+#if 0
+ case AE_CTRL_SKIP:
+
+ parser_state->aml = parser_state->scope->parse_scope.pkg_end;
+ status = AE_OK;
+ break;
+#endif
+
+ case AE_CTRL_TRUE:
+
+ /*
+ * Predicate of an IF was true, and we are at the matching ELSE.
+ * Just close out this package
+ */
+ parser_state->aml = acpi_ps_get_next_package_end (parser_state);
+ break;
+
+
+ case AE_CTRL_FALSE:
+
+ /*
+ * Either an IF/WHILE Predicate was false or we encountered a BREAK
+ * opcode. In both cases, we do not execute the rest of the
+ * package; We simply close out the parent (finishing the walk of
+ * this branch of the tree) and continue execution at the parent
+ * level.
+ */
+ parser_state->aml = parser_state->scope->parse_scope.pkg_end;
+
+ /* In the case of a BREAK, just force a predicate (if any) to FALSE */
+
+ walk_state->control_state->common.value = FALSE;
+ status = AE_CTRL_END;
+ break;
+
+
+ case AE_CTRL_TRANSFER:
+
+ /*
+ * A method call (invocation) -- transfer control
+ */
+ status = AE_CTRL_TRANSFER;
+ walk_state->prev_op = op;
+ walk_state->method_call_op = op;
+ walk_state->method_call_node = (op->common.value.arg)->common.node;
+
+ /* Will return value (if any) be used by the caller? */
+
+ walk_state->return_used = acpi_ds_is_result_used (op, walk_state);
+ break;
+
+
+ default:
+ status = callback_status;
+ if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) {
+ status = AE_OK;
+ }
+ break;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_parse_loop
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
+ * a tree of ops.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_parse_loop (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+ union acpi_parse_object *op = NULL; /* current op */
+ union acpi_parse_object *arg = NULL;
+ union acpi_parse_object *pre_op = NULL;
+ struct acpi_parse_state *parser_state;
+ u8 *aml_op_start = NULL;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_parse_loop", walk_state);
+
+ if (walk_state->descending_callback == NULL) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ parser_state = &walk_state->parser_state;
+ walk_state->arg_types = 0;
+
+#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+ if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
+ /* We are restarting a preempted control method */
+
+ if (acpi_ps_has_completed_scope (parser_state)) {
+ /*
+ * We must check if a predicate to an IF or WHILE statement
+ * was just completed
+ */
+ if ((parser_state->scope->parse_scope.op) &&
+ ((parser_state->scope->parse_scope.op->common.aml_opcode == AML_IF_OP) ||
+ (parser_state->scope->parse_scope.op->common.aml_opcode == AML_WHILE_OP)) &&
+ (walk_state->control_state) &&
+ (walk_state->control_state->common.state ==
+ ACPI_CONTROL_PREDICATE_EXECUTING)) {
+ /*
+ * A predicate was just completed, get the value of the
+ * predicate and branch based on that value
+ */
+ walk_state->op = NULL;
+ status = acpi_ds_get_predicate_value (walk_state, ACPI_TO_POINTER (TRUE));
+ if (ACPI_FAILURE (status) &&
+ ((status & AE_CODE_MASK) != AE_CODE_CONTROL)) {
+ if (status == AE_AML_NO_RETURN_VALUE) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invoked method did not return a value, %s\n",
+ acpi_format_exception (status)));
+
+ }
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "get_predicate Failed, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_ps_next_parse_state (walk_state, op, status);
+ }
+
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op));
+ }
+ else if (walk_state->prev_op) {
+ /* We were in the middle of an op */
+
+ op = walk_state->prev_op;
+ walk_state->arg_types = walk_state->prev_arg_types;
+ }
+ }
+#endif
+
+ /*
+ * Iterative parsing loop, while there is more aml to process:
+ */
+ while ((parser_state->aml < parser_state->aml_end) || (op)) {
+ aml_op_start = parser_state->aml;
+ if (!op) {
+ /* Get the next opcode from the AML stream */
+
+ walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml,
+ parser_state->aml_start);
+ walk_state->opcode = acpi_ps_peek_opcode (parser_state);
+
+ /*
+ * First cut to determine what we have found:
+ * 1) A valid AML opcode
+ * 2) A name string
+ * 3) An unknown/invalid opcode
+ */
+ walk_state->op_info = acpi_ps_get_opcode_info (walk_state->opcode);
+ switch (walk_state->op_info->class) {
+ case AML_CLASS_ASCII:
+ case AML_CLASS_PREFIX:
+ /*
+ * Starts with a valid prefix or ASCII char, this is a name
+ * string. Convert the bare name string to a namepath.
+ */
+ walk_state->opcode = AML_INT_NAMEPATH_OP;
+ walk_state->arg_types = ARGP_NAMESTRING;
+ break;
+
+ case AML_CLASS_UNKNOWN:
+
+ /* The opcode is unrecognized. Just skip unknown opcodes */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Found unknown opcode %X at AML address %p offset %X, ignoring\n",
+ walk_state->opcode, parser_state->aml, walk_state->aml_offset));
+
+ ACPI_DUMP_BUFFER (parser_state->aml, 128);
+
+ /* Assume one-byte bad opcode */
+
+ parser_state->aml++;
+ continue;
+
+ default:
+
+ /* Found opcode info, this is a normal opcode */
+
+ parser_state->aml += acpi_ps_get_opcode_size (walk_state->opcode);
+ walk_state->arg_types = walk_state->op_info->parse_args;
+ break;
+ }
+
+ /* Create Op structure and append to parent's argument list */
+
+ if (walk_state->op_info->flags & AML_NAMED) {
+ /* Allocate a new pre_op if necessary */
+
+ if (!pre_op) {
+ pre_op = acpi_ps_alloc_op (walk_state->opcode);
+ if (!pre_op) {
+ status = AE_NO_MEMORY;
+ goto close_this_op;
+ }
+ }
+
+ pre_op->common.value.arg = NULL;
+ pre_op->common.aml_opcode = walk_state->opcode;
+
+ /*
+ * Get and append arguments until we find the node that contains
+ * the name (the type ARGP_NAME).
+ */
+ while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) &&
+ (GET_CURRENT_ARG_TYPE (walk_state->arg_types) != ARGP_NAME)) {
+ status = acpi_ps_get_next_arg (walk_state, parser_state,
+ GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg);
+ if (ACPI_FAILURE (status)) {
+ goto close_this_op;
+ }
+
+ acpi_ps_append_arg (pre_op, arg);
+ INCREMENT_ARG_LIST (walk_state->arg_types);
+ }
+
+ /* Make sure that we found a NAME and didn't run out of arguments */
+
+ if (!GET_CURRENT_ARG_TYPE (walk_state->arg_types)) {
+ status = AE_AML_NO_OPERAND;
+ goto close_this_op;
+ }
+
+ /* We know that this arg is a name, move to next arg */
+
+ INCREMENT_ARG_LIST (walk_state->arg_types);
+
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = NULL;
+
+ status = walk_state->descending_callback (walk_state, &op);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "During name lookup/catalog, %s\n",
+ acpi_format_exception (status)));
+ goto close_this_op;
+ }
+
+ if (op == NULL) {
+ continue;
+ }
+
+ status = acpi_ps_next_parse_state (walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_OK;
+ goto close_this_op;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ goto close_this_op;
+ }
+
+ acpi_ps_append_arg (op, pre_op->common.value.arg);
+ acpi_gbl_depth++;
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Defer final parsing of an operation_region body,
+ * because we don't have enough info in the first pass
+ * to parse it correctly (i.e., there may be method
+ * calls within the term_arg elements of the body.)
+ *
+ * However, we must continue parsing because
+ * the opregion is not a standalone package --
+ * we don't know where the end is at this point.
+ *
+ * (Length is unknown until parse of the body complete)
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
+ }
+ else {
+ /* Not a named opcode, just allocate Op and append to parent */
+
+ walk_state->op_info = acpi_ps_get_opcode_info (walk_state->opcode);
+ op = acpi_ps_alloc_op (walk_state->opcode);
+ if (!op) {
+ status = AE_NO_MEMORY;
+ goto close_this_op;
+ }
+
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration
+ * body_length is unknown until we parse the body
+ */
+ op->named.data = aml_op_start;
+ op->named.length = 0;
+ }
+
+ acpi_ps_append_arg (acpi_ps_get_parent_scope (parser_state), op);
+
+ if ((walk_state->descending_callback != NULL)) {
+ /*
+ * Find the object. This will either insert the object into
+ * the namespace or simply look it up
+ */
+ walk_state->op = op;
+
+ status = walk_state->descending_callback (walk_state, &op);
+ status = acpi_ps_next_parse_state (walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_OK;
+ goto close_this_op;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ goto close_this_op;
+ }
+ }
+ }
+
+ op->common.aml_offset = walk_state->aml_offset;
+
+ if (walk_state->op_info) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "Opcode %4.4X [%s] Op %p Aml %p aml_offset %5.5X\n",
+ (u32) op->common.aml_opcode, walk_state->op_info->name,
+ op, parser_state->aml, op->common.aml_offset));
+ }
+ }
+
+
+ /* Start arg_count at zero because we don't know if there are any args yet */
+
+ walk_state->arg_count = 0;
+
+ if (walk_state->arg_types) /* Are there any arguments that must be processed? */ {
+ /* Get arguments */
+
+ switch (op->common.aml_opcode) {
+ case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
+ case AML_WORD_OP: /* AML_WORDDATA_ARG */
+ case AML_DWORD_OP: /* AML_DWORDATA_ARG */
+ case AML_QWORD_OP: /* AML_QWORDATA_ARG */
+ case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
+
+ /* Fill in constant or string argument directly */
+
+ acpi_ps_get_next_simple_arg (parser_state,
+ GET_CURRENT_ARG_TYPE (walk_state->arg_types), op);
+ break;
+
+ case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
+
+ status = acpi_ps_get_next_namepath (walk_state, parser_state, op, 1);
+ if (ACPI_FAILURE (status)) {
+ goto close_this_op;
+ }
+
+ walk_state->arg_types = 0;
+ break;
+
+ default:
+
+ /* Op is not a constant or string, append each argument to the Op */
+
+ while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) &&
+ !walk_state->arg_count) {
+ walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml,
+ parser_state->aml_start);
+ status = acpi_ps_get_next_arg (walk_state, parser_state,
+ GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg);
+ if (ACPI_FAILURE (status)) {
+ goto close_this_op;
+ }
+
+ if (arg) {
+ arg->common.aml_offset = walk_state->aml_offset;
+ acpi_ps_append_arg (op, arg);
+ }
+ INCREMENT_ARG_LIST (walk_state->arg_types);
+ }
+
+ /* Special processing for certain opcodes */
+
+ switch (op->common.aml_opcode) {
+ case AML_METHOD_OP:
+
+ /*
+ * Skip parsing of control method
+ * because we don't have enough info in the first pass
+ * to parse it correctly.
+ *
+ * Save the length and address of the body
+ */
+ op->named.data = parser_state->aml;
+ op->named.length = (u32) (parser_state->pkg_end - parser_state->aml);
+
+ /* Skip body of method */
+
+ parser_state->aml = parser_state->pkg_end;
+ walk_state->arg_count = 0;
+ break;
+
+ case AML_BUFFER_OP:
+ case AML_PACKAGE_OP:
+ case AML_VAR_PACKAGE_OP:
+
+ if ((op->common.parent) &&
+ (op->common.parent->common.aml_opcode == AML_NAME_OP) &&
+ (walk_state->descending_callback != acpi_ds_exec_begin_op)) {
+ /*
+ * Skip parsing of Buffers and Packages
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ */
+ op->named.data = aml_op_start;
+ op->named.length = (u32) (parser_state->pkg_end - aml_op_start);
+
+ /* Skip body */
+
+ parser_state->aml = parser_state->pkg_end;
+ walk_state->arg_count = 0;
+ }
+ break;
+
+ case AML_WHILE_OP:
+
+ if (walk_state->control_state) {
+ walk_state->control_state->control.package_end = parser_state->pkg_end;
+ }
+ break;
+
+ default:
+
+ /* No action for all other opcodes */
+ break;
+ }
+ break;
+ }
+ }
+
+ /* Check for arguments that need to be processed */
+
+ if (walk_state->arg_count) {
+ /* There are arguments (complex ones), push Op and prepare for argument */
+
+ status = acpi_ps_push_scope (parser_state, op,
+ walk_state->arg_types, walk_state->arg_count);
+ if (ACPI_FAILURE (status)) {
+ goto close_this_op;
+ }
+ op = NULL;
+ continue;
+ }
+
+ /* All arguments have been processed -- Op is complete, prepare for next */
+
+ walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+ if (walk_state->op_info->flags & AML_NAMED) {
+ if (acpi_gbl_depth) {
+ acpi_gbl_depth--;
+ }
+
+ if (op->common.aml_opcode == AML_REGION_OP) {
+ /*
+ * Skip parsing of control method or opregion body,
+ * because we don't have enough info in the first pass
+ * to parse them correctly.
+ *
+ * Completed parsing an op_region declaration, we now
+ * know the length.
+ */
+ op->named.length = (u32) (parser_state->aml - op->named.data);
+ }
+ }
+
+ if (walk_state->op_info->flags & AML_CREATE) {
+ /*
+ * Backup to beginning of create_xXXfield declaration (1 for
+ * Opcode)
+ *
+ * body_length is unknown until we parse the body
+ */
+ op->named.length = (u32) (parser_state->aml - op->named.data);
+ }
+
+ /* This op complete, notify the dispatcher */
+
+ if (walk_state->ascending_callback != NULL) {
+ walk_state->op = op;
+ walk_state->opcode = op->common.aml_opcode;
+
+ status = walk_state->ascending_callback (walk_state);
+ status = acpi_ps_next_parse_state (walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_OK;
+ goto close_this_op;
+ }
+ }
+
+
+close_this_op:
+ /*
+ * Finished one argument of the containing scope
+ */
+ parser_state->scope->parse_scope.arg_count--;
+
+ /* Close this Op (will result in parse subtree deletion) */
+
+ acpi_ps_complete_this_op (walk_state, op);
+ op = NULL;
+ if (pre_op) {
+ acpi_ps_free_op (pre_op);
+ pre_op = NULL;
+ }
+
+ switch (status) {
+ case AE_OK:
+ break;
+
+
+ case AE_CTRL_TRANSFER:
+
+ /*
+ * We are about to transfer to a called method.
+ */
+ walk_state->prev_op = op;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS (status);
+
+
+ case AE_CTRL_END:
+
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+
+ if (op) {
+ walk_state->op = op;
+ walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+ walk_state->opcode = op->common.aml_opcode;
+
+ status = walk_state->ascending_callback (walk_state);
+ status = acpi_ps_next_parse_state (walk_state, op, status);
+
+ acpi_ps_complete_this_op (walk_state, op);
+ op = NULL;
+ }
+ status = AE_OK;
+ break;
+
+
+ case AE_CTRL_BREAK:
+ case AE_CTRL_CONTINUE:
+
+ /* Pop off scopes until we find the While */
+
+ while (!op || (op->common.aml_opcode != AML_WHILE_OP)) {
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+ }
+
+ /* Close this iteration of the While loop */
+
+ walk_state->op = op;
+ walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+ walk_state->opcode = op->common.aml_opcode;
+
+ status = walk_state->ascending_callback (walk_state);
+ status = acpi_ps_next_parse_state (walk_state, op, status);
+
+ acpi_ps_complete_this_op (walk_state, op);
+ op = NULL;
+
+ status = AE_OK;
+ break;
+
+
+ case AE_CTRL_TERMINATE:
+
+ status = AE_OK;
+
+ /* Clean up */
+ do {
+ if (op) {
+ acpi_ps_complete_this_op (walk_state, op);
+ }
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+
+ } while (op);
+
+ return_ACPI_STATUS (status);
+
+
+ default: /* All other non-AE_OK status */
+
+ do {
+ if (op) {
+ acpi_ps_complete_this_op (walk_state, op);
+ }
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+
+ } while (op);
+
+
+ /*
+ * TBD: Cleanup parse ops on error
+ */
+#if 0
+ if (op == NULL) {
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+ }
+#endif
+ walk_state->prev_op = op;
+ walk_state->prev_arg_types = walk_state->arg_types;
+ return_ACPI_STATUS (status);
+ }
+
+ /* This scope complete? */
+
+ if (acpi_ps_has_completed_scope (parser_state)) {
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", op));
+ }
+ else {
+ op = NULL;
+ }
+
+ } /* while parser_state->Aml */
+
+
+ /*
+ * Complete the last Op (if not completed), and clear the scope stack.
+ * It is easily possible to end an AML "package" with an unbounded number
+ * of open scopes (such as when several ASL blocks are closed with
+ * sequential closing braces). We want to terminate each one cleanly.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "AML package complete at Op %p\n", op));
+ do {
+ if (op) {
+ if (walk_state->ascending_callback != NULL) {
+ walk_state->op = op;
+ walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+ walk_state->opcode = op->common.aml_opcode;
+
+ status = walk_state->ascending_callback (walk_state);
+ status = acpi_ps_next_parse_state (walk_state, op, status);
+ if (status == AE_CTRL_PENDING) {
+ status = AE_OK;
+ goto close_this_op;
+ }
+
+ if (status == AE_CTRL_TERMINATE) {
+ status = AE_OK;
+
+ /* Clean up */
+ do {
+ if (op) {
+ acpi_ps_complete_this_op (walk_state, op);
+ }
+
+ acpi_ps_pop_scope (parser_state, &op,
+ &walk_state->arg_types, &walk_state->arg_count);
+
+ } while (op);
+
+ return_ACPI_STATUS (status);
+ }
+
+ else if (ACPI_FAILURE (status)) {
+ acpi_ps_complete_this_op (walk_state, op);
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ acpi_ps_complete_this_op (walk_state, op);
+ }
+
+ acpi_ps_pop_scope (parser_state, &op, &walk_state->arg_types,
+ &walk_state->arg_count);
+
+ } while (op);
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_parse_aml
+ *
+ * PARAMETERS: start_scope - The starting point of the parse. Becomes the
+ * root of the parsed op tree.
+ * Aml - Pointer to the raw AML code to parse
+ * aml_size - Length of the AML to parse
+ *
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Parse raw AML and return a tree of ops
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_parse_aml (
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ acpi_status terminate_status;
+ struct acpi_thread_state *thread;
+ struct acpi_thread_state *prev_walk_list = acpi_gbl_current_walk_list;
+ struct acpi_walk_state *previous_walk_state;
+
+
+ ACPI_FUNCTION_TRACE ("ps_parse_aml");
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Entered with walk_state=%p Aml=%p size=%X\n",
+ walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size));
+
+
+ /* Create and initialize a new thread state */
+
+ thread = acpi_ut_create_thread_state ();
+ if (!thread) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ walk_state->thread = thread;
+ acpi_ds_push_walk_state (walk_state, thread);
+
+ /*
+ * This global allows the AML debugger to get a handle to the currently
+ * executing control method.
+ */
+ acpi_gbl_current_walk_list = thread;
+
+ /*
+ * Execute the walk loop as long as there is a valid Walk State. This
+ * handles nested control method invocations without recursion.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "State=%p\n", walk_state));
+
+ status = AE_OK;
+ while (walk_state) {
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * The parse_loop executes AML until the method terminates
+ * or calls another method.
+ */
+ status = acpi_ps_parse_loop (walk_state);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "Completed one call to walk loop, %s State=%p\n",
+ acpi_format_exception (status), walk_state));
+
+ if (status == AE_CTRL_TRANSFER) {
+ /*
+ * A method call was detected.
+ * Transfer control to the called control method
+ */
+ status = acpi_ds_call_control_method (thread, walk_state, NULL);
+
+ /*
+ * If the transfer to the new method method call worked, a new walk
+ * state was created -- get it
+ */
+ walk_state = acpi_ds_get_current_walk_state (thread);
+ continue;
+ }
+ else if (status == AE_CTRL_TERMINATE) {
+ status = AE_OK;
+ }
+ else if ((status != AE_OK) && (walk_state->method_desc)) {
+ ACPI_REPORT_METHOD_ERROR ("Method execution failed",
+ walk_state->method_node, NULL, status);
+
+ /* Check for possible multi-thread reentrancy problem */
+
+ if ((status == AE_ALREADY_EXISTS) &&
+ (!walk_state->method_desc->method.semaphore)) {
+ /*
+ * This method is marked not_serialized, but it tried to create a named
+ * object, causing the second thread entrance to fail. We will workaround
+ * this by marking the method permanently as Serialized.
+ */
+ walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED;
+ walk_state->method_desc->method.concurrency = 1;
+ }
+ }
+
+ if (walk_state->method_desc) {
+ /* Decrement the thread count on the method parse tree */
+
+ if (walk_state->method_desc->method.thread_count) {
+ walk_state->method_desc->method.thread_count--;
+ }
+ }
+
+ /* We are done with this walk, move on to the parent if any */
+
+ walk_state = acpi_ds_pop_walk_state (thread);
+
+ /* Reset the current scope to the beginning of scope stack */
+
+ acpi_ds_scope_stack_clear (walk_state);
+
+ /*
+ * If we just returned from the execution of a control method,
+ * there's lots of cleanup to do
+ */
+ if ((walk_state->parse_flags & ACPI_PARSE_MODE_MASK) == ACPI_PARSE_EXECUTE) {
+ terminate_status = acpi_ds_terminate_control_method (walk_state);
+ if (ACPI_FAILURE (terminate_status)) {
+ ACPI_REPORT_ERROR ((
+ "Could not terminate control method properly\n"));
+
+ /* Ignore error and continue */
+ }
+ }
+
+ /* Delete this walk state and all linked control states */
+
+ acpi_ps_cleanup_scope (&walk_state->parser_state);
+
+ previous_walk_state = walk_state;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, implicit_value=%p State=%p\n",
+ walk_state->return_desc, walk_state->implicit_return_obj, walk_state));
+
+ /* Check if we have restarted a preempted walk */
+
+ walk_state = acpi_ds_get_current_walk_state (thread);
+ if (walk_state) {
+ if (ACPI_SUCCESS (status)) {
+ /*
+ * There is another walk state, restart it.
+ * If the method return value is not used by the parent,
+ * The object is deleted
+ */
+ if (!previous_walk_state->return_desc) {
+ status = acpi_ds_restart_control_method (walk_state,
+ previous_walk_state->implicit_return_obj);
+ }
+ else {
+ /*
+ * We have a valid return value, delete any implicit
+ * return value.
+ */
+ acpi_ds_clear_implicit_return (previous_walk_state);
+
+ status = acpi_ds_restart_control_method (walk_state,
+ previous_walk_state->return_desc);
+ }
+ if (ACPI_SUCCESS (status)) {
+ walk_state->walk_type |= ACPI_WALK_METHOD_RESTART;
+ }
+ }
+ else {
+ /* On error, delete any return object */
+
+ acpi_ut_remove_reference (previous_walk_state->return_desc);
+ }
+ }
+
+ /*
+ * Just completed a 1st-level method, save the final internal return
+ * value (if any)
+ */
+ else if (previous_walk_state->caller_return_desc) {
+ if (previous_walk_state->implicit_return_obj) {
+ *(previous_walk_state->caller_return_desc) = previous_walk_state->implicit_return_obj;
+ }
+ else {
+ /* NULL if no return value */
+
+ *(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc;
+ }
+ }
+ else {
+ if (previous_walk_state->return_desc) {
+ /* Caller doesn't want it, must delete it */
+
+ acpi_ut_remove_reference (previous_walk_state->return_desc);
+ }
+ if (previous_walk_state->implicit_return_obj) {
+ /* Caller doesn't want it, must delete it */
+
+ acpi_ut_remove_reference (previous_walk_state->implicit_return_obj);
+ }
+ }
+
+ acpi_ds_delete_walk_state (previous_walk_state);
+ }
+
+ /* Normal exit */
+
+ acpi_ex_release_all_mutexes (thread);
+ acpi_ut_delete_generic_state (ACPI_CAST_PTR (union acpi_generic_state, thread));
+ acpi_gbl_current_walk_list = prev_walk_list;
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
new file mode 100644
index 000000000000..dcbed49608b0
--- /dev/null
+++ b/drivers/acpi/parser/psscope.c
@@ -0,0 +1,290 @@
+/******************************************************************************
+ *
+ * Module Name: psscope - Parser scope stack management routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("psscope")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_parent_scope
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Pointer to an Op object
+ *
+ * DESCRIPTION: Get parent of current op being parsed
+ *
+ ******************************************************************************/
+
+union acpi_parse_object *
+acpi_ps_get_parent_scope (
+ struct acpi_parse_state *parser_state)
+{
+ return (parser_state->scope->parse_scope.op);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_has_completed_scope
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Boolean, TRUE = scope completed.
+ *
+ * DESCRIPTION: Is parsing of current argument complete? Determined by
+ * 1) AML pointer is at or beyond the end of the scope
+ * 2) The scope argument count has reached zero.
+ *
+ ******************************************************************************/
+
+u8
+acpi_ps_has_completed_scope (
+ struct acpi_parse_state *parser_state)
+{
+ return ((u8) ((parser_state->aml >= parser_state->scope->parse_scope.arg_end ||
+ !parser_state->scope->parse_scope.arg_count)));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_init_scope
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ * Root - the Root Node of this new scope
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate and init a new scope object
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_init_scope (
+ struct acpi_parse_state *parser_state,
+ union acpi_parse_object *root_op)
+{
+ union acpi_generic_state *scope;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_init_scope", root_op);
+
+
+ scope = acpi_ut_create_generic_state ();
+ if (!scope) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ scope->common.data_type = ACPI_DESC_TYPE_STATE_RPSCOPE;
+ scope->parse_scope.op = root_op;
+ scope->parse_scope.arg_count = ACPI_VAR_ARGS;
+ scope->parse_scope.arg_end = parser_state->aml_end;
+ scope->parse_scope.pkg_end = parser_state->aml_end;
+
+ parser_state->scope = scope;
+ parser_state->start_op = root_op;
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_push_scope
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ * Op - Current op to be pushed
+ * remaining_args - List of args remaining
+ * arg_count - Fixed or variable number of args
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push current op to begin parsing its argument
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ps_push_scope (
+ struct acpi_parse_state *parser_state,
+ union acpi_parse_object *op,
+ u32 remaining_args,
+ u32 arg_count)
+{
+ union acpi_generic_state *scope;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_push_scope", op);
+
+
+ scope = acpi_ut_create_generic_state ();
+ if (!scope) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE;
+ scope->parse_scope.op = op;
+ scope->parse_scope.arg_list = remaining_args;
+ scope->parse_scope.arg_count = arg_count;
+ scope->parse_scope.pkg_end = parser_state->pkg_end;
+
+ /* Push onto scope stack */
+
+ acpi_ut_push_generic_state (&parser_state->scope, scope);
+
+ if (arg_count == ACPI_VAR_ARGS) {
+ /* multiple arguments */
+
+ scope->parse_scope.arg_end = parser_state->pkg_end;
+ }
+ else {
+ /* single argument */
+
+ scope->parse_scope.arg_end = ACPI_TO_POINTER (ACPI_MAX_PTR);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_pop_scope
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ * Op - Where the popped op is returned
+ * arg_list - Where the popped "next argument" is
+ * returned
+ * arg_count - Count of objects in arg_list
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return to parsing a previous op
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_pop_scope (
+ struct acpi_parse_state *parser_state,
+ union acpi_parse_object **op,
+ u32 *arg_list,
+ u32 *arg_count)
+{
+ union acpi_generic_state *scope = parser_state->scope;
+
+
+ ACPI_FUNCTION_TRACE ("ps_pop_scope");
+
+
+ /*
+ * Only pop the scope if there is in fact a next scope
+ */
+ if (scope->common.next) {
+ scope = acpi_ut_pop_generic_state (&parser_state->scope);
+
+ /* return to parsing previous op */
+
+ *op = scope->parse_scope.op;
+ *arg_list = scope->parse_scope.arg_list;
+ *arg_count = scope->parse_scope.arg_count;
+ parser_state->pkg_end = scope->parse_scope.pkg_end;
+
+ /* All done with this scope state structure */
+
+ acpi_ut_delete_generic_state (scope);
+ }
+ else {
+ /* empty parse stack, prepare to fetch next opcode */
+
+ *op = NULL;
+ *arg_list = 0;
+ *arg_count = 0;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count));
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_cleanup_scope
+ *
+ * PARAMETERS: parser_state - Current parser state object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Destroy available list, remaining stack levels, and return
+ * root scope
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_cleanup_scope (
+ struct acpi_parse_state *parser_state)
+{
+ union acpi_generic_state *scope;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_cleanup_scope", parser_state);
+
+
+ if (!parser_state) {
+ return_VOID;
+ }
+
+ /* Delete anything on the scope stack */
+
+ while (parser_state->scope) {
+ scope = acpi_ut_pop_generic_state (&parser_state->scope);
+ acpi_ut_delete_generic_state (scope);
+ }
+
+ return_VOID;
+}
+
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
new file mode 100644
index 000000000000..2140bd1ac10b
--- /dev/null
+++ b/drivers/acpi/parser/pstree.c
@@ -0,0 +1,327 @@
+/******************************************************************************
+ *
+ * Module Name: pstree - Parser op tree manipulation/traversal/search
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("pstree")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_arg
+ *
+ * PARAMETERS: Op - Get an argument for this op
+ * Argn - Nth argument to get
+ *
+ * RETURN: The argument (as an Op object). NULL if argument does not exist
+ *
+ * DESCRIPTION: Get the specified op's argument.
+ *
+ ******************************************************************************/
+
+union acpi_parse_object *
+acpi_ps_get_arg (
+ union acpi_parse_object *op,
+ u32 argn)
+{
+ union acpi_parse_object *arg = NULL;
+ const struct acpi_opcode_info *op_info;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Get the info structure for this opcode */
+
+ op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+ if (op_info->class == AML_CLASS_UNKNOWN) {
+ /* Invalid opcode or ASCII character */
+
+ return (NULL);
+ }
+
+ /* Check if this opcode requires argument sub-objects */
+
+ if (!(op_info->flags & AML_HAS_ARGS)) {
+ /* Has no linked argument objects */
+
+ return (NULL);
+ }
+
+ /* Get the requested argument object */
+
+ arg = op->common.value.arg;
+ while (arg && argn) {
+ argn--;
+ arg = arg->common.next;
+ }
+
+ return (arg);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_append_arg
+ *
+ * PARAMETERS: Op - Append an argument to this Op.
+ * Arg - Argument Op to append
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Append an argument to an op's argument list (a NULL arg is OK)
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_append_arg (
+ union acpi_parse_object *op,
+ union acpi_parse_object *arg)
+{
+ union acpi_parse_object *prev_arg;
+ const struct acpi_opcode_info *op_info;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (!op) {
+ return;
+ }
+
+ /* Get the info structure for this opcode */
+
+ op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
+ if (op_info->class == AML_CLASS_UNKNOWN) {
+ /* Invalid opcode */
+
+ ACPI_REPORT_ERROR (("ps_append_arg: Invalid AML Opcode: 0x%2.2X\n",
+ op->common.aml_opcode));
+ return;
+ }
+
+ /* Check if this opcode requires argument sub-objects */
+
+ if (!(op_info->flags & AML_HAS_ARGS)) {
+ /* Has no linked argument objects */
+
+ return;
+ }
+
+
+ /* Append the argument to the linked argument list */
+
+ if (op->common.value.arg) {
+ /* Append to existing argument list */
+
+ prev_arg = op->common.value.arg;
+ while (prev_arg->common.next) {
+ prev_arg = prev_arg->common.next;
+ }
+ prev_arg->common.next = arg;
+ }
+
+ else {
+ /* No argument list, this will be the first argument */
+
+ op->common.value.arg = arg;
+ }
+
+
+ /* Set the parent in this arg and any args linked after it */
+
+ while (arg) {
+ arg->common.parent = op;
+ arg = arg->common.next;
+ }
+}
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_child
+ *
+ * PARAMETERS: Op - Get the child of this Op
+ *
+ * RETURN: Child Op, Null if none is found.
+ *
+ * DESCRIPTION: Get op's children or NULL if none
+ *
+ ******************************************************************************/
+union acpi_parse_object *
+acpi_ps_get_child (
+ union acpi_parse_object *op)
+{
+ union acpi_parse_object *child = NULL;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ switch (op->common.aml_opcode) {
+ case AML_SCOPE_OP:
+ case AML_ELSE_OP:
+ case AML_DEVICE_OP:
+ case AML_THERMAL_ZONE_OP:
+ case AML_INT_METHODCALL_OP:
+
+ child = acpi_ps_get_arg (op, 0);
+ break;
+
+
+ case AML_BUFFER_OP:
+ case AML_PACKAGE_OP:
+ case AML_METHOD_OP:
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+ case AML_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 1);
+ break;
+
+
+ case AML_POWER_RES_OP:
+ case AML_INDEX_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 2);
+ break;
+
+
+ case AML_PROCESSOR_OP:
+ case AML_BANK_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 3);
+ break;
+
+
+ default:
+ /* All others have no children */
+ break;
+ }
+
+ return (child);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_depth_next
+ *
+ * PARAMETERS: Origin - Root of subtree to search
+ * Op - Last (previous) Op that was found
+ *
+ * RETURN: Next Op found in the search.
+ *
+ * DESCRIPTION: Get next op in tree (walking the tree in depth-first order)
+ * Return NULL when reaching "origin" or when walking up from root
+ *
+ ******************************************************************************/
+
+union acpi_parse_object *
+acpi_ps_get_depth_next (
+ union acpi_parse_object *origin,
+ union acpi_parse_object *op)
+{
+ union acpi_parse_object *next = NULL;
+ union acpi_parse_object *parent;
+ union acpi_parse_object *arg;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (!op) {
+ return (NULL);
+ }
+
+ /* look for an argument or child */
+
+ next = acpi_ps_get_arg (op, 0);
+ if (next) {
+ return (next);
+ }
+
+ /* look for a sibling */
+
+ next = op->common.next;
+ if (next) {
+ return (next);
+ }
+
+ /* look for a sibling of parent */
+
+ parent = op->common.parent;
+
+ while (parent) {
+ arg = acpi_ps_get_arg (parent, 0);
+ while (arg && (arg != origin) && (arg != op)) {
+ arg = arg->common.next;
+ }
+
+ if (arg == origin) {
+ /* reached parent of origin, end search */
+
+ return (NULL);
+ }
+
+ if (parent->common.next) {
+ /* found sibling of parent */
+
+ return (parent->common.next);
+ }
+
+ op = parent;
+ parent = parent->common.parent;
+ }
+
+ return (next);
+}
+
+#endif /* ACPI_FUTURE_USAGE */
+
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
new file mode 100644
index 000000000000..b3597cb19f88
--- /dev/null
+++ b/drivers/acpi/parser/psutils.c
@@ -0,0 +1,309 @@
+/******************************************************************************
+ *
+ * Module Name: psutils - Parser miscellaneous utilities (Parser only)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("psutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_create_scope_op
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: scope_op
+ *
+ * DESCRIPTION: Create a Scope and associated namepath op with the root name
+ *
+ ******************************************************************************/
+
+union acpi_parse_object *
+acpi_ps_create_scope_op (
+ void)
+{
+ union acpi_parse_object *scope_op;
+
+
+ scope_op = acpi_ps_alloc_op (AML_SCOPE_OP);
+ if (!scope_op) {
+ return (NULL);
+ }
+
+
+ scope_op->named.name = ACPI_ROOT_NAME;
+ return (scope_op);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_init_op
+ *
+ * PARAMETERS: Op - A newly allocated Op object
+ * Opcode - Opcode to store in the Op
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on
+ * opcode
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_init_op (
+ union acpi_parse_object *op,
+ u16 opcode)
+{
+ ACPI_FUNCTION_ENTRY ();
+
+
+ op->common.data_type = ACPI_DESC_TYPE_PARSER;
+ op->common.aml_opcode = opcode;
+
+ ACPI_DISASM_ONLY_MEMBERS (ACPI_STRNCPY (op->common.aml_op_name,
+ (acpi_ps_get_opcode_info (opcode))->name, sizeof (op->common.aml_op_name)));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_alloc_op
+ *
+ * PARAMETERS: Opcode - Opcode that will be stored in the new Op
+ *
+ * RETURN: Pointer to the new Op.
+ *
+ * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on
+ * opcode. A cache of opcodes is available for the pure
+ * GENERIC_OP, since this is by far the most commonly used.
+ *
+ ******************************************************************************/
+
+union acpi_parse_object*
+acpi_ps_alloc_op (
+ u16 opcode)
+{
+ union acpi_parse_object *op;
+ const struct acpi_opcode_info *op_info;
+ u8 flags = ACPI_PARSEOP_GENERIC;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ op_info = acpi_ps_get_opcode_info (opcode);
+
+ /* Determine type of parse_op required */
+
+ if (op_info->flags & AML_DEFER) {
+ flags = ACPI_PARSEOP_DEFERRED;
+ }
+ else if (op_info->flags & AML_NAMED) {
+ flags = ACPI_PARSEOP_NAMED;
+ }
+ else if (opcode == AML_INT_BYTELIST_OP) {
+ flags = ACPI_PARSEOP_BYTELIST;
+ }
+
+ /* Allocate the minimum required size object */
+
+ if (flags == ACPI_PARSEOP_GENERIC) {
+ /* The generic op (default) is by far the most common (16 to 1) */
+
+ op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE);
+ }
+ else {
+ /* Extended parseop */
+
+ op = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_PSNODE_EXT);
+ }
+
+ /* Initialize the Op */
+
+ if (op) {
+ acpi_ps_init_op (op, opcode);
+ op->common.flags = flags;
+ }
+
+ return (op);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_free_op
+ *
+ * PARAMETERS: Op - Op to be freed
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free an Op object. Either put it on the GENERIC_OP cache list
+ * or actually free it.
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_free_op (
+ union acpi_parse_object *op)
+{
+ ACPI_FUNCTION_NAME ("ps_free_op");
+
+
+ if (op->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Free retval op: %p\n", op));
+ }
+
+ if (op->common.flags & ACPI_PARSEOP_GENERIC) {
+ acpi_ut_release_to_cache (ACPI_MEM_LIST_PSNODE, op);
+ }
+ else {
+ acpi_ut_release_to_cache (ACPI_MEM_LIST_PSNODE_EXT, op);
+ }
+}
+
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_delete_parse_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Free all objects that are on the parse cache list.
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_delete_parse_cache (
+ void)
+{
+ ACPI_FUNCTION_TRACE ("ps_delete_parse_cache");
+
+
+ acpi_ut_delete_generic_cache (ACPI_MEM_LIST_PSNODE);
+ acpi_ut_delete_generic_cache (ACPI_MEM_LIST_PSNODE_EXT);
+ return_VOID;
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: Utility functions
+ *
+ * DESCRIPTION: Low level character and object functions
+ *
+ ******************************************************************************/
+
+
+/*
+ * Is "c" a namestring lead character?
+ */
+u8
+acpi_ps_is_leading_char (
+ u32 c)
+{
+ return ((u8) (c == '_' || (c >= 'A' && c <= 'Z')));
+}
+
+
+/*
+ * Is "c" a namestring prefix character?
+ */
+u8
+acpi_ps_is_prefix_char (
+ u32 c)
+{
+ return ((u8) (c == '\\' || c == '^'));
+}
+
+
+/*
+ * Get op's name (4-byte name segment) or 0 if unnamed
+ */
+#ifdef ACPI_FUTURE_USAGE
+u32
+acpi_ps_get_name (
+ union acpi_parse_object *op)
+{
+
+
+ /* The "generic" object has no name associated with it */
+
+ if (op->common.flags & ACPI_PARSEOP_GENERIC) {
+ return (0);
+ }
+
+ /* Only the "Extended" parse objects have a name */
+
+ return (op->named.name);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*
+ * Set op's name
+ */
+void
+acpi_ps_set_name (
+ union acpi_parse_object *op,
+ u32 name)
+{
+
+ /* The "generic" object has no name associated with it */
+
+ if (op->common.flags & ACPI_PARSEOP_GENERIC) {
+ return;
+ }
+
+ op->named.name = name;
+}
+
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
new file mode 100644
index 000000000000..110d2ce917b6
--- /dev/null
+++ b/drivers/acpi/parser/pswalk.c
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * Module Name: pswalk - Parser routines to walk parsed op tree(s)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("pswalk")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_delete_parse_tree
+ *
+ * PARAMETERS: subtree_root - Root of tree (or subtree) to delete
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Delete a portion of or an entire parse tree.
+ *
+ ******************************************************************************/
+
+void
+acpi_ps_delete_parse_tree (
+ union acpi_parse_object *subtree_root)
+{
+ union acpi_parse_object *op = subtree_root;
+ union acpi_parse_object *next = NULL;
+ union acpi_parse_object *parent = NULL;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ps_delete_parse_tree", subtree_root);
+
+
+ /* Visit all nodes in the subtree */
+
+ while (op) {
+ /* Check if we are not ascending */
+
+ if (op != parent) {
+ /* Look for an argument or child of the current op */
+
+ next = acpi_ps_get_arg (op, 0);
+ if (next) {
+ /* Still going downward in tree (Op is not completed yet) */
+
+ op = next;
+ continue;
+ }
+ }
+
+ /*
+ * No more children, this Op is complete.
+ */
+ next = op->common.next;
+ parent = op->common.parent;
+
+ acpi_ps_free_op (op);
+
+ /*
+ * If we are back to the starting point, the walk is complete.
+ */
+ if (op == subtree_root) {
+ return_VOID;
+ }
+ if (next) {
+ op = next;
+ }
+ else {
+ op = parent;
+ }
+ }
+ return_VOID;
+}
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
new file mode 100644
index 000000000000..b318ad24726d
--- /dev/null
+++ b/drivers/acpi/parser/psxface.c
@@ -0,0 +1,243 @@
+/******************************************************************************
+ *
+ * Module Name: psxface - Parser external interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acparser.h>
+#include <acpi/acdispat.h>
+#include <acpi/acinterp.h>
+#include <acpi/acnamesp.h>
+
+
+#define _COMPONENT ACPI_PARSER
+ ACPI_MODULE_NAME ("psxface")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_psx_execute
+ *
+ * PARAMETERS: Info->Node - A method object containing both the AML
+ * address and length.
+ * **Params - List of parameters to pass to method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ * **return_obj_desc - Return object from execution of the
+ * method.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Execute a control method
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_psx_execute (
+ struct acpi_parameter_info *info)
+{
+ acpi_status status;
+ union acpi_operand_object *obj_desc;
+ u32 i;
+ union acpi_parse_object *op;
+ struct acpi_walk_state *walk_state;
+
+
+ ACPI_FUNCTION_TRACE ("psx_execute");
+
+
+ /* Validate the Node and get the attached object */
+
+ if (!info || !info->node) {
+ return_ACPI_STATUS (AE_NULL_ENTRY);
+ }
+
+ obj_desc = acpi_ns_get_attached_object (info->node);
+ if (!obj_desc) {
+ return_ACPI_STATUS (AE_NULL_OBJECT);
+ }
+
+ /* Init for new method, wait on concurrency semaphore */
+
+ status = acpi_ds_begin_method_execution (info->node, obj_desc, NULL);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if ((info->parameter_type == ACPI_PARAM_ARGS) &&
+ (info->parameters)) {
+ /*
+ * The caller "owns" the parameters, so give each one an extra
+ * reference
+ */
+ for (i = 0; info->parameters[i]; i++) {
+ acpi_ut_add_reference (info->parameters[i]);
+ }
+ }
+
+ /*
+ * 1) Perform the first pass parse of the method to enter any
+ * named objects that it creates into the namespace
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "**** Begin Method Parse **** Entry=%p obj=%p\n",
+ info->node, obj_desc));
+
+ /* Create and init a Root Node */
+
+ op = acpi_ps_create_scope_op ();
+ if (!op) {
+ status = AE_NO_MEMORY;
+ goto cleanup1;
+ }
+
+ /*
+ * Get a new owner_id for objects created by this method. Namespace
+ * objects (such as Operation Regions) can be created during the
+ * first pass parse.
+ */
+ obj_desc->method.owning_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_METHOD);
+
+ /* Create and initialize a new walk state */
+
+ walk_state = acpi_ds_create_walk_state (obj_desc->method.owning_id,
+ NULL, NULL, NULL);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup2;
+ }
+
+ status = acpi_ds_init_aml_walk (walk_state, op, info->node,
+ obj_desc->method.aml_start,
+ obj_desc->method.aml_length, NULL, 1);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup3;
+ }
+
+ /* Parse the AML */
+
+ status = acpi_ps_parse_aml (walk_state);
+ acpi_ps_delete_parse_tree (op);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup1; /* Walk state is already deleted */
+ }
+
+ /*
+ * 2) Execute the method. Performs second pass parse simultaneously
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "**** Begin Method Execution **** Entry=%p obj=%p\n",
+ info->node, obj_desc));
+
+ /* Create and init a Root Node */
+
+ op = acpi_ps_create_scope_op ();
+ if (!op) {
+ status = AE_NO_MEMORY;
+ goto cleanup1;
+ }
+
+ /* Init new op with the method name and pointer back to the NS node */
+
+ acpi_ps_set_name (op, info->node->name.integer);
+ op->common.node = info->node;
+
+ /* Create and initialize a new walk state */
+
+ walk_state = acpi_ds_create_walk_state (0, NULL, NULL, NULL);
+ if (!walk_state) {
+ status = AE_NO_MEMORY;
+ goto cleanup2;
+ }
+
+ status = acpi_ds_init_aml_walk (walk_state, op, info->node,
+ obj_desc->method.aml_start,
+ obj_desc->method.aml_length, info, 3);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup3;
+ }
+
+ /*
+ * The walk of the parse tree is where we actually execute the method
+ */
+ status = acpi_ps_parse_aml (walk_state);
+ goto cleanup2; /* Walk state already deleted */
+
+
+cleanup3:
+ acpi_ds_delete_walk_state (walk_state);
+
+cleanup2:
+ acpi_ps_delete_parse_tree (op);
+
+cleanup1:
+ if ((info->parameter_type == ACPI_PARAM_ARGS) &&
+ (info->parameters)) {
+ /* Take away the extra reference that we gave the parameters above */
+
+ for (i = 0; info->parameters[i]; i++) {
+ /* Ignore errors, just do them all */
+
+ (void) acpi_ut_update_object_reference (info->parameters[i], REF_DECREMENT);
+ }
+ }
+
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * If the method has returned an object, signal this to the caller with
+ * a control exception code
+ */
+ if (info->return_object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Method returned obj_desc=%p\n",
+ info->return_object));
+ ACPI_DUMP_STACK_ENTRY (info->return_object);
+
+ status = AE_CTRL_RETURN_VALUE;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
new file mode 100644
index 000000000000..5d19b39e9e2b
--- /dev/null
+++ b/drivers/acpi/pci_bind.c
@@ -0,0 +1,384 @@
+/*
+ * pci_bind.c - ACPI PCI Device Binding ($Revision: 2 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_PCI_COMPONENT
+ACPI_MODULE_NAME ("pci_bind")
+
+struct acpi_pci_data {
+ struct acpi_pci_id id;
+ struct pci_bus *bus;
+ struct pci_dev *dev;
+};
+
+
+void
+acpi_pci_data_handler (
+ acpi_handle handle,
+ u32 function,
+ void *context)
+{
+ ACPI_FUNCTION_TRACE("acpi_pci_data_handler");
+
+ /* TBD: Anything we need to do here? */
+
+ return_VOID;
+}
+
+
+/**
+ * acpi_os_get_pci_id
+ * ------------------
+ * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem)
+ * to resolve PCI information for ACPI-PCI devices defined in the namespace.
+ * This typically occurs when resolving PCI operation region information.
+ */
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_os_get_pci_id (
+ acpi_handle handle,
+ struct acpi_pci_id *id)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_device *device = NULL;
+ struct acpi_pci_data *data = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_os_get_pci_id");
+
+ if (!id)
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid ACPI Bus context for device %s\n",
+ acpi_device_bid(device)));
+ return_ACPI_STATUS(AE_NOT_EXIST);
+ }
+
+ status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data);
+ if (ACPI_FAILURE(status) || !data || !data->dev) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid ACPI-PCI context for device %s\n",
+ acpi_device_bid(device)));
+ return_ACPI_STATUS(status);
+ }
+
+ *id = data->id;
+
+ /*
+ id->segment = data->id.segment;
+ id->bus = data->id.bus;
+ id->device = data->id.device;
+ id->function = data->id.function;
+ */
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Device %s has PCI address %02x:%02x:%02x.%02x\n",
+ acpi_device_bid(device), id->segment, id->bus,
+ id->device, id->function));
+
+ return_ACPI_STATUS(AE_OK);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+int
+acpi_pci_bind (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_pci_data *data = NULL;
+ struct acpi_pci_data *pdata = NULL;
+ char *pathname = NULL;
+ struct acpi_buffer buffer = {0, NULL};
+ acpi_handle handle = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_bind");
+
+ if (!device || !device->parent)
+ return_VALUE(-EINVAL);
+
+ pathname = kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ if(!pathname)
+ return_VALUE(-ENOMEM);
+ memset(pathname, 0, ACPI_PATHNAME_MAX);
+ buffer.length = ACPI_PATHNAME_MAX;
+ buffer.pointer = pathname;
+
+ data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
+ if (!data){
+ kfree (pathname);
+ return_VALUE(-ENOMEM);
+ }
+ memset(data, 0, sizeof(struct acpi_pci_data));
+
+ acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI device [%s]...\n",
+ pathname));
+
+ /*
+ * Segment & Bus
+ * -------------
+ * These are obtained via the parent device's ACPI-PCI context.
+ */
+ status = acpi_get_data(device->parent->handle, acpi_pci_data_handler,
+ (void**) &pdata);
+ if (ACPI_FAILURE(status) || !pdata || !pdata->bus) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid ACPI-PCI context for parent device %s\n",
+ acpi_device_bid(device->parent)));
+ result = -ENODEV;
+ goto end;
+ }
+ data->id.segment = pdata->id.segment;
+ data->id.bus = pdata->bus->number;
+
+ /*
+ * Device & Function
+ * -----------------
+ * These are simply obtained from the device's _ADR method. Note
+ * that a value of zero is valid.
+ */
+ data->id.device = device->pnp.bus_address >> 16;
+ data->id.function = device->pnp.bus_address & 0xFFFF;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "...to %02x:%02x:%02x.%02x\n",
+ data->id.segment, data->id.bus, data->id.device,
+ data->id.function));
+
+ /*
+ * TBD: Support slot devices (e.g. function=0xFFFF).
+ */
+
+ /*
+ * Locate PCI Device
+ * -----------------
+ * Locate matching device in PCI namespace. If it doesn't exist
+ * this typically means that the device isn't currently inserted
+ * (e.g. docking station, port replicator, etc.).
+ */
+ data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function));
+ if (!data->dev) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
+ data->id.segment, data->id.bus,
+ data->id.device, data->id.function));
+ result = -ENODEV;
+ goto end;
+ }
+ if (!data->dev->bus) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Device %02x:%02x:%02x.%02x has invalid 'bus' field\n",
+ data->id.segment, data->id.bus,
+ data->id.device, data->id.function));
+ result = -ENODEV;
+ goto end;
+ }
+
+ /*
+ * PCI Bridge?
+ * -----------
+ * If so, set the 'bus' field and install the 'bind' function to
+ * facilitate callbacks for all of its children.
+ */
+ if (data->dev->subordinate) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Device %02x:%02x:%02x.%02x is a PCI bridge\n",
+ data->id.segment, data->id.bus,
+ data->id.device, data->id.function));
+ data->bus = data->dev->subordinate;
+ device->ops.bind = acpi_pci_bind;
+ device->ops.unbind = acpi_pci_unbind;
+ }
+
+ /*
+ * Attach ACPI-PCI Context
+ * -----------------------
+ * Thus binding the ACPI and PCI devices.
+ */
+ status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to attach ACPI-PCI context to device %s\n",
+ acpi_device_bid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+
+ /*
+ * PCI Routing Table
+ * -----------------
+ * Evaluate and parse _PRT, if exists. This code is independent of
+ * PCI bridges (above) to allow parsing of _PRT objects within the
+ * scope of non-bridge devices. Note that _PRTs within the scope of
+ * a PCI bridge assume the bridge's subordinate bus number.
+ *
+ * TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
+ */
+ status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
+ if (ACPI_SUCCESS(status)) {
+ if (data->bus) /* PCI-PCI bridge */
+ acpi_pci_irq_add_prt(device->handle, data->id.segment,
+ data->bus->number);
+ else /* non-bridge PCI device */
+ acpi_pci_irq_add_prt(device->handle, data->id.segment,
+ data->id.bus);
+ }
+
+end:
+ kfree(pathname);
+ if (result)
+ kfree(data);
+
+ return_VALUE(result);
+}
+
+int acpi_pci_unbind(
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_pci_data *data = NULL;
+ char *pathname = NULL;
+ struct acpi_buffer buffer = {0, NULL};
+
+ ACPI_FUNCTION_TRACE("acpi_pci_unbind");
+
+ if (!device || !device->parent)
+ return_VALUE(-EINVAL);
+
+ pathname = (char *) kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ if(!pathname)
+ return_VALUE(-ENOMEM);
+ memset(pathname, 0, ACPI_PATHNAME_MAX);
+
+ buffer.length = ACPI_PATHNAME_MAX;
+ buffer.pointer = pathname;
+ acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Unbinding PCI device [%s]...\n",
+ pathname));
+ kfree(pathname);
+
+ status = acpi_get_data(device->handle, acpi_pci_data_handler, (void**)&data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to get data from device %s\n",
+ acpi_device_bid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+
+ status = acpi_detach_data(device->handle, acpi_pci_data_handler);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to detach data from device %s\n",
+ acpi_device_bid(device)));
+ result = -ENODEV;
+ goto end;
+ }
+ if (data->dev->subordinate) {
+ acpi_pci_irq_del_prt(data->id.segment, data->bus->number);
+ }
+ kfree(data);
+
+end:
+ return_VALUE(result);
+}
+
+int
+acpi_pci_bind_root (
+ struct acpi_device *device,
+ struct acpi_pci_id *id,
+ struct pci_bus *bus)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_pci_data *data = NULL;
+ char *pathname = NULL;
+ struct acpi_buffer buffer = {0, NULL};
+
+ ACPI_FUNCTION_TRACE("acpi_pci_bind_root");
+
+ pathname = (char *)kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ if(!pathname)
+ return_VALUE(-ENOMEM);
+ memset(pathname, 0, ACPI_PATHNAME_MAX);
+
+ buffer.length = ACPI_PATHNAME_MAX;
+ buffer.pointer = pathname;
+
+ if (!device || !id || !bus){
+ kfree(pathname);
+ return_VALUE(-EINVAL);
+ }
+
+ data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
+ if (!data){
+ kfree(pathname);
+ return_VALUE(-ENOMEM);
+ }
+ memset(data, 0, sizeof(struct acpi_pci_data));
+
+ data->id = *id;
+ data->bus = bus;
+ device->ops.bind = acpi_pci_bind;
+ device->ops.unbind = acpi_pci_unbind;
+
+ acpi_get_name(device->handle, ACPI_FULL_PATHNAME, &buffer);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Binding PCI root bridge [%s] to "
+ "%02x:%02x\n", pathname, id->segment, id->bus));
+
+ status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to attach ACPI-PCI context to device %s\n",
+ pathname));
+ result = -ENODEV;
+ goto end;
+ }
+
+end:
+ kfree(pathname);
+ if (result != 0)
+ kfree(data);
+
+ return_VALUE(result);
+}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
new file mode 100644
index 000000000000..12b0eea63407
--- /dev/null
+++ b/drivers/acpi/pci_irq.c
@@ -0,0 +1,518 @@
+/*
+ * pci_irq.c - ACPI PCI Interrupt Routing ($Revision: 11 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2002 Dominik Brodowski <devel@brodo.de>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/config.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_PCI_COMPONENT
+ACPI_MODULE_NAME ("pci_irq")
+
+static struct acpi_prt_list acpi_prt;
+static DEFINE_SPINLOCK(acpi_prt_lock);
+
+/* --------------------------------------------------------------------------
+ PCI IRQ Routing Table (PRT) Support
+ -------------------------------------------------------------------------- */
+
+static struct acpi_prt_entry *
+acpi_pci_irq_find_prt_entry (
+ int segment,
+ int bus,
+ int device,
+ int pin)
+{
+ struct list_head *node = NULL;
+ struct acpi_prt_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_irq_find_prt_entry");
+
+ if (!acpi_prt.count)
+ return_PTR(NULL);
+
+ /*
+ * Parse through all PRT entries looking for a match on the specified
+ * PCI device's segment, bus, device, and pin (don't care about func).
+ *
+ */
+ spin_lock(&acpi_prt_lock);
+ list_for_each(node, &acpi_prt.entries) {
+ entry = list_entry(node, struct acpi_prt_entry, node);
+ if ((segment == entry->id.segment)
+ && (bus == entry->id.bus)
+ && (device == entry->id.device)
+ && (pin == entry->pin)) {
+ spin_unlock(&acpi_prt_lock);
+ return_PTR(entry);
+ }
+ }
+
+ spin_unlock(&acpi_prt_lock);
+ return_PTR(NULL);
+}
+
+
+static int
+acpi_pci_irq_add_entry (
+ acpi_handle handle,
+ int segment,
+ int bus,
+ struct acpi_pci_routing_table *prt)
+{
+ struct acpi_prt_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_irq_add_entry");
+
+ if (!prt)
+ return_VALUE(-EINVAL);
+
+ entry = kmalloc(sizeof(struct acpi_prt_entry), GFP_KERNEL);
+ if (!entry)
+ return_VALUE(-ENOMEM);
+ memset(entry, 0, sizeof(struct acpi_prt_entry));
+
+ entry->id.segment = segment;
+ entry->id.bus = bus;
+ entry->id.device = (prt->address >> 16) & 0xFFFF;
+ entry->id.function = prt->address & 0xFFFF;
+ entry->pin = prt->pin;
+
+ /*
+ * Type 1: Dynamic
+ * ---------------
+ * The 'source' field specifies the PCI interrupt link device used to
+ * configure the IRQ assigned to this slot|dev|pin. The 'source_index'
+ * indicates which resource descriptor in the resource template (of
+ * the link device) this interrupt is allocated from.
+ *
+ * NOTE: Don't query the Link Device for IRQ information at this time
+ * because Link Device enumeration may not have occurred yet
+ * (e.g. exists somewhere 'below' this _PRT entry in the ACPI
+ * namespace).
+ */
+ if (prt->source[0]) {
+ acpi_get_handle(handle, prt->source, &entry->link.handle);
+ entry->link.index = prt->source_index;
+ }
+ /*
+ * Type 2: Static
+ * --------------
+ * The 'source' field is NULL, and the 'source_index' field specifies
+ * the IRQ value, which is hardwired to specific interrupt inputs on
+ * the interrupt controller.
+ */
+ else
+ entry->link.index = prt->source_index;
+
+ ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
+ " %02X:%02X:%02X[%c] -> %s[%d]\n",
+ entry->id.segment, entry->id.bus, entry->id.device,
+ ('A' + entry->pin), prt->source, entry->link.index));
+
+ spin_lock(&acpi_prt_lock);
+ list_add_tail(&entry->node, &acpi_prt.entries);
+ acpi_prt.count++;
+ spin_unlock(&acpi_prt_lock);
+
+ return_VALUE(0);
+}
+
+
+static void
+acpi_pci_irq_del_entry (
+ int segment,
+ int bus,
+ struct acpi_prt_entry *entry)
+{
+ if (segment == entry->id.segment && bus == entry->id.bus){
+ acpi_prt.count--;
+ list_del(&entry->node);
+ kfree(entry);
+ }
+}
+
+
+int
+acpi_pci_irq_add_prt (
+ acpi_handle handle,
+ int segment,
+ int bus)
+{
+ acpi_status status = AE_OK;
+ char *pathname = NULL;
+ struct acpi_buffer buffer = {0, NULL};
+ struct acpi_pci_routing_table *prt = NULL;
+ struct acpi_pci_routing_table *entry = NULL;
+ static int first_time = 1;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_irq_add_prt");
+
+ pathname = (char *) kmalloc(ACPI_PATHNAME_MAX, GFP_KERNEL);
+ if(!pathname)
+ return_VALUE(-ENOMEM);
+ memset(pathname, 0, ACPI_PATHNAME_MAX);
+
+ if (first_time) {
+ acpi_prt.count = 0;
+ INIT_LIST_HEAD(&acpi_prt.entries);
+ first_time = 0;
+ }
+
+ /*
+ * NOTE: We're given a 'handle' to the _PRT object's parent device
+ * (either a PCI root bridge or PCI-PCI bridge).
+ */
+
+ buffer.length = ACPI_PATHNAME_MAX;
+ buffer.pointer = pathname;
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+ printk(KERN_DEBUG "ACPI: PCI Interrupt Routing Table [%s._PRT]\n",
+ pathname);
+
+ /*
+ * Evaluate this _PRT and add its entries to our global list (acpi_prt).
+ */
+
+ buffer.length = 0;
+ buffer.pointer = NULL;
+ kfree(pathname);
+ status = acpi_get_irq_routing_table(handle, &buffer);
+ if (status != AE_BUFFER_OVERFLOW) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
+ acpi_format_exception(status)));
+ return_VALUE(-ENODEV);
+ }
+
+ prt = kmalloc(buffer.length, GFP_KERNEL);
+ if (!prt){
+ return_VALUE(-ENOMEM);
+ }
+ memset(prt, 0, buffer.length);
+ buffer.pointer = prt;
+
+ status = acpi_get_irq_routing_table(handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRT [%s]\n",
+ acpi_format_exception(status)));
+ kfree(buffer.pointer);
+ return_VALUE(-ENODEV);
+ }
+
+ entry = prt;
+
+ while (entry && (entry->length > 0)) {
+ acpi_pci_irq_add_entry(handle, segment, bus, entry);
+ entry = (struct acpi_pci_routing_table *)
+ ((unsigned long) entry + entry->length);
+ }
+
+ kfree(prt);
+
+ return_VALUE(0);
+}
+
+void
+acpi_pci_irq_del_prt (int segment, int bus)
+{
+ struct list_head *node = NULL, *n = NULL;
+ struct acpi_prt_entry *entry = NULL;
+
+ if (!acpi_prt.count) {
+ return;
+ }
+
+ printk(KERN_DEBUG "ACPI: Delete PCI Interrupt Routing Table for %x:%x\n",
+ segment, bus);
+ spin_lock(&acpi_prt_lock);
+ list_for_each_safe(node, n, &acpi_prt.entries) {
+ entry = list_entry(node, struct acpi_prt_entry, node);
+
+ acpi_pci_irq_del_entry(segment, bus, entry);
+ }
+ spin_unlock(&acpi_prt_lock);
+}
+/* --------------------------------------------------------------------------
+ PCI Interrupt Routing Support
+ -------------------------------------------------------------------------- */
+
+/*
+ * acpi_pci_irq_lookup
+ * success: return IRQ >= 0
+ * failure: return -1
+ */
+static int
+acpi_pci_irq_lookup (
+ struct pci_bus *bus,
+ int device,
+ int pin,
+ int *edge_level,
+ int *active_high_low,
+ char **link)
+{
+ struct acpi_prt_entry *entry = NULL;
+ int segment = pci_domain_nr(bus);
+ int bus_nr = bus->number;
+ int irq;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_irq_lookup");
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Searching for PRT entry for %02x:%02x:%02x[%c]\n",
+ segment, bus_nr, device, ('A' + pin)));
+
+ entry = acpi_pci_irq_find_prt_entry(segment, bus_nr, device, pin);
+ if (!entry) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PRT entry not found\n"));
+ return_VALUE(-1);
+ }
+
+ if (entry->link.handle) {
+ irq = acpi_pci_link_get_irq(entry->link.handle,
+ entry->link.index, edge_level, active_high_low, link);
+ if (irq < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ link routing entry\n"));
+ return_VALUE(-1);
+ }
+ } else {
+ irq = entry->link.index;
+ *edge_level = ACPI_LEVEL_SENSITIVE;
+ *active_high_low = ACPI_ACTIVE_LOW;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", irq));
+
+ return_VALUE(irq);
+}
+
+/*
+ * acpi_pci_irq_derive
+ * success: return IRQ >= 0
+ * failure: return < 0
+ */
+static int
+acpi_pci_irq_derive (
+ struct pci_dev *dev,
+ int pin,
+ int *edge_level,
+ int *active_high_low,
+ char **link)
+{
+ struct pci_dev *bridge = dev;
+ int irq = -1;
+ u8 bridge_pin = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_irq_derive");
+
+ if (!dev)
+ return_VALUE(-EINVAL);
+
+ /*
+ * Attempt to derive an IRQ for this device from a parent bridge's
+ * PCI interrupt routing entry (eg. yenta bridge and add-in card bridge).
+ */
+ while (irq < 0 && bridge->bus->self) {
+ pin = (pin + PCI_SLOT(bridge->devfn)) % 4;
+ bridge = bridge->bus->self;
+
+ if ((bridge->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
+ /* PC card has the same IRQ as its cardbridge */
+ pci_read_config_byte(bridge, PCI_INTERRUPT_PIN, &bridge_pin);
+ if (!bridge_pin) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No interrupt pin configured for device %s\n", pci_name(bridge)));
+ return_VALUE(-1);
+ }
+ /* Pin is from 0 to 3 */
+ bridge_pin --;
+ pin = bridge_pin;
+ }
+
+ irq = acpi_pci_irq_lookup(bridge->bus, PCI_SLOT(bridge->devfn),
+ pin, edge_level, active_high_low, link);
+ }
+
+ if (irq < 0) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to derive IRQ for device %s\n", pci_name(dev)));
+ return_VALUE(-1);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Derive IRQ %d for device %s from %s\n",
+ irq, pci_name(dev), pci_name(bridge)));
+
+ return_VALUE(irq);
+}
+
+/*
+ * acpi_pci_irq_enable
+ * success: return 0
+ * failure: return < 0
+ */
+
+int
+acpi_pci_irq_enable (
+ struct pci_dev *dev)
+{
+ int irq = 0;
+ u8 pin = 0;
+ int edge_level = ACPI_LEVEL_SENSITIVE;
+ int active_high_low = ACPI_ACTIVE_LOW;
+ extern int via_interrupt_line_quirk;
+ char *link = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_irq_enable");
+
+ if (!dev)
+ return_VALUE(-EINVAL);
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (!pin) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No interrupt pin configured for device %s\n", pci_name(dev)));
+ return_VALUE(0);
+ }
+ pin--;
+
+ if (!dev->bus) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) 'bus' field\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ /*
+ * First we check the PCI IRQ routing table (PRT) for an IRQ. PRT
+ * values override any BIOS-assigned IRQs set during boot.
+ */
+ irq = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
+ &edge_level, &active_high_low, &link);
+
+ /*
+ * If no PRT entry was found, we'll try to derive an IRQ from the
+ * device's parent bridge.
+ */
+ if (irq < 0)
+ irq = acpi_pci_irq_derive(dev, pin, &edge_level,
+ &active_high_low, &link);
+
+ /*
+ * No IRQ known to the ACPI subsystem - maybe the BIOS /
+ * driver reported one, then use it. Exit in any case.
+ */
+ if (irq < 0) {
+ printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI",
+ pci_name(dev), ('A' + pin));
+ /* Interrupt Line values above 0xF are forbidden */
+ if (dev->irq >= 0 && (dev->irq <= 0xF)) {
+ printk(" - using IRQ %d\n", dev->irq);
+ return_VALUE(0);
+ }
+ else {
+ printk("\n");
+ return_VALUE(0);
+ }
+ }
+
+ if (via_interrupt_line_quirk)
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq & 15);
+
+ dev->irq = acpi_register_gsi(irq, edge_level, active_high_low);
+
+ printk(KERN_INFO PREFIX "PCI Interrupt %s[%c] -> ",
+ pci_name(dev), 'A' + pin);
+
+ if (link)
+ printk("Link [%s] -> ", link);
+
+ printk("GSI %u (%s, %s) -> IRQ %d\n", irq,
+ (edge_level == ACPI_LEVEL_SENSITIVE) ? "level" : "edge",
+ (active_high_low == ACPI_ACTIVE_LOW) ? "low" : "high",
+ dev->irq);
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_pci_irq_enable);
+
+
+#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
+void
+acpi_pci_irq_disable (
+ struct pci_dev *dev)
+{
+ int gsi = 0;
+ u8 pin = 0;
+ int edge_level = ACPI_LEVEL_SENSITIVE;
+ int active_high_low = ACPI_ACTIVE_LOW;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_irq_disable");
+
+ if (!dev)
+ return_VOID;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+ if (!pin)
+ return_VOID;
+ pin--;
+
+ if (!dev->bus)
+ return_VOID;
+
+ /*
+ * First we check the PCI IRQ routing table (PRT) for an IRQ.
+ */
+ gsi = acpi_pci_irq_lookup(dev->bus, PCI_SLOT(dev->devfn), pin,
+ &edge_level, &active_high_low, NULL);
+ /*
+ * If no PRT entry was found, we'll try to derive an IRQ from the
+ * device's parent bridge.
+ */
+ if (gsi < 0)
+ gsi = acpi_pci_irq_derive(dev, pin,
+ &edge_level, &active_high_low, NULL);
+ if (gsi < 0)
+ return_VOID;
+
+ /*
+ * TBD: It might be worth clearing dev->irq by magic constant
+ * (e.g. PCI_UNDEFINED_IRQ).
+ */
+
+ printk(KERN_INFO PREFIX "PCI interrupt for device %s disabled\n",
+ pci_name(dev));
+
+ acpi_unregister_gsi(gsi);
+
+ return_VOID;
+}
+#endif /* CONFIG_ACPI_DEALLOCATE_IRQ */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
new file mode 100644
index 000000000000..520b28ad0740
--- /dev/null
+++ b/drivers/acpi/pci_link.c
@@ -0,0 +1,904 @@
+/*
+ * pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 34 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2002 Dominik Brodowski <devel@brodo.de>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * TBD:
+ * 1. Support more than one IRQ resource entry per link device (index).
+ * 2. Implement start/stop mechanism and use ACPI Bus Driver facilities
+ * for IRQ management (e.g. start()->_SRS).
+ */
+
+#include <linux/sysdev.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_PCI_COMPONENT
+ACPI_MODULE_NAME ("pci_link")
+
+#define ACPI_PCI_LINK_CLASS "pci_irq_routing"
+#define ACPI_PCI_LINK_HID "PNP0C0F"
+#define ACPI_PCI_LINK_DRIVER_NAME "ACPI PCI Interrupt Link Driver"
+#define ACPI_PCI_LINK_DEVICE_NAME "PCI Interrupt Link"
+#define ACPI_PCI_LINK_FILE_INFO "info"
+#define ACPI_PCI_LINK_FILE_STATUS "state"
+
+#define ACPI_PCI_LINK_MAX_POSSIBLE 16
+
+static int acpi_pci_link_add (struct acpi_device *device);
+static int acpi_pci_link_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_pci_link_driver = {
+ .name = ACPI_PCI_LINK_DRIVER_NAME,
+ .class = ACPI_PCI_LINK_CLASS,
+ .ids = ACPI_PCI_LINK_HID,
+ .ops = {
+ .add = acpi_pci_link_add,
+ .remove = acpi_pci_link_remove,
+ },
+};
+
+struct acpi_pci_link_irq {
+ u8 active; /* Current IRQ */
+ u8 edge_level; /* All IRQs */
+ u8 active_high_low; /* All IRQs */
+ u8 initialized;
+ u8 resource_type;
+ u8 possible_count;
+ u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
+};
+
+struct acpi_pci_link {
+ struct list_head node;
+ struct acpi_device *device;
+ acpi_handle handle;
+ struct acpi_pci_link_irq irq;
+};
+
+static struct {
+ int count;
+ struct list_head entries;
+} acpi_link;
+
+
+/* --------------------------------------------------------------------------
+ PCI Link Device Management
+ -------------------------------------------------------------------------- */
+
+/*
+ * set context (link) possible list from resource list
+ */
+static acpi_status
+acpi_pci_link_check_possible (
+ struct acpi_resource *resource,
+ void *context)
+{
+ struct acpi_pci_link *link = (struct acpi_pci_link *) context;
+ u32 i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_check_possible");
+
+ switch (resource->id) {
+ case ACPI_RSTYPE_START_DPF:
+ return_ACPI_STATUS(AE_OK);
+ case ACPI_RSTYPE_IRQ:
+ {
+ struct acpi_resource_irq *p = &resource->data.irq;
+ if (!p || !p->number_of_interrupts) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Blank IRQ resource\n"));
+ return_ACPI_STATUS(AE_OK);
+ }
+ for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
+ if (!p->interrupts[i]) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i]));
+ continue;
+ }
+ link->irq.possible[i] = p->interrupts[i];
+ link->irq.possible_count++;
+ }
+ link->irq.edge_level = p->edge_level;
+ link->irq.active_high_low = p->active_high_low;
+ link->irq.resource_type = ACPI_RSTYPE_IRQ;
+ break;
+ }
+ case ACPI_RSTYPE_EXT_IRQ:
+ {
+ struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
+ if (!p || !p->number_of_interrupts) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Blank EXT IRQ resource\n"));
+ return_ACPI_STATUS(AE_OK);
+ }
+ for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_POSSIBLE); i++) {
+ if (!p->interrupts[i]) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid IRQ %d\n", p->interrupts[i]));
+ continue;
+ }
+ link->irq.possible[i] = p->interrupts[i];
+ link->irq.possible_count++;
+ }
+ link->irq.edge_level = p->edge_level;
+ link->irq.active_high_low = p->active_high_low;
+ link->irq.resource_type = ACPI_RSTYPE_EXT_IRQ;
+ break;
+ }
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Resource is not an IRQ entry\n"));
+ return_ACPI_STATUS(AE_OK);
+ }
+
+ return_ACPI_STATUS(AE_CTRL_TERMINATE);
+}
+
+
+static int
+acpi_pci_link_get_possible (
+ struct acpi_pci_link *link)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible");
+
+ if (!link)
+ return_VALUE(-EINVAL);
+
+ status = acpi_walk_resources(link->handle, METHOD_NAME__PRS,
+ acpi_pci_link_check_possible, link);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Found %d possible IRQs\n", link->irq.possible_count));
+
+ return_VALUE(0);
+}
+
+
+static acpi_status
+acpi_pci_link_check_current (
+ struct acpi_resource *resource,
+ void *context)
+{
+ int *irq = (int *) context;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_check_current");
+
+ switch (resource->id) {
+ case ACPI_RSTYPE_IRQ:
+ {
+ struct acpi_resource_irq *p = &resource->data.irq;
+ if (!p || !p->number_of_interrupts) {
+ /*
+ * IRQ descriptors may have no IRQ# bits set,
+ * particularly those those w/ _STA disabled
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Blank IRQ resource\n"));
+ return_ACPI_STATUS(AE_OK);
+ }
+ *irq = p->interrupts[0];
+ break;
+ }
+ case ACPI_RSTYPE_EXT_IRQ:
+ {
+ struct acpi_resource_ext_irq *p = &resource->data.extended_irq;
+ if (!p || !p->number_of_interrupts) {
+ /*
+ * extended IRQ descriptors must
+ * return at least 1 IRQ
+ */
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Blank EXT IRQ resource\n"));
+ return_ACPI_STATUS(AE_OK);
+ }
+ *irq = p->interrupts[0];
+ break;
+ }
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Resource isn't an IRQ\n"));
+ return_ACPI_STATUS(AE_OK);
+ }
+ return_ACPI_STATUS(AE_CTRL_TERMINATE);
+}
+
+/*
+ * Run _CRS and set link->irq.active
+ *
+ * return value:
+ * 0 - success
+ * !0 - failure
+ */
+static int
+acpi_pci_link_get_current (
+ struct acpi_pci_link *link)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ int irq = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_get_current");
+
+ if (!link || !link->handle)
+ return_VALUE(-EINVAL);
+
+ link->irq.active = 0;
+
+ /* in practice, status disabled is meaningless, ignore it */
+ if (acpi_strict) {
+ /* Query _STA, set link->device->status */
+ result = acpi_bus_get_status(link->device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
+ goto end;
+ }
+
+ if (!link->device->status.enabled) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link disabled\n"));
+ return_VALUE(0);
+ }
+ }
+
+ /*
+ * Query and parse _CRS to get the current IRQ assignment.
+ */
+
+ status = acpi_walk_resources(link->handle, METHOD_NAME__CRS,
+ acpi_pci_link_check_current, &irq);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ if (acpi_strict && !irq) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "_CRS returned 0\n"));
+ result = -ENODEV;
+ }
+
+ link->irq.active = irq;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n", link->irq.active));
+
+end:
+ return_VALUE(result);
+}
+
+static int
+acpi_pci_link_set (
+ struct acpi_pci_link *link,
+ int irq)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct {
+ struct acpi_resource res;
+ struct acpi_resource end;
+ } *resource;
+ struct acpi_buffer buffer = {0, NULL};
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_set");
+
+ if (!link || !irq)
+ return_VALUE(-EINVAL);
+
+ resource = kmalloc( sizeof(*resource)+1, GFP_KERNEL);
+ if(!resource)
+ return_VALUE(-ENOMEM);
+
+ memset(resource, 0, sizeof(*resource)+1);
+ buffer.length = sizeof(*resource) +1;
+ buffer.pointer = resource;
+
+ switch(link->irq.resource_type) {
+ case ACPI_RSTYPE_IRQ:
+ resource->res.id = ACPI_RSTYPE_IRQ;
+ resource->res.length = sizeof(struct acpi_resource);
+ resource->res.data.irq.edge_level = link->irq.edge_level;
+ resource->res.data.irq.active_high_low = link->irq.active_high_low;
+ if (link->irq.edge_level == ACPI_EDGE_SENSITIVE)
+ resource->res.data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+ else
+ resource->res.data.irq.shared_exclusive = ACPI_SHARED;
+ resource->res.data.irq.number_of_interrupts = 1;
+ resource->res.data.irq.interrupts[0] = irq;
+ break;
+
+ case ACPI_RSTYPE_EXT_IRQ:
+ resource->res.id = ACPI_RSTYPE_EXT_IRQ;
+ resource->res.length = sizeof(struct acpi_resource);
+ resource->res.data.extended_irq.producer_consumer = ACPI_CONSUMER;
+ resource->res.data.extended_irq.edge_level = link->irq.edge_level;
+ resource->res.data.extended_irq.active_high_low = link->irq.active_high_low;
+ if (link->irq.edge_level == ACPI_EDGE_SENSITIVE)
+ resource->res.data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+ else
+ resource->res.data.irq.shared_exclusive = ACPI_SHARED;
+ resource->res.data.extended_irq.number_of_interrupts = 1;
+ resource->res.data.extended_irq.interrupts[0] = irq;
+ /* ignore resource_source, it's optional */
+ break;
+ default:
+ printk("ACPI BUG: resource_type %d\n", link->irq.resource_type);
+ result = -EINVAL;
+ goto end;
+
+ }
+ resource->end.id = ACPI_RSTYPE_END_TAG;
+
+ /* Attempt to set the resource */
+ status = acpi_set_current_resources(link->handle, &buffer);
+
+ /* check for total failure */
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SRS\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ /* Query _STA, set device->status */
+ result = acpi_bus_get_status(link->device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
+ goto end;
+ }
+ if (!link->device->status.enabled) {
+ printk(KERN_WARNING PREFIX
+ "%s [%s] disabled and referenced, BIOS bug.\n",
+ acpi_device_name(link->device),
+ acpi_device_bid(link->device));
+ }
+
+ /* Query _CRS, set link->irq.active */
+ result = acpi_pci_link_get_current(link);
+ if (result) {
+ goto end;
+ }
+
+ /*
+ * Is current setting not what we set?
+ * set link->irq.active
+ */
+ if (link->irq.active != irq) {
+ /*
+ * policy: when _CRS doesn't return what we just _SRS
+ * assume _SRS worked and override _CRS value.
+ */
+ printk(KERN_WARNING PREFIX
+ "%s [%s] BIOS reported IRQ %d, using IRQ %d\n",
+ acpi_device_name(link->device),
+ acpi_device_bid(link->device),
+ link->irq.active, irq);
+ link->irq.active = irq;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", link->irq.active));
+
+end:
+ kfree(resource);
+ return_VALUE(result);
+}
+
+
+/* --------------------------------------------------------------------------
+ PCI Link IRQ Management
+ -------------------------------------------------------------------------- */
+
+/*
+ * "acpi_irq_balance" (default in APIC mode) enables ACPI to use PIC Interrupt
+ * Link Devices to move the PIRQs around to minimize sharing.
+ *
+ * "acpi_irq_nobalance" (default in PIC mode) tells ACPI not to move any PIC IRQs
+ * that the BIOS has already set to active. This is necessary because
+ * ACPI has no automatic means of knowing what ISA IRQs are used. Note that
+ * if the BIOS doesn't set a Link Device active, ACPI needs to program it
+ * even if acpi_irq_nobalance is set.
+ *
+ * A tables of penalties avoids directing PCI interrupts to well known
+ * ISA IRQs. Boot params are available to over-ride the default table:
+ *
+ * List interrupts that are free for PCI use.
+ * acpi_irq_pci=n[,m]
+ *
+ * List interrupts that should not be used for PCI:
+ * acpi_irq_isa=n[,m]
+ *
+ * Note that PCI IRQ routers have a list of possible IRQs,
+ * which may not include the IRQs this table says are available.
+ *
+ * Since this heuristic can't tell the difference between a link
+ * that no device will attach to, vs. a link which may be shared
+ * by multiple active devices -- it is not optimal.
+ *
+ * If interrupt performance is that important, get an IO-APIC system
+ * with a pin dedicated to each device. Or for that matter, an MSI
+ * enabled system.
+ */
+
+#define ACPI_MAX_IRQS 256
+#define ACPI_MAX_ISA_IRQ 16
+
+#define PIRQ_PENALTY_PCI_AVAILABLE (0)
+#define PIRQ_PENALTY_PCI_POSSIBLE (16*16)
+#define PIRQ_PENALTY_PCI_USING (16*16*16)
+#define PIRQ_PENALTY_ISA_TYPICAL (16*16*16*16)
+#define PIRQ_PENALTY_ISA_USED (16*16*16*16*16)
+#define PIRQ_PENALTY_ISA_ALWAYS (16*16*16*16*16*16)
+
+static int acpi_irq_penalty[ACPI_MAX_IRQS] = {
+ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ0 timer */
+ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ1 keyboard */
+ PIRQ_PENALTY_ISA_ALWAYS, /* IRQ2 cascade */
+ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ3 serial */
+ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ4 serial */
+ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ5 sometimes SoundBlaster */
+ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ6 */
+ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ7 parallel, spurious */
+ PIRQ_PENALTY_ISA_TYPICAL, /* IRQ8 rtc, sometimes */
+ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ9 PCI, often acpi */
+ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ10 PCI */
+ PIRQ_PENALTY_PCI_AVAILABLE, /* IRQ11 PCI */
+ PIRQ_PENALTY_ISA_USED, /* IRQ12 mouse */
+ PIRQ_PENALTY_ISA_USED, /* IRQ13 fpe, sometimes */
+ PIRQ_PENALTY_ISA_USED, /* IRQ14 ide0 */
+ PIRQ_PENALTY_ISA_USED, /* IRQ15 ide1 */
+ /* >IRQ15 */
+};
+
+int __init
+acpi_irq_penalty_init(void)
+{
+ struct list_head *node = NULL;
+ struct acpi_pci_link *link = NULL;
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_irq_penalty_init");
+
+ /*
+ * Update penalties to facilitate IRQ balancing.
+ */
+ list_for_each(node, &acpi_link.entries) {
+
+ link = list_entry(node, struct acpi_pci_link, node);
+ if (!link) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+ continue;
+ }
+
+ /*
+ * reflect the possible and active irqs in the penalty table --
+ * useful for breaking ties.
+ */
+ if (link->irq.possible_count) {
+ int penalty = PIRQ_PENALTY_PCI_POSSIBLE / link->irq.possible_count;
+
+ for (i = 0; i < link->irq.possible_count; i++) {
+ if (link->irq.possible[i] < ACPI_MAX_ISA_IRQ)
+ acpi_irq_penalty[link->irq.possible[i]] += penalty;
+ }
+
+ } else if (link->irq.active) {
+ acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_POSSIBLE;
+ }
+ }
+ /* Add a penalty for the SCI */
+ acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
+
+ return_VALUE(0);
+}
+
+static int acpi_irq_balance; /* 0: static, 1: balance */
+
+static int acpi_pci_link_allocate(
+ struct acpi_pci_link *link)
+{
+ int irq;
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
+
+ if (link->irq.initialized)
+ return_VALUE(0);
+
+ /*
+ * search for active IRQ in list of possible IRQs.
+ */
+ for (i = 0; i < link->irq.possible_count; ++i) {
+ if (link->irq.active == link->irq.possible[i])
+ break;
+ }
+ /*
+ * forget active IRQ that is not in possible list
+ */
+ if (i == link->irq.possible_count) {
+ if (acpi_strict)
+ printk(KERN_WARNING PREFIX "_CRS %d not found"
+ " in _PRS\n", link->irq.active);
+ link->irq.active = 0;
+ }
+
+ /*
+ * if active found, use it; else pick entry from end of possible list.
+ */
+ if (link->irq.active) {
+ irq = link->irq.active;
+ } else {
+ irq = link->irq.possible[link->irq.possible_count - 1];
+ }
+
+ if (acpi_irq_balance || !link->irq.active) {
+ /*
+ * Select the best IRQ. This is done in reverse to promote
+ * the use of IRQs 9, 10, 11, and >15.
+ */
+ for (i = (link->irq.possible_count - 1); i >= 0; i--) {
+ if (acpi_irq_penalty[irq] > acpi_irq_penalty[link->irq.possible[i]])
+ irq = link->irq.possible[i];
+ }
+ }
+
+ /* Attempt to enable the link device at this IRQ. */
+ if (acpi_pci_link_set(link, irq)) {
+ printk(PREFIX "Unable to set IRQ for %s [%s] (likely buggy ACPI BIOS).\n"
+ "Try pci=noacpi or acpi=off\n",
+ acpi_device_name(link->device),
+ acpi_device_bid(link->device));
+ return_VALUE(-ENODEV);
+ } else {
+ acpi_irq_penalty[link->irq.active] += PIRQ_PENALTY_PCI_USING;
+ printk(PREFIX "%s [%s] enabled at IRQ %d\n",
+ acpi_device_name(link->device),
+ acpi_device_bid(link->device), link->irq.active);
+ }
+
+ link->irq.initialized = 1;
+
+ return_VALUE(0);
+}
+
+/*
+ * acpi_pci_link_get_irq
+ * success: return IRQ >= 0
+ * failure: return -1
+ */
+
+int
+acpi_pci_link_get_irq (
+ acpi_handle handle,
+ int index,
+ int *edge_level,
+ int *active_high_low,
+ char **name)
+{
+ int result = 0;
+ struct acpi_device *device = NULL;
+ struct acpi_pci_link *link = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_get_irq");
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link device\n"));
+ return_VALUE(-1);
+ }
+
+ link = (struct acpi_pci_link *) acpi_driver_data(device);
+ if (!link) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+ return_VALUE(-1);
+ }
+
+ /* TBD: Support multiple index (IRQ) entries per Link Device */
+ if (index) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid index %d\n", index));
+ return_VALUE(-1);
+ }
+
+ if (acpi_pci_link_allocate(link))
+ return_VALUE(-1);
+
+ if (!link->irq.active) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link active IRQ is 0!\n"));
+ return_VALUE(-1);
+ }
+
+ if (edge_level) *edge_level = link->irq.edge_level;
+ if (active_high_low) *active_high_low = link->irq.active_high_low;
+ if (name) *name = acpi_device_bid(link->device);
+ return_VALUE(link->irq.active);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_pci_link_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_pci_link *link = NULL;
+ int i = 0;
+ int found = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ link = kmalloc(sizeof(struct acpi_pci_link), GFP_KERNEL);
+ if (!link)
+ return_VALUE(-ENOMEM);
+ memset(link, 0, sizeof(struct acpi_pci_link));
+
+ link->device = device;
+ link->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_PCI_LINK_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PCI_LINK_CLASS);
+ acpi_driver_data(device) = link;
+
+ result = acpi_pci_link_get_possible(link);
+ if (result)
+ goto end;
+
+ /* query and set link->irq.active */
+ acpi_pci_link_get_current(link);
+
+ printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
+ acpi_device_bid(device));
+ for (i = 0; i < link->irq.possible_count; i++) {
+ if (link->irq.active == link->irq.possible[i]) {
+ printk(" *%d", link->irq.possible[i]);
+ found = 1;
+ }
+ else
+ printk(" %d", link->irq.possible[i]);
+ }
+
+ printk(")");
+
+ if (!found)
+ printk(" *%d", link->irq.active);
+
+ if(!link->device->status.enabled)
+ printk(", disabled.");
+
+ printk("\n");
+
+ /* TBD: Acquire/release lock */
+ list_add_tail(&link->node, &acpi_link.entries);
+ acpi_link.count++;
+
+end:
+ /* disable all links -- to be activated on use */
+ acpi_ut_evaluate_object(link->handle, "_DIS", 0, NULL);
+
+ if (result)
+ kfree(link);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_pci_link_resume (
+ struct acpi_pci_link *link)
+{
+ ACPI_FUNCTION_TRACE("acpi_pci_link_resume");
+
+ if (link->irq.active && link->irq.initialized)
+ return_VALUE(acpi_pci_link_set(link, link->irq.active));
+ else
+ return_VALUE(0);
+}
+
+
+static int
+irqrouter_resume(
+ struct sys_device *dev)
+{
+ struct list_head *node = NULL;
+ struct acpi_pci_link *link = NULL;
+
+ ACPI_FUNCTION_TRACE("irqrouter_resume");
+
+ list_for_each(node, &acpi_link.entries) {
+
+ link = list_entry(node, struct acpi_pci_link, node);
+ if (!link) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid link context\n"));
+ continue;
+ }
+
+ acpi_pci_link_resume(link);
+ }
+ return_VALUE(0);
+}
+
+
+static int
+acpi_pci_link_remove (
+ struct acpi_device *device,
+ int type)
+{
+ struct acpi_pci_link *link = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_link_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ link = (struct acpi_pci_link *) acpi_driver_data(device);
+
+ /* TBD: Acquire/release lock */
+ list_del(&link->node);
+
+ kfree(link);
+
+ return_VALUE(0);
+}
+
+/*
+ * modify acpi_irq_penalty[] from cmdline
+ */
+static int __init acpi_irq_penalty_update(char *str, int used)
+{
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ int retval;
+ int irq;
+
+ retval = get_option(&str,&irq);
+
+ if (!retval)
+ break; /* no number found */
+
+ if (irq < 0)
+ continue;
+
+ if (irq >= ACPI_MAX_IRQS)
+ continue;
+
+ if (used)
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
+ else
+ acpi_irq_penalty[irq] = PIRQ_PENALTY_PCI_AVAILABLE;
+
+ if (retval != 2) /* no next number */
+ break;
+ }
+ return 1;
+}
+
+/*
+ * We'd like PNP to call this routine for the
+ * single ISA_USED value for each legacy device.
+ * But instead it calls us with each POSSIBLE setting.
+ * There is no ISA_POSSIBLE weight, so we simply use
+ * the (small) PCI_USING penalty.
+ */
+void acpi_penalize_isa_irq(int irq)
+{
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
+}
+
+/*
+ * Over-ride default table to reserve additional IRQs for use by ISA
+ * e.g. acpi_irq_isa=5
+ * Useful for telling ACPI how not to interfere with your ISA sound card.
+ */
+static int __init acpi_irq_isa(char *str)
+{
+ return acpi_irq_penalty_update(str, 1);
+}
+__setup("acpi_irq_isa=", acpi_irq_isa);
+
+/*
+ * Over-ride default table to free additional IRQs for use by PCI
+ * e.g. acpi_irq_pci=7,15
+ * Used for acpi_irq_balance to free up IRQs to reduce PCI IRQ sharing.
+ */
+static int __init acpi_irq_pci(char *str)
+{
+ return acpi_irq_penalty_update(str, 0);
+}
+__setup("acpi_irq_pci=", acpi_irq_pci);
+
+static int __init acpi_irq_nobalance_set(char *str)
+{
+ acpi_irq_balance = 0;
+ return 1;
+}
+__setup("acpi_irq_nobalance", acpi_irq_nobalance_set);
+
+int __init acpi_irq_balance_set(char *str)
+{
+ acpi_irq_balance = 1;
+ return 1;
+}
+__setup("acpi_irq_balance", acpi_irq_balance_set);
+
+
+static struct sysdev_class irqrouter_sysdev_class = {
+ set_kset_name("irqrouter"),
+ .resume = irqrouter_resume,
+};
+
+
+static struct sys_device device_irqrouter = {
+ .id = 0,
+ .cls = &irqrouter_sysdev_class,
+};
+
+
+static int __init irqrouter_init_sysfs(void)
+{
+ int error;
+
+ ACPI_FUNCTION_TRACE("irqrouter_init_sysfs");
+
+ if (acpi_disabled || acpi_noirq)
+ return_VALUE(0);
+
+ error = sysdev_class_register(&irqrouter_sysdev_class);
+ if (!error)
+ error = sysdev_register(&device_irqrouter);
+
+ return_VALUE(error);
+}
+
+device_initcall(irqrouter_init_sysfs);
+
+
+static int __init acpi_pci_link_init (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_pci_link_init");
+
+ if (acpi_noirq)
+ return_VALUE(0);
+
+ acpi_link.count = 0;
+ INIT_LIST_HEAD(&acpi_link.entries);
+
+ if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
+ return_VALUE(-ENODEV);
+
+ return_VALUE(0);
+}
+
+subsys_initcall(acpi_pci_link_init);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
new file mode 100644
index 000000000000..7e6b8e3b2ed4
--- /dev/null
+++ b/drivers/acpi/pci_root.c
@@ -0,0 +1,347 @@
+/*
+ * pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 40 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/pm.h>
+#include <linux/pci.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_PCI_COMPONENT
+ACPI_MODULE_NAME ("pci_root")
+
+#define ACPI_PCI_ROOT_CLASS "pci_bridge"
+#define ACPI_PCI_ROOT_HID "PNP0A03"
+#define ACPI_PCI_ROOT_DRIVER_NAME "ACPI PCI Root Bridge Driver"
+#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
+
+static int acpi_pci_root_add (struct acpi_device *device);
+static int acpi_pci_root_remove (struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_pci_root_driver = {
+ .name = ACPI_PCI_ROOT_DRIVER_NAME,
+ .class = ACPI_PCI_ROOT_CLASS,
+ .ids = ACPI_PCI_ROOT_HID,
+ .ops = {
+ .add = acpi_pci_root_add,
+ .remove = acpi_pci_root_remove,
+ },
+};
+
+struct acpi_pci_root {
+ struct list_head node;
+ acpi_handle handle;
+ struct acpi_pci_id id;
+ struct pci_bus *bus;
+};
+
+static LIST_HEAD(acpi_pci_roots);
+
+static struct acpi_pci_driver *sub_driver;
+
+int acpi_pci_register_driver(struct acpi_pci_driver *driver)
+{
+ int n = 0;
+ struct list_head *entry;
+
+ struct acpi_pci_driver **pptr = &sub_driver;
+ while (*pptr)
+ pptr = &(*pptr)->next;
+ *pptr = driver;
+
+ if (!driver->add)
+ return 0;
+
+ list_for_each(entry, &acpi_pci_roots) {
+ struct acpi_pci_root *root;
+ root = list_entry(entry, struct acpi_pci_root, node);
+ driver->add(root->handle);
+ n++;
+ }
+
+ return n;
+}
+EXPORT_SYMBOL(acpi_pci_register_driver);
+
+void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
+{
+ struct list_head *entry;
+
+ struct acpi_pci_driver **pptr = &sub_driver;
+ while (*pptr) {
+ if (*pptr != driver)
+ continue;
+ *pptr = (*pptr)->next;
+ break;
+ }
+
+ if (!driver->remove)
+ return;
+
+ list_for_each(entry, &acpi_pci_roots) {
+ struct acpi_pci_root *root;
+ root = list_entry(entry, struct acpi_pci_root, node);
+ driver->remove(root->handle);
+ }
+}
+EXPORT_SYMBOL(acpi_pci_unregister_driver);
+
+static acpi_status
+get_root_bridge_busnr_callback (struct acpi_resource *resource, void *data)
+{
+ int *busnr = (int *)data;
+ struct acpi_resource_address64 address;
+
+ if (resource->id != ACPI_RSTYPE_ADDRESS16 &&
+ resource->id != ACPI_RSTYPE_ADDRESS32 &&
+ resource->id != ACPI_RSTYPE_ADDRESS64)
+ return AE_OK;
+
+ acpi_resource_to_address64(resource, &address);
+ if ((address.address_length > 0) &&
+ (address.resource_type == ACPI_BUS_NUMBER_RANGE))
+ *busnr = address.min_address_range;
+
+ return AE_OK;
+}
+
+static acpi_status
+try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
+{
+ acpi_status status;
+
+ *busnum = -1;
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS, get_root_bridge_busnr_callback, busnum);
+ if (ACPI_FAILURE(status))
+ return status;
+ /* Check if we really get a bus number from _CRS */
+ if (*busnum == -1)
+ return AE_ERROR;
+ return AE_OK;
+}
+
+static int
+acpi_pci_root_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_pci_root *root = NULL;
+ struct acpi_pci_root *tmp;
+ acpi_status status = AE_OK;
+ unsigned long value = 0;
+ acpi_handle handle = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_root_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
+ if (!root)
+ return_VALUE(-ENOMEM);
+ memset(root, 0, sizeof(struct acpi_pci_root));
+
+ root->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
+ acpi_driver_data(device) = root;
+
+ /*
+ * TBD: Doesn't the bus driver automatically set this?
+ */
+ device->ops.bind = acpi_pci_bind;
+
+ /*
+ * Segment
+ * -------
+ * Obtained via _SEG, if exists, otherwise assumed to be zero (0).
+ */
+ status = acpi_evaluate_integer(root->handle, METHOD_NAME__SEG, NULL,
+ &value);
+ switch (status) {
+ case AE_OK:
+ root->id.segment = (u16) value;
+ break;
+ case AE_NOT_FOUND:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Assuming segment 0 (no _SEG)\n"));
+ root->id.segment = 0;
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SEG\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ /*
+ * Bus
+ * ---
+ * Obtained via _BBN, if exists, otherwise assumed to be zero (0).
+ */
+ status = acpi_evaluate_integer(root->handle, METHOD_NAME__BBN, NULL,
+ &value);
+ switch (status) {
+ case AE_OK:
+ root->id.bus = (u16) value;
+ break;
+ case AE_NOT_FOUND:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n"));
+ root->id.bus = 0;
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BBN\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ /* Some systems have wrong _BBN */
+ list_for_each_entry(tmp, &acpi_pci_roots, node) {
+ if ((tmp->id.segment == root->id.segment)
+ && (tmp->id.bus == root->id.bus)) {
+ int bus = 0;
+ acpi_status status;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Wrong _BBN value, please reboot and using option 'pci=noacpi'\n"));
+
+ status = try_get_root_bridge_busnr(root->handle, &bus);
+ if (ACPI_FAILURE(status))
+ break;
+ if (bus != root->id.bus) {
+ printk(KERN_INFO PREFIX "PCI _CRS %d overrides _BBN 0\n", bus);
+ root->id.bus = bus;
+ }
+ break;
+ }
+ }
+ /*
+ * Device & Function
+ * -----------------
+ * Obtained from _ADR (which has already been evaluated for us).
+ */
+ root->id.device = device->pnp.bus_address >> 16;
+ root->id.function = device->pnp.bus_address & 0xFFFF;
+
+ /*
+ * TBD: Need PCI interface for enumeration/configuration of roots.
+ */
+
+ /* TBD: Locking */
+ list_add_tail(&root->node, &acpi_pci_roots);
+
+ printk(KERN_INFO PREFIX "%s [%s] (%04x:%02x)\n",
+ acpi_device_name(device), acpi_device_bid(device),
+ root->id.segment, root->id.bus);
+
+ /*
+ * Scan the Root Bridge
+ * --------------------
+ * Must do this prior to any attempt to bind the root device, as the
+ * PCI namespace does not get created until this call is made (and
+ * thus the root bridge's pci_dev does not exist).
+ */
+ root->bus = pci_acpi_scan_root(device, root->id.segment, root->id.bus);
+ if (!root->bus) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Bus %04x:%02x not present in PCI namespace\n",
+ root->id.segment, root->id.bus));
+ result = -ENODEV;
+ goto end;
+ }
+
+ /*
+ * Attach ACPI-PCI Context
+ * -----------------------
+ * Thus binding the ACPI and PCI devices.
+ */
+ result = acpi_pci_bind_root(device, &root->id, root->bus);
+ if (result)
+ goto end;
+
+ /*
+ * PCI Routing Table
+ * -----------------
+ * Evaluate and parse _PRT, if exists.
+ */
+ status = acpi_get_handle(root->handle, METHOD_NAME__PRT, &handle);
+ if (ACPI_SUCCESS(status))
+ result = acpi_pci_irq_add_prt(root->handle, root->id.segment,
+ root->id.bus);
+
+end:
+ if (result)
+ kfree(root);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_pci_root_remove (
+ struct acpi_device *device,
+ int type)
+{
+ struct acpi_pci_root *root = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_root_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ root = (struct acpi_pci_root *) acpi_driver_data(device);
+
+ kfree(root);
+
+ return_VALUE(0);
+}
+
+
+static int __init acpi_pci_root_init (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_pci_root_init");
+
+ if (acpi_pci_disabled)
+ return_VALUE(0);
+
+ /* DEBUG:
+ acpi_dbg_layer = ACPI_PCI_COMPONENT;
+ acpi_dbg_level = 0xFFFFFFFF;
+ */
+
+ if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
+ return_VALUE(-ENODEV);
+
+ return_VALUE(0);
+}
+
+subsys_initcall(acpi_pci_root_init);
+
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c
new file mode 100644
index 000000000000..373a3a95bb4e
--- /dev/null
+++ b/drivers/acpi/power.c
@@ -0,0 +1,692 @@
+/*
+ * acpi_power.c - ACPI Bus Power Management ($Revision: 39 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+/*
+ * ACPI power-managed devices may be controlled in two ways:
+ * 1. via "Device Specific (D-State) Control"
+ * 2. via "Power Resource Control".
+ * This module is used to manage devices relying on Power Resource Control.
+ *
+ * An ACPI "power resource object" describes a software controllable power
+ * plane, clock plane, or other resource used by a power managed device.
+ * A device may rely on multiple power resources, and a power resource
+ * may be shared by multiple devices.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_POWER_COMPONENT
+ACPI_MODULE_NAME ("acpi_power")
+
+#define ACPI_POWER_COMPONENT 0x00800000
+#define ACPI_POWER_CLASS "power_resource"
+#define ACPI_POWER_DRIVER_NAME "ACPI Power Resource Driver"
+#define ACPI_POWER_DEVICE_NAME "Power Resource"
+#define ACPI_POWER_FILE_INFO "info"
+#define ACPI_POWER_FILE_STATUS "state"
+#define ACPI_POWER_RESOURCE_STATE_OFF 0x00
+#define ACPI_POWER_RESOURCE_STATE_ON 0x01
+#define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF
+
+static int acpi_power_add (struct acpi_device *device);
+static int acpi_power_remove (struct acpi_device *device, int type);
+static int acpi_power_open_fs(struct inode *inode, struct file *file);
+
+static struct acpi_driver acpi_power_driver = {
+ .name = ACPI_POWER_DRIVER_NAME,
+ .class = ACPI_POWER_CLASS,
+ .ids = ACPI_POWER_HID,
+ .ops = {
+ .add = acpi_power_add,
+ .remove = acpi_power_remove,
+ },
+};
+
+struct acpi_power_resource
+{
+ acpi_handle handle;
+ acpi_bus_id name;
+ u32 system_level;
+ u32 order;
+ int state;
+ int references;
+};
+
+static struct list_head acpi_power_resource_list;
+
+static struct file_operations acpi_power_fops = {
+ .open = acpi_power_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* --------------------------------------------------------------------------
+ Power Resource Management
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_power_get_context (
+ acpi_handle handle,
+ struct acpi_power_resource **resource)
+{
+ int result = 0;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_power_get_context");
+
+ if (!resource)
+ return_VALUE(-ENODEV);
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Error getting context [%p]\n",
+ handle));
+ return_VALUE(result);
+ }
+
+ *resource = (struct acpi_power_resource *) acpi_driver_data(device);
+ if (!resource)
+ return_VALUE(-ENODEV);
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_power_get_state (
+ struct acpi_power_resource *resource)
+{
+ acpi_status status = AE_OK;
+ unsigned long sta = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_power_get_state");
+
+ if (!resource)
+ return_VALUE(-EINVAL);
+
+ status = acpi_evaluate_integer(resource->handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ if (sta & 0x01)
+ resource->state = ACPI_POWER_RESOURCE_STATE_ON;
+ else
+ resource->state = ACPI_POWER_RESOURCE_STATE_OFF;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] is %s\n",
+ resource->name, resource->state?"on":"off"));
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_power_get_list_state (
+ struct acpi_handle_list *list,
+ int *state)
+{
+ int result = 0;
+ struct acpi_power_resource *resource = NULL;
+ u32 i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_power_get_list_state");
+
+ if (!list || !state)
+ return_VALUE(-EINVAL);
+
+ /* The state of the list is 'on' IFF all resources are 'on'. */
+
+ for (i=0; i<list->count; i++) {
+ result = acpi_power_get_context(list->handles[i], &resource);
+ if (result)
+ return_VALUE(result);
+ result = acpi_power_get_state(resource);
+ if (result)
+ return_VALUE(result);
+
+ *state = resource->state;
+
+ if (*state != ACPI_POWER_RESOURCE_STATE_ON)
+ break;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n",
+ *state?"on":"off"));
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_power_on (
+ acpi_handle handle)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_device *device = NULL;
+ struct acpi_power_resource *resource = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_power_on");
+
+ result = acpi_power_get_context(handle, &resource);
+ if (result)
+ return_VALUE(result);
+
+ resource->references++;
+
+ if ((resource->references > 1)
+ || (resource->state == ACPI_POWER_RESOURCE_STATE_ON)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already on\n",
+ resource->name));
+ return_VALUE(0);
+ }
+
+ status = acpi_evaluate_object(resource->handle, "_ON", NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ result = acpi_power_get_state(resource);
+ if (result)
+ return_VALUE(result);
+ if (resource->state != ACPI_POWER_RESOURCE_STATE_ON)
+ return_VALUE(-ENOEXEC);
+
+ /* Update the power resource's _device_ power state */
+ result = acpi_bus_get_device(resource->handle, &device);
+ if (result)
+ return_VALUE(result);
+ device->power.state = ACPI_STATE_D0;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned on\n",
+ resource->name));
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_power_off_device (
+ acpi_handle handle)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_device *device = NULL;
+ struct acpi_power_resource *resource = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_power_off_device");
+
+ result = acpi_power_get_context(handle, &resource);
+ if (result)
+ return_VALUE(result);
+
+ if (resource->references)
+ resource->references--;
+
+ if (resource->references) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Resource [%s] is still in use, dereferencing\n",
+ device->pnp.bus_id));
+ return_VALUE(0);
+ }
+
+ if (resource->state == ACPI_POWER_RESOURCE_STATE_OFF) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] already off\n",
+ device->pnp.bus_id));
+ return_VALUE(0);
+ }
+
+ status = acpi_evaluate_object(resource->handle, "_OFF", NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ result = acpi_power_get_state(resource);
+ if (result)
+ return_VALUE(result);
+ if (resource->state != ACPI_POWER_RESOURCE_STATE_OFF)
+ return_VALUE(-ENOEXEC);
+
+ /* Update the power resource's _device_ power state */
+ result = acpi_bus_get_device(resource->handle, &device);
+ if (result)
+ return_VALUE(result);
+ device->power.state = ACPI_STATE_D3;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource [%s] turned off\n",
+ resource->name));
+
+ return_VALUE(0);
+}
+
+/*
+ * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229):
+ * 1. Power on the power resources required for the wakeup device
+ * 2. Enable _PSW (power state wake) for the device if present
+ */
+int acpi_enable_wakeup_device_power (struct acpi_device *dev)
+{
+ union acpi_object arg = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list arg_list = {1, &arg};
+ acpi_status status = AE_OK;
+ int i;
+ int ret = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_power");
+ if (!dev || !dev->wakeup.flags.valid)
+ return_VALUE(-1);
+
+ arg.integer.value = 1;
+ /* Open power resource */
+ for (i = 0; i < dev->wakeup.resources.count; i++) {
+ ret = acpi_power_on(dev->wakeup.resources.handles[i]);
+ if (ret) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error transition power state\n"));
+ dev->wakeup.flags.valid = 0;
+ return_VALUE(-1);
+ }
+ }
+
+ /* Execute PSW */
+ status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
+ if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n"));
+ dev->wakeup.flags.valid = 0;
+ ret = -1;
+ }
+
+ return_VALUE(ret);
+}
+
+/*
+ * Shutdown a wakeup device, counterpart of above method
+ * 1. Disable _PSW (power state wake)
+ * 2. Shutdown down the power resources
+ */
+int acpi_disable_wakeup_device_power (struct acpi_device *dev)
+{
+ union acpi_object arg = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list arg_list = {1, &arg};
+ acpi_status status = AE_OK;
+ int i;
+ int ret = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device_power");
+
+ if (!dev || !dev->wakeup.flags.valid)
+ return_VALUE(-1);
+
+ arg.integer.value = 0;
+ /* Execute PSW */
+ status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL);
+ if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluate _PSW\n"));
+ dev->wakeup.flags.valid = 0;
+ return_VALUE(-1);
+ }
+
+ /* Close power resource */
+ for (i = 0; i < dev->wakeup.resources.count; i++) {
+ ret = acpi_power_off_device(dev->wakeup.resources.handles[i]);
+ if (ret) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error transition power state\n"));
+ dev->wakeup.flags.valid = 0;
+ return_VALUE(-1);
+ }
+ }
+
+ return_VALUE(ret);
+}
+
+/* --------------------------------------------------------------------------
+ Device Power Management
+ -------------------------------------------------------------------------- */
+
+int
+acpi_power_get_inferred_state (
+ struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_handle_list *list = NULL;
+ int list_state = 0;
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_power_get_inferred_state");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ device->power.state = ACPI_STATE_UNKNOWN;
+
+ /*
+ * We know a device's inferred power state when all the resources
+ * required for a given D-state are 'on'.
+ */
+ for (i=ACPI_STATE_D0; i<ACPI_STATE_D3; i++) {
+ list = &device->power.states[i].resources;
+ if (list->count < 1)
+ continue;
+
+ result = acpi_power_get_list_state(list, &list_state);
+ if (result)
+ return_VALUE(result);
+
+ if (list_state == ACPI_POWER_RESOURCE_STATE_ON) {
+ device->power.state = i;
+ return_VALUE(0);
+ }
+ }
+
+ device->power.state = ACPI_STATE_D3;
+
+ return_VALUE(0);
+}
+
+
+int
+acpi_power_transition (
+ struct acpi_device *device,
+ int state)
+{
+ int result = 0;
+ struct acpi_handle_list *cl = NULL; /* Current Resources */
+ struct acpi_handle_list *tl = NULL; /* Target Resources */
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_power_transition");
+
+ if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3))
+ return_VALUE(-EINVAL);
+
+ if ((device->power.state < ACPI_STATE_D0) || (device->power.state > ACPI_STATE_D3))
+ return_VALUE(-ENODEV);
+
+ cl = &device->power.states[device->power.state].resources;
+ tl = &device->power.states[state].resources;
+
+ device->power.state = ACPI_STATE_UNKNOWN;
+
+ if (!cl->count && !tl->count) {
+ result = -ENODEV;
+ goto end;
+ }
+
+ /* TBD: Resources must be ordered. */
+
+ /*
+ * First we reference all power resources required in the target list
+ * (e.g. so the device doesn't lose power while transitioning).
+ */
+ for (i=0; i<tl->count; i++) {
+ result = acpi_power_on(tl->handles[i]);
+ if (result)
+ goto end;
+ }
+
+ /*
+ * Then we dereference all power resources used in the current list.
+ */
+ for (i=0; i<cl->count; i++) {
+ result = acpi_power_off_device(cl->handles[i]);
+ if (result)
+ goto end;
+ }
+
+ /* We shouldn't change the state till all above operations succeed */
+ device->power.state = state;
+end:
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN,
+ "Error transitioning device [%s] to D%d\n",
+ device->pnp.bus_id, state));
+
+ return_VALUE(result);
+}
+
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_power_dir;
+
+static int acpi_power_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_power_resource *resource = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_power_seq_show");
+
+ resource = (struct acpi_power_resource *)seq->private;
+
+ if (!resource)
+ goto end;
+
+ seq_puts(seq, "state: ");
+ switch (resource->state) {
+ case ACPI_POWER_RESOURCE_STATE_ON:
+ seq_puts(seq, "on\n");
+ break;
+ case ACPI_POWER_RESOURCE_STATE_OFF:
+ seq_puts(seq, "off\n");
+ break;
+ default:
+ seq_puts(seq, "unknown\n");
+ break;
+ }
+
+ seq_printf(seq, "system level: S%d\n"
+ "order: %d\n"
+ "reference count: %d\n",
+ resource->system_level,
+ resource->order,
+ resource->references);
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_power_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_power_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_power_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_power_add_fs");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_power_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ }
+
+ /* 'status' [R] */
+ entry = create_proc_entry(ACPI_POWER_FILE_STATUS,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_POWER_FILE_STATUS));
+ else {
+ entry->proc_fops = &acpi_power_fops;
+ entry->data = acpi_driver_data(device);
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_power_remove_fs (
+ struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_power_remove_fs");
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_POWER_FILE_STATUS,
+ acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device), acpi_power_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_power_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_power_resource *resource = NULL;
+ union acpi_object acpi_object;
+ struct acpi_buffer buffer = {sizeof(acpi_object), &acpi_object};
+
+ ACPI_FUNCTION_TRACE("acpi_power_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ resource = kmalloc(sizeof(struct acpi_power_resource), GFP_KERNEL);
+ if (!resource)
+ return_VALUE(-ENOMEM);
+ memset(resource, 0, sizeof(struct acpi_power_resource));
+
+ resource->handle = device->handle;
+ strcpy(resource->name, device->pnp.bus_id);
+ strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
+ acpi_driver_data(device) = resource;
+
+ /* Evalute the object to get the system level and resource order. */
+ status = acpi_evaluate_object(resource->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ result = -ENODEV;
+ goto end;
+ }
+ resource->system_level = acpi_object.power_resource.system_level;
+ resource->order = acpi_object.power_resource.resource_order;
+
+ result = acpi_power_get_state(resource);
+ if (result)
+ goto end;
+
+ switch (resource->state) {
+ case ACPI_POWER_RESOURCE_STATE_ON:
+ device->power.state = ACPI_STATE_D0;
+ break;
+ case ACPI_POWER_RESOURCE_STATE_OFF:
+ device->power.state = ACPI_STATE_D3;
+ break;
+ default:
+ device->power.state = ACPI_STATE_UNKNOWN;
+ break;
+ }
+
+ result = acpi_power_add_fs(device);
+ if (result)
+ goto end;
+
+ printk(KERN_INFO PREFIX "%s [%s] (%s)\n", acpi_device_name(device),
+ acpi_device_bid(device), resource->state?"on":"off");
+
+end:
+ if (result)
+ kfree(resource);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_power_remove (
+ struct acpi_device *device,
+ int type)
+{
+ struct acpi_power_resource *resource = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_power_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ resource = (struct acpi_power_resource *) acpi_driver_data(device);
+
+ acpi_power_remove_fs(device);
+
+ kfree(resource);
+
+ return_VALUE(0);
+}
+
+
+static int __init acpi_power_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_power_init");
+
+ if (acpi_disabled)
+ return_VALUE(0);
+
+ INIT_LIST_HEAD(&acpi_power_resource_list);
+
+ acpi_power_dir = proc_mkdir(ACPI_POWER_CLASS, acpi_root_dir);
+ if (!acpi_power_dir)
+ return_VALUE(-ENODEV);
+
+ result = acpi_bus_register_driver(&acpi_power_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_POWER_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+subsys_initcall(acpi_power_init);
+
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
new file mode 100644
index 000000000000..f4778747e889
--- /dev/null
+++ b/drivers/acpi/processor_core.c
@@ -0,0 +1,989 @@
+/*
+ * acpi_processor.c - ACPI Processor Driver ($Revision: 71 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * - Added processor hotplug support
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * TBD:
+ * 1. Make # power states dynamic.
+ * 2. Support duty_cycle values that span bit 4.
+ * 3. Optimize by having scheduler determine business instead of
+ * having us try to calculate it here.
+ * 4. Need C1 timing -- must modify kernel (IRQ handler) to get this.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/pm.h>
+#include <linux/cpufreq.h>
+#include <linux/cpu.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/dmi.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/cpu.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+#include <asm/processor.h>
+#include <asm/smp.h>
+#include <asm/acpi.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/processor.h>
+
+
+#define ACPI_PROCESSOR_COMPONENT 0x01000000
+#define ACPI_PROCESSOR_CLASS "processor"
+#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
+#define ACPI_PROCESSOR_DEVICE_NAME "Processor"
+#define ACPI_PROCESSOR_FILE_INFO "info"
+#define ACPI_PROCESSOR_FILE_THROTTLING "throttling"
+#define ACPI_PROCESSOR_FILE_LIMIT "limit"
+#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
+#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
+
+#define ACPI_PROCESSOR_LIMIT_USER 0
+#define ACPI_PROCESSOR_LIMIT_THERMAL 1
+
+#define ACPI_STA_PRESENT 0x00000001
+
+#define _COMPONENT ACPI_PROCESSOR_COMPONENT
+ACPI_MODULE_NAME ("acpi_processor")
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION(ACPI_PROCESSOR_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+
+static int acpi_processor_add (struct acpi_device *device);
+static int acpi_processor_start (struct acpi_device *device);
+static int acpi_processor_remove (struct acpi_device *device, int type);
+static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
+static void acpi_processor_notify ( acpi_handle handle, u32 event, void *data);
+static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
+static int acpi_processor_handle_eject(struct acpi_processor *pr);
+
+static struct acpi_driver acpi_processor_driver = {
+ .name = ACPI_PROCESSOR_DRIVER_NAME,
+ .class = ACPI_PROCESSOR_CLASS,
+ .ids = ACPI_PROCESSOR_HID,
+ .ops = {
+ .add = acpi_processor_add,
+ .remove = acpi_processor_remove,
+ .start = acpi_processor_start,
+ },
+};
+
+#define INSTALL_NOTIFY_HANDLER 1
+#define UNINSTALL_NOTIFY_HANDLER 2
+
+
+static struct file_operations acpi_processor_info_fops = {
+ .open = acpi_processor_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+struct acpi_processor *processors[NR_CPUS];
+struct acpi_processor_errata errata;
+
+
+/* --------------------------------------------------------------------------
+ Errata Handling
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_processor_errata_piix4 (
+ struct pci_dev *dev)
+{
+ u8 rev = 0;
+ u8 value1 = 0;
+ u8 value2 = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_errata_piix4");
+
+ if (!dev)
+ return_VALUE(-EINVAL);
+
+ /*
+ * Note that 'dev' references the PIIX4 ACPI Controller.
+ */
+
+ pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+ switch (rev) {
+ case 0:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
+ break;
+ case 1:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
+ break;
+ case 2:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
+ break;
+ case 3:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
+ break;
+ }
+
+ switch (rev) {
+
+ case 0: /* PIIX4 A-step */
+ case 1: /* PIIX4 B-step */
+ /*
+ * See specification changes #13 ("Manual Throttle Duty Cycle")
+ * and #14 ("Enabling and Disabling Manual Throttle"), plus
+ * erratum #5 ("STPCLK# Deassertion Time") from the January
+ * 2002 PIIX4 specification update. Applies to only older
+ * PIIX4 models.
+ */
+ errata.piix4.throttle = 1;
+
+ case 2: /* PIIX4E */
+ case 3: /* PIIX4M */
+ /*
+ * See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
+ * Livelock") from the January 2002 PIIX4 specification update.
+ * Applies to all PIIX4 models.
+ */
+
+ /*
+ * BM-IDE
+ * ------
+ * Find the PIIX4 IDE Controller and get the Bus Master IDE
+ * Status register address. We'll use this later to read
+ * each IDE controller's DMA status to make sure we catch all
+ * DMA activity.
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB,
+ PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev) {
+ errata.piix4.bmisx = pci_resource_start(dev, 4);
+ pci_dev_put(dev);
+ }
+
+ /*
+ * Type-F DMA
+ * ----------
+ * Find the PIIX4 ISA Controller and read the Motherboard
+ * DMA controller's status to see if Type-F (Fast) DMA mode
+ * is enabled (bit 7) on either channel. Note that we'll
+ * disable C3 support if this is enabled, as some legacy
+ * devices won't operate well if fast DMA is disabled.
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_0,
+ PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev) {
+ pci_read_config_byte(dev, 0x76, &value1);
+ pci_read_config_byte(dev, 0x77, &value2);
+ if ((value1 & 0x80) || (value2 & 0x80))
+ errata.piix4.fdma = 1;
+ pci_dev_put(dev);
+ }
+
+ break;
+ }
+
+ if (errata.piix4.bmisx)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Bus master activity detection (BM-IDE) erratum enabled\n"));
+ if (errata.piix4.fdma)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Type-F DMA livelock erratum (C3 disabled)\n"));
+
+ return_VALUE(0);
+}
+
+
+int
+acpi_processor_errata (
+ struct acpi_processor *pr)
+{
+ int result = 0;
+ struct pci_dev *dev = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_errata");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ /*
+ * PIIX4
+ */
+ dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, PCI_ANY_ID, NULL);
+ if (dev) {
+ result = acpi_processor_errata_piix4(dev);
+ pci_dev_put(dev);
+ }
+
+ return_VALUE(result);
+}
+
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_processor_dir = NULL;
+
+static int acpi_processor_info_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_info_seq_show");
+
+ if (!pr)
+ goto end;
+
+ seq_printf(seq, "processor id: %d\n"
+ "acpi id: %d\n"
+ "bus mastering control: %s\n"
+ "power management: %s\n"
+ "throttling control: %s\n"
+ "limit interface: %s\n",
+ pr->id,
+ pr->acpi_id,
+ pr->flags.bm_control ? "yes" : "no",
+ pr->flags.power ? "yes" : "no",
+ pr->flags.throttling ? "yes" : "no",
+ pr->flags.limit ? "yes" : "no");
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_processor_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_processor_info_seq_show,
+ PDE(inode)->data);
+}
+
+
+static int
+acpi_processor_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_add_fs");
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_processor_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ }
+ acpi_device_dir(device)->owner = THIS_MODULE;
+
+ /* 'info' [R] */
+ entry = create_proc_entry(ACPI_PROCESSOR_FILE_INFO,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_PROCESSOR_FILE_INFO));
+ else {
+ entry->proc_fops = &acpi_processor_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'throttling' [R/W] */
+ entry = create_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_PROCESSOR_FILE_THROTTLING));
+ else {
+ entry->proc_fops = &acpi_processor_throttling_fops;
+ entry->proc_fops->write = acpi_processor_write_throttling;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'limit' [R/W] */
+ entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_PROCESSOR_FILE_LIMIT));
+ else {
+ entry->proc_fops = &acpi_processor_limit_fops;
+ entry->proc_fops->write = acpi_processor_write_limit;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_processor_remove_fs (
+ struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_remove_fs");
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_PROCESSOR_FILE_INFO,acpi_device_dir(device));
+ remove_proc_entry(ACPI_PROCESSOR_FILE_THROTTLING,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device), acpi_processor_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+/* Use the acpiid in MADT to map cpus in case of SMP */
+#ifndef CONFIG_SMP
+#define convert_acpiid_to_cpu(acpi_id) (0xff)
+#else
+
+#ifdef CONFIG_IA64
+#define arch_acpiid_to_apicid ia64_acpiid_to_sapicid
+#define arch_cpu_to_apicid ia64_cpu_to_sapicid
+#define ARCH_BAD_APICID (0xffff)
+#else
+#define arch_acpiid_to_apicid x86_acpiid_to_apicid
+#define arch_cpu_to_apicid x86_cpu_to_apicid
+#define ARCH_BAD_APICID (0xff)
+#endif
+
+static u8 convert_acpiid_to_cpu(u8 acpi_id)
+{
+ u16 apic_id;
+ int i;
+
+ apic_id = arch_acpiid_to_apicid[acpi_id];
+ if (apic_id == ARCH_BAD_APICID)
+ return -1;
+
+ for (i = 0; i < NR_CPUS; i++) {
+ if (arch_cpu_to_apicid[i] == apic_id)
+ return i;
+ }
+ return -1;
+}
+#endif
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_processor_get_info (
+ struct acpi_processor *pr)
+{
+ acpi_status status = 0;
+ union acpi_object object = {0};
+ struct acpi_buffer buffer = {sizeof(union acpi_object), &object};
+ u8 cpu_index;
+ static int cpu0_initialized;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_info");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if (num_online_cpus() > 1)
+ errata.smp = TRUE;
+
+ acpi_processor_errata(pr);
+
+ /*
+ * Check to see if we have bus mastering arbitration control. This
+ * is required for proper C3 usage (to maintain cache coherency).
+ */
+ if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) {
+ pr->flags.bm_control = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Bus mastering arbitration control present\n"));
+ }
+ else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No bus mastering arbitration control\n"));
+
+ /*
+ * Evalute the processor object. Note that it is common on SMP to
+ * have the first (boot) processor with a valid PBLK address while
+ * all others have a NULL address.
+ */
+ status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error evaluating processor object\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ /*
+ * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+ * >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
+ */
+ pr->acpi_id = object.processor.proc_id;
+
+ cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
+
+ /* Handle UP system running SMP kernel, with no LAPIC in MADT */
+ if ( !cpu0_initialized && (cpu_index == 0xff) &&
+ (num_online_cpus() == 1)) {
+ cpu_index = 0;
+ }
+
+ cpu0_initialized = 1;
+
+ pr->id = cpu_index;
+
+ /*
+ * Extra Processor objects may be enumerated on MP systems with
+ * less than the max # of CPUs. They should be ignored _iff
+ * they are physically not present.
+ */
+ if (cpu_index >= NR_CPUS) {
+ if (ACPI_FAILURE(acpi_processor_hotadd_init(pr->handle, &pr->id))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error getting cpuindex for acpiid 0x%x\n",
+ pr->acpi_id));
+ return_VALUE(-ENODEV);
+ }
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d:%d]\n", pr->id,
+ pr->acpi_id));
+
+ if (!object.processor.pblk_address)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No PBLK (NULL address)\n"));
+ else if (object.processor.pblk_length != 6)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid PBLK length [%d]\n",
+ object.processor.pblk_length));
+ else {
+ pr->throttling.address = object.processor.pblk_address;
+ pr->throttling.duty_offset = acpi_fadt.duty_offset;
+ pr->throttling.duty_width = acpi_fadt.duty_width;
+
+ pr->pblk = object.processor.pblk_address;
+
+ /*
+ * We don't care about error returns - we just try to mark
+ * these reserved so that nobody else is confused into thinking
+ * that this region might be unused..
+ *
+ * (In particular, allocating the IO range for Cardbus)
+ */
+ request_region(pr->throttling.address, 6, "ACPI CPU throttle");
+ }
+
+#ifdef CONFIG_CPU_FREQ
+ acpi_processor_ppc_has_changed(pr);
+#endif
+ acpi_processor_get_throttling_info(pr);
+ acpi_processor_get_limit_info(pr);
+
+ return_VALUE(0);
+}
+
+static int
+acpi_processor_start(
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_start");
+
+ pr = acpi_driver_data(device);
+
+ result = acpi_processor_get_info(pr);
+ if (result) {
+ /* Processor is physically not present */
+ return_VALUE(0);
+ }
+
+ BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0));
+
+ processors[pr->id] = pr;
+
+ result = acpi_processor_add_fs(device);
+ if (result)
+ goto end;
+
+ status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
+ acpi_processor_notify, pr);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing device notify handler\n"));
+ }
+
+ acpi_processor_power_init(pr, device);
+
+ if (pr->flags.throttling) {
+ printk(KERN_INFO PREFIX "%s [%s] (supports",
+ acpi_device_name(device), acpi_device_bid(device));
+ printk(" %d throttling states", pr->throttling.state_count);
+ printk(")\n");
+ }
+
+end:
+
+ return_VALUE(result);
+}
+
+
+
+static void
+acpi_processor_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_processor *pr = (struct acpi_processor *) data;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_notify");
+
+ if (!pr)
+ return_VOID;
+
+ if (acpi_bus_get_device(pr->handle, &device))
+ return_VOID;
+
+ switch (event) {
+ case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
+ acpi_processor_ppc_has_changed(pr);
+ acpi_bus_generate_event(device, event,
+ pr->performance_platform_limit);
+ break;
+ case ACPI_PROCESSOR_NOTIFY_POWER:
+ acpi_processor_cst_has_changed(pr);
+ acpi_bus_generate_event(device, event, 0);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+
+static int
+acpi_processor_add (
+ struct acpi_device *device)
+{
+ struct acpi_processor *pr = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ pr = kmalloc(sizeof(struct acpi_processor), GFP_KERNEL);
+ if (!pr)
+ return_VALUE(-ENOMEM);
+ memset(pr, 0, sizeof(struct acpi_processor));
+
+ pr->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_PROCESSOR_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_PROCESSOR_CLASS);
+ acpi_driver_data(device) = pr;
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_processor_remove (
+ struct acpi_device *device,
+ int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_processor *pr = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ pr = (struct acpi_processor *) acpi_driver_data(device);
+
+ if (pr->id >= NR_CPUS) {
+ kfree(pr);
+ return_VALUE(0);
+ }
+
+ if (type == ACPI_BUS_REMOVAL_EJECT) {
+ if (acpi_processor_handle_eject(pr))
+ return_VALUE(-EINVAL);
+ }
+
+ acpi_processor_power_exit(pr, device);
+
+ status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
+ acpi_processor_notify);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+ }
+
+ acpi_processor_remove_fs(device);
+
+ processors[pr->id] = NULL;
+
+ kfree(pr);
+
+ return_VALUE(0);
+}
+
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+/****************************************************************************
+ * Acpi processor hotplug support *
+ ****************************************************************************/
+
+static int is_processor_present(acpi_handle handle);
+
+static int
+is_processor_present(
+ acpi_handle handle)
+{
+ acpi_status status;
+ unsigned long sta = 0;
+
+ ACPI_FUNCTION_TRACE("is_processor_present");
+
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_FAILURE(status) || !(sta & ACPI_STA_PRESENT)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Processor Device is not present\n"));
+ return_VALUE(0);
+ }
+ return_VALUE(1);
+}
+
+
+static
+int acpi_processor_device_add(
+ acpi_handle handle,
+ struct acpi_device **device)
+{
+ acpi_handle phandle;
+ struct acpi_device *pdev;
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_device_add");
+
+ if (acpi_get_parent(handle, &phandle)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_get_device(phandle, &pdev)) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (acpi_bus_add(device, pdev, handle, ACPI_BUS_TYPE_PROCESSOR)) {
+ return_VALUE(-ENODEV);
+ }
+
+ acpi_bus_scan(*device);
+
+ pr = acpi_driver_data(*device);
+ if (!pr)
+ return_VALUE(-ENODEV);
+
+ if ((pr->id >=0) && (pr->id < NR_CPUS)) {
+ kobject_hotplug(&(*device)->kobj, KOBJ_ONLINE);
+ }
+ return_VALUE(0);
+}
+
+
+static void
+acpi_processor_hotplug_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_processor *pr;
+ struct acpi_device *device = NULL;
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_hotplug_notify");
+
+ switch (event) {
+ case ACPI_NOTIFY_BUS_CHECK:
+ case ACPI_NOTIFY_DEVICE_CHECK:
+ printk("Processor driver received %s event\n",
+ (event==ACPI_NOTIFY_BUS_CHECK)?
+ "ACPI_NOTIFY_BUS_CHECK":"ACPI_NOTIFY_DEVICE_CHECK");
+
+ if (!is_processor_present(handle))
+ break;
+
+ if (acpi_bus_get_device(handle, &device)) {
+ result = acpi_processor_device_add(handle, &device);
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to add the device\n"));
+ break;
+ }
+
+ pr = acpi_driver_data(device);
+ if (!pr) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Driver data is NULL\n"));
+ break;
+ }
+
+ if (pr->id >= 0 && (pr->id < NR_CPUS)) {
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ break;
+ }
+
+ result = acpi_processor_start(device);
+ if ((!result) && ((pr->id >=0) && (pr->id < NR_CPUS))) {
+ kobject_hotplug(&device->kobj, KOBJ_ONLINE);
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Device [%s] failed to start\n",
+ acpi_device_bid(device)));
+ }
+ break;
+ case ACPI_NOTIFY_EJECT_REQUEST:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"received ACPI_NOTIFY_EJECT_REQUEST\n"));
+
+ if (acpi_bus_get_device(handle, &device)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Device don't exist, dropping EJECT\n"));
+ break;
+ }
+ pr = acpi_driver_data(device);
+ if (!pr) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Driver data is NULL, dropping EJECT\n"));
+ return_VOID;
+ }
+
+ if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
+ kobject_hotplug(&device->kobj, KOBJ_OFFLINE);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+static acpi_status
+processor_walk_namespace_cb(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ acpi_status status;
+ int *action = context;
+ acpi_object_type type = 0;
+
+ status = acpi_get_type(handle, &type);
+ if (ACPI_FAILURE(status))
+ return(AE_OK);
+
+ if (type != ACPI_TYPE_PROCESSOR)
+ return(AE_OK);
+
+ switch(*action) {
+ case INSTALL_NOTIFY_HANDLER:
+ acpi_install_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify,
+ NULL);
+ break;
+ case UNINSTALL_NOTIFY_HANDLER:
+ acpi_remove_notify_handler(handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_processor_hotplug_notify);
+ break;
+ default:
+ break;
+ }
+
+ return(AE_OK);
+}
+
+
+static acpi_status
+acpi_processor_hotadd_init(
+ acpi_handle handle,
+ int *p_cpu)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_hotadd_init");
+
+ if (!is_processor_present(handle)) {
+ return_VALUE(AE_ERROR);
+ }
+
+ if (acpi_map_lsapic(handle, p_cpu))
+ return_VALUE(AE_ERROR);
+
+ if (arch_register_cpu(*p_cpu)) {
+ acpi_unmap_lsapic(*p_cpu);
+ return_VALUE(AE_ERROR);
+ }
+
+ return_VALUE(AE_OK);
+}
+
+
+static int
+acpi_processor_handle_eject(struct acpi_processor *pr)
+{
+ if (cpu_online(pr->id)) {
+ return(-EINVAL);
+ }
+ arch_unregister_cpu(pr->id);
+ acpi_unmap_lsapic(pr->id);
+ return(0);
+}
+#else
+static acpi_status
+acpi_processor_hotadd_init(
+ acpi_handle handle,
+ int *p_cpu)
+{
+ return AE_ERROR;
+}
+static int
+acpi_processor_handle_eject(struct acpi_processor *pr)
+{
+ return(-EINVAL);
+}
+#endif
+
+
+static
+void acpi_processor_install_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = INSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb,
+ &action, NULL);
+#endif
+}
+
+
+static
+void acpi_processor_uninstall_hotplug_notify(void)
+{
+#ifdef CONFIG_ACPI_HOTPLUG_CPU
+ int action = UNINSTALL_NOTIFY_HANDLER;
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR,
+ ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ processor_walk_namespace_cb,
+ &action, NULL);
+#endif
+}
+
+/*
+ * We keep the driver loaded even when ACPI is not running.
+ * This is needed for the powernow-k8 driver, that works even without
+ * ACPI, but needs symbols from this driver
+ */
+
+static int __init
+acpi_processor_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_init");
+
+ memset(&processors, 0, sizeof(processors));
+ memset(&errata, 0, sizeof(errata));
+
+ acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+ if (!acpi_processor_dir)
+ return_VALUE(0);
+ acpi_processor_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&acpi_processor_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+ return_VALUE(0);
+ }
+
+ acpi_processor_install_hotplug_notify();
+
+ acpi_thermal_cpufreq_init();
+
+ acpi_processor_ppc_init();
+
+ return_VALUE(0);
+}
+
+
+static void __exit
+acpi_processor_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_exit");
+
+ acpi_processor_ppc_exit();
+
+ acpi_thermal_cpufreq_exit();
+
+ acpi_processor_uninstall_hotplug_notify();
+
+ acpi_bus_unregister_driver(&acpi_processor_driver);
+
+ remove_proc_entry(ACPI_PROCESSOR_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+
+
+module_init(acpi_processor_init);
+module_exit(acpi_processor_exit);
+
+EXPORT_SYMBOL(acpi_processor_set_thermal_limit);
+
+MODULE_ALIAS("processor");
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
new file mode 100644
index 000000000000..05a17812d521
--- /dev/null
+++ b/drivers/acpi/processor_idle.c
@@ -0,0 +1,1017 @@
+/*
+ * processor_idle - idle state submodule to the ACPI processor driver
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * - Added processor hotplug support
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/cpufreq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/acpi.h>
+#include <linux/dmi.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/processor.h>
+
+#define ACPI_PROCESSOR_COMPONENT 0x01000000
+#define ACPI_PROCESSOR_CLASS "processor"
+#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
+#define _COMPONENT ACPI_PROCESSOR_COMPONENT
+ACPI_MODULE_NAME ("acpi_processor")
+
+#define ACPI_PROCESSOR_FILE_POWER "power"
+
+#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
+#define C2_OVERHEAD 4 /* 1us (3.579 ticks per us) */
+#define C3_OVERHEAD 4 /* 1us (3.579 ticks per us) */
+
+static void (*pm_idle_save)(void);
+module_param(max_cstate, uint, 0644);
+
+static unsigned int nocst = 0;
+module_param(nocst, uint, 0000);
+
+/*
+ * bm_history -- bit-mask with a bit per jiffy of bus-master activity
+ * 1000 HZ: 0xFFFFFFFF: 32 jiffies = 32ms
+ * 800 HZ: 0xFFFFFFFF: 32 jiffies = 40ms
+ * 100 HZ: 0x0000000F: 4 jiffies = 40ms
+ * reduce history for more aggressive entry into C3
+ */
+static unsigned int bm_history = (HZ >= 800 ? 0xFFFFFFFF : ((1U << (HZ / 25)) - 1));
+module_param(bm_history, uint, 0644);
+/* --------------------------------------------------------------------------
+ Power Management
+ -------------------------------------------------------------------------- */
+
+/*
+ * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
+ * For now disable this. Probably a bug somewhere else.
+ *
+ * To skip this limit, boot/load with a large max_cstate limit.
+ */
+static int no_c2c3(struct dmi_system_id *id)
+{
+ if (max_cstate > ACPI_PROCESSOR_MAX_POWER)
+ return 0;
+
+ printk(KERN_NOTICE PREFIX "%s detected - C2,C3 disabled."
+ " Override with \"processor.max_cstate=%d\"\n", id->ident,
+ ACPI_PROCESSOR_MAX_POWER + 1);
+
+ max_cstate = 1;
+
+ return 0;
+}
+
+
+
+
+static struct dmi_system_id __initdata processor_power_dmi_table[] = {
+ { no_c2c3, "IBM ThinkPad R40e", {
+ DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
+ DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW") }},
+ { no_c2c3, "Medion 41700", {
+ DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
+ DMI_MATCH(DMI_BIOS_VERSION,"R01-A1J") }},
+ {},
+};
+
+
+static inline u32
+ticks_elapsed (
+ u32 t1,
+ u32 t2)
+{
+ if (t2 >= t1)
+ return (t2 - t1);
+ else if (!acpi_fadt.tmr_val_ext)
+ return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
+ else
+ return ((0xFFFFFFFF - t1) + t2);
+}
+
+
+static void
+acpi_processor_power_activate (
+ struct acpi_processor *pr,
+ struct acpi_processor_cx *new)
+{
+ struct acpi_processor_cx *old;
+
+ if (!pr || !new)
+ return;
+
+ old = pr->power.state;
+
+ if (old)
+ old->promotion.count = 0;
+ new->demotion.count = 0;
+
+ /* Cleanup from old state. */
+ if (old) {
+ switch (old->type) {
+ case ACPI_STATE_C3:
+ /* Disable bus master reload */
+ if (new->type != ACPI_STATE_C3)
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, ACPI_MTX_DO_NOT_LOCK);
+ break;
+ }
+ }
+
+ /* Prepare to use new state. */
+ switch (new->type) {
+ case ACPI_STATE_C3:
+ /* Enable bus master reload */
+ if (old->type != ACPI_STATE_C3)
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1, ACPI_MTX_DO_NOT_LOCK);
+ break;
+ }
+
+ pr->power.state = new;
+
+ return;
+}
+
+
+static void acpi_processor_idle (void)
+{
+ struct acpi_processor *pr = NULL;
+ struct acpi_processor_cx *cx = NULL;
+ struct acpi_processor_cx *next_state = NULL;
+ int sleep_ticks = 0;
+ u32 t1, t2 = 0;
+
+ pr = processors[_smp_processor_id()];
+ if (!pr)
+ return;
+
+ /*
+ * Interrupts must be disabled during bus mastering calculations and
+ * for C2/C3 transitions.
+ */
+ local_irq_disable();
+
+ /*
+ * Check whether we truly need to go idle, or should
+ * reschedule:
+ */
+ if (unlikely(need_resched())) {
+ local_irq_enable();
+ return;
+ }
+
+ cx = pr->power.state;
+ if (!cx)
+ goto easy_out;
+
+ /*
+ * Check BM Activity
+ * -----------------
+ * Check for bus mastering activity (if required), record, and check
+ * for demotion.
+ */
+ if (pr->flags.bm_check) {
+ u32 bm_status = 0;
+ unsigned long diff = jiffies - pr->power.bm_check_timestamp;
+
+ if (diff > 32)
+ diff = 32;
+
+ while (diff) {
+ /* if we didn't get called, assume there was busmaster activity */
+ diff--;
+ if (diff)
+ pr->power.bm_activity |= 0x1;
+ pr->power.bm_activity <<= 1;
+ }
+
+ acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
+ &bm_status, ACPI_MTX_DO_NOT_LOCK);
+ if (bm_status) {
+ pr->power.bm_activity++;
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
+ 1, ACPI_MTX_DO_NOT_LOCK);
+ }
+ /*
+ * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
+ * the true state of bus mastering activity; forcing us to
+ * manually check the BMIDEA bit of each IDE channel.
+ */
+ else if (errata.piix4.bmisx) {
+ if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
+ || (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
+ pr->power.bm_activity++;
+ }
+
+ pr->power.bm_check_timestamp = jiffies;
+
+ /*
+ * Apply bus mastering demotion policy. Automatically demote
+ * to avoid a faulty transition. Note that the processor
+ * won't enter a low-power state during this call (to this
+ * funciton) but should upon the next.
+ *
+ * TBD: A better policy might be to fallback to the demotion
+ * state (use it for this quantum only) istead of
+ * demoting -- and rely on duration as our sole demotion
+ * qualification. This may, however, introduce DMA
+ * issues (e.g. floppy DMA transfer overrun/underrun).
+ */
+ if (pr->power.bm_activity & cx->demotion.threshold.bm) {
+ local_irq_enable();
+ next_state = cx->demotion.state;
+ goto end;
+ }
+ }
+
+ cx->usage++;
+
+ /*
+ * Sleep:
+ * ------
+ * Invoke the current Cx state to put the processor to sleep.
+ */
+ switch (cx->type) {
+
+ case ACPI_STATE_C1:
+ /*
+ * Invoke C1.
+ * Use the appropriate idle routine, the one that would
+ * be used without acpi C-states.
+ */
+ if (pm_idle_save)
+ pm_idle_save();
+ else
+ safe_halt();
+ /*
+ * TBD: Can't get time duration while in C1, as resumes
+ * go to an ISR rather than here. Need to instrument
+ * base interrupt handler.
+ */
+ sleep_ticks = 0xFFFFFFFF;
+ break;
+
+ case ACPI_STATE_C2:
+ /* Get start time (ticks) */
+ t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Invoke C2 */
+ inb(cx->address);
+ /* Dummy op - must do something useless after P_LVL2 read */
+ t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Get end time (ticks) */
+ t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Re-enable interrupts */
+ local_irq_enable();
+ /* Compute time (ticks) that we were actually asleep */
+ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
+ break;
+
+ case ACPI_STATE_C3:
+ /* Disable bus master arbitration */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+ /* Get start time (ticks) */
+ t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Invoke C3 */
+ inb(cx->address);
+ /* Dummy op - must do something useless after P_LVL3 read */
+ t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Get end time (ticks) */
+ t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+ /* Enable bus master arbitration */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK);
+ /* Re-enable interrupts */
+ local_irq_enable();
+ /* Compute time (ticks) that we were actually asleep */
+ sleep_ticks = ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;
+ break;
+
+ default:
+ local_irq_enable();
+ return;
+ }
+
+ next_state = pr->power.state;
+
+ /*
+ * Promotion?
+ * ----------
+ * Track the number of longs (time asleep is greater than threshold)
+ * and promote when the count threshold is reached. Note that bus
+ * mastering activity may prevent promotions.
+ * Do not promote above max_cstate.
+ */
+ if (cx->promotion.state &&
+ ((cx->promotion.state - pr->power.states) <= max_cstate)) {
+ if (sleep_ticks > cx->promotion.threshold.ticks) {
+ cx->promotion.count++;
+ cx->demotion.count = 0;
+ if (cx->promotion.count >= cx->promotion.threshold.count) {
+ if (pr->flags.bm_check) {
+ if (!(pr->power.bm_activity & cx->promotion.threshold.bm)) {
+ next_state = cx->promotion.state;
+ goto end;
+ }
+ }
+ else {
+ next_state = cx->promotion.state;
+ goto end;
+ }
+ }
+ }
+ }
+
+ /*
+ * Demotion?
+ * ---------
+ * Track the number of shorts (time asleep is less than time threshold)
+ * and demote when the usage threshold is reached.
+ */
+ if (cx->demotion.state) {
+ if (sleep_ticks < cx->demotion.threshold.ticks) {
+ cx->demotion.count++;
+ cx->promotion.count = 0;
+ if (cx->demotion.count >= cx->demotion.threshold.count) {
+ next_state = cx->demotion.state;
+ goto end;
+ }
+ }
+ }
+
+end:
+ /*
+ * Demote if current state exceeds max_cstate
+ */
+ if ((pr->power.state - pr->power.states) > max_cstate) {
+ if (cx->demotion.state)
+ next_state = cx->demotion.state;
+ }
+
+ /*
+ * New Cx State?
+ * -------------
+ * If we're going to start using a new Cx state we must clean up
+ * from the previous and prepare to use the new.
+ */
+ if (next_state != pr->power.state)
+ acpi_processor_power_activate(pr, next_state);
+
+ return;
+
+ easy_out:
+ /* do C1 instead of busy loop */
+ if (pm_idle_save)
+ pm_idle_save();
+ else
+ safe_halt();
+ return;
+}
+
+
+static int
+acpi_processor_set_power_policy (
+ struct acpi_processor *pr)
+{
+ unsigned int i;
+ unsigned int state_is_set = 0;
+ struct acpi_processor_cx *lower = NULL;
+ struct acpi_processor_cx *higher = NULL;
+ struct acpi_processor_cx *cx;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_set_power_policy");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ /*
+ * This function sets the default Cx state policy (OS idle handler).
+ * Our scheme is to promote quickly to C2 but more conservatively
+ * to C3. We're favoring C2 for its characteristics of low latency
+ * (quick response), good power savings, and ability to allow bus
+ * mastering activity. Note that the Cx state policy is completely
+ * customizable and can be altered dynamically.
+ */
+
+ /* startup state */
+ for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ cx = &pr->power.states[i];
+ if (!cx->valid)
+ continue;
+
+ if (!state_is_set)
+ pr->power.state = cx;
+ state_is_set++;
+ break;
+ }
+
+ if (!state_is_set)
+ return_VALUE(-ENODEV);
+
+ /* demotion */
+ for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ cx = &pr->power.states[i];
+ if (!cx->valid)
+ continue;
+
+ if (lower) {
+ cx->demotion.state = lower;
+ cx->demotion.threshold.ticks = cx->latency_ticks;
+ cx->demotion.threshold.count = 1;
+ if (cx->type == ACPI_STATE_C3)
+ cx->demotion.threshold.bm = bm_history;
+ }
+
+ lower = cx;
+ }
+
+ /* promotion */
+ for (i = (ACPI_PROCESSOR_MAX_POWER - 1); i > 0; i--) {
+ cx = &pr->power.states[i];
+ if (!cx->valid)
+ continue;
+
+ if (higher) {
+ cx->promotion.state = higher;
+ cx->promotion.threshold.ticks = cx->latency_ticks;
+ if (cx->type >= ACPI_STATE_C2)
+ cx->promotion.threshold.count = 4;
+ else
+ cx->promotion.threshold.count = 10;
+ if (higher->type == ACPI_STATE_C3)
+ cx->promotion.threshold.bm = bm_history;
+ }
+
+ higher = cx;
+ }
+
+ return_VALUE(0);
+}
+
+
+static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
+{
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_fadt");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if (!pr->pblk)
+ return_VALUE(-ENODEV);
+
+ for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
+ memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+
+ /* if info is obtained from pblk/fadt, type equals state */
+ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+ pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2;
+ pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3;
+
+ /* the C0 state only exists as a filler in our array,
+ * and all processors need to support C1 */
+ pr->power.states[ACPI_STATE_C0].valid = 1;
+ pr->power.states[ACPI_STATE_C1].valid = 1;
+
+ /* determine C2 and C3 address from pblk */
+ pr->power.states[ACPI_STATE_C2].address = pr->pblk + 4;
+ pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
+
+ /* determine latencies from FADT */
+ pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
+ pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "lvl2[0x%08x] lvl3[0x%08x]\n",
+ pr->power.states[ACPI_STATE_C2].address,
+ pr->power.states[ACPI_STATE_C3].address));
+
+ return_VALUE(0);
+}
+
+
+static int acpi_processor_get_power_info_cst (struct acpi_processor *pr)
+{
+ acpi_status status = 0;
+ acpi_integer count;
+ int i;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *cst;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_cst");
+
+ if (errata.smp)
+ return_VALUE(-ENODEV);
+
+ if (nocst)
+ return_VALUE(-ENODEV);
+
+ pr->power.count = 0;
+ for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
+ memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+
+ status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _CST, giving up\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ cst = (union acpi_object *) buffer.pointer;
+
+ /* There must be at least 2 elements */
+ if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "not enough elements in _CST\n"));
+ status = -EFAULT;
+ goto end;
+ }
+
+ count = cst->package.elements[0].integer.value;
+
+ /* Validate number of power states. */
+ if (count < 1 || count != cst->package.count - 1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "count given by _CST is not valid\n"));
+ status = -EFAULT;
+ goto end;
+ }
+
+ /* We support up to ACPI_PROCESSOR_MAX_POWER. */
+ if (count > ACPI_PROCESSOR_MAX_POWER) {
+ printk(KERN_WARNING "Limiting number of power states to max (%d)\n", ACPI_PROCESSOR_MAX_POWER);
+ printk(KERN_WARNING "Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");
+ count = ACPI_PROCESSOR_MAX_POWER;
+ }
+
+ /* Tell driver that at least _CST is supported. */
+ pr->flags.has_cst = 1;
+
+ for (i = 1; i <= count; i++) {
+ union acpi_object *element;
+ union acpi_object *obj;
+ struct acpi_power_register *reg;
+ struct acpi_processor_cx cx;
+
+ memset(&cx, 0, sizeof(cx));
+
+ element = (union acpi_object *) &(cst->package.elements[i]);
+ if (element->type != ACPI_TYPE_PACKAGE)
+ continue;
+
+ if (element->package.count != 4)
+ continue;
+
+ obj = (union acpi_object *) &(element->package.elements[0]);
+
+ if (obj->type != ACPI_TYPE_BUFFER)
+ continue;
+
+ reg = (struct acpi_power_register *) obj->buffer.pointer;
+
+ if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&
+ (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
+ continue;
+
+ cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
+ 0 : reg->address;
+
+ /* There should be an easy way to extract an integer... */
+ obj = (union acpi_object *) &(element->package.elements[1]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ cx.type = obj->integer.value;
+
+ if ((cx.type != ACPI_STATE_C1) &&
+ (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
+ continue;
+
+ if ((cx.type < ACPI_STATE_C1) ||
+ (cx.type > ACPI_STATE_C3))
+ continue;
+
+ obj = (union acpi_object *) &(element->package.elements[2]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ cx.latency = obj->integer.value;
+
+ obj = (union acpi_object *) &(element->package.elements[3]);
+ if (obj->type != ACPI_TYPE_INTEGER)
+ continue;
+
+ cx.power = obj->integer.value;
+
+ (pr->power.count)++;
+ memcpy(&(pr->power.states[pr->power.count]), &cx, sizeof(cx));
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n", pr->power.count));
+
+ /* Validate number of power states discovered */
+ if (pr->power.count < 2)
+ status = -ENODEV;
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ return_VALUE(status);
+}
+
+
+static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c2");
+
+ if (!cx->address)
+ return_VOID;
+
+ /*
+ * C2 latency must be less than or equal to 100
+ * microseconds.
+ */
+ else if (cx->latency > ACPI_PROCESSOR_MAX_C2_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "latency too large [%d]\n",
+ cx->latency));
+ return_VOID;
+ }
+
+ /* We're (currently) only supporting C2 on UP */
+ else if (errata.smp) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C2 not supported in SMP mode\n"));
+ return_VOID;
+ }
+
+ /*
+ * Otherwise we've met all of our C2 requirements.
+ * Normalize the C2 latency to expidite policy
+ */
+ cx->valid = 1;
+ cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+
+ return_VOID;
+}
+
+
+static void acpi_processor_power_verify_c3(
+ struct acpi_processor *pr,
+ struct acpi_processor_cx *cx)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c3");
+
+ if (!cx->address)
+ return_VOID;
+
+ /*
+ * C3 latency must be less than or equal to 1000
+ * microseconds.
+ */
+ else if (cx->latency > ACPI_PROCESSOR_MAX_C3_LATENCY) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "latency too large [%d]\n",
+ cx->latency));
+ return_VOID;
+ }
+
+ /* bus mastering control is necessary */
+ else if (!pr->flags.bm_control) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 support requires bus mastering control\n"));
+ return_VOID;
+ }
+
+ /* We're (currently) only supporting C2 on UP */
+ else if (errata.smp) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 not supported in SMP mode\n"));
+ return_VOID;
+ }
+
+ /*
+ * PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
+ * DMA transfers are used by any ISA device to avoid livelock.
+ * Note that we could disable Type-F DMA (as recommended by
+ * the erratum), but this is known to disrupt certain ISA
+ * devices thus we take the conservative approach.
+ */
+ else if (errata.piix4.fdma) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 not supported on PIIX4 with Type-F DMA\n"));
+ return_VOID;
+ }
+
+ /*
+ * Otherwise we've met all of our C3 requirements.
+ * Normalize the C3 latency to expidite policy. Enable
+ * checking of bus mastering status (bm_check) so we can
+ * use this in our C3 policy
+ */
+ cx->valid = 1;
+ cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
+ pr->flags.bm_check = 1;
+
+ return_VOID;
+}
+
+
+static int acpi_processor_power_verify(struct acpi_processor *pr)
+{
+ unsigned int i;
+ unsigned int working = 0;
+
+ for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ struct acpi_processor_cx *cx = &pr->power.states[i];
+
+ switch (cx->type) {
+ case ACPI_STATE_C1:
+ cx->valid = 1;
+ break;
+
+ case ACPI_STATE_C2:
+ acpi_processor_power_verify_c2(cx);
+ break;
+
+ case ACPI_STATE_C3:
+ acpi_processor_power_verify_c3(pr, cx);
+ break;
+ }
+
+ if (cx->valid)
+ working++;
+ }
+
+ return (working);
+}
+
+static int acpi_processor_get_power_info (
+ struct acpi_processor *pr)
+{
+ unsigned int i;
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_info");
+
+ /* NOTE: the idle thread may not be running while calling
+ * this function */
+
+ result = acpi_processor_get_power_info_cst(pr);
+ if ((result) || (acpi_processor_power_verify(pr) < 2)) {
+ result = acpi_processor_get_power_info_fadt(pr);
+ if (result)
+ return_VALUE(result);
+
+ if (acpi_processor_power_verify(pr) < 2)
+ return_VALUE(-ENODEV);
+ }
+
+ /*
+ * Set Default Policy
+ * ------------------
+ * Now that we know which states are supported, set the default
+ * policy. Note that this policy can be changed dynamically
+ * (e.g. encourage deeper sleeps to conserve battery life when
+ * not on AC).
+ */
+ result = acpi_processor_set_power_policy(pr);
+ if (result)
+ return_VALUE(result);
+
+ /*
+ * if one state of type C2 or C3 is available, mark this
+ * CPU as being "idle manageable"
+ */
+ for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+ if (pr->power.states[i].valid)
+ pr->power.count = i;
+ if ((pr->power.states[i].valid) &&
+ (pr->power.states[i].type >= ACPI_STATE_C2))
+ pr->flags.power = 1;
+ }
+
+ return_VALUE(0);
+}
+
+int acpi_processor_cst_has_changed (struct acpi_processor *pr)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_cst_has_changed");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if (errata.smp || nocst) {
+ return_VALUE(-ENODEV);
+ }
+
+ if (!pr->flags.power_setup_done)
+ return_VALUE(-ENODEV);
+
+ /* Fall back to the default idle loop */
+ pm_idle = pm_idle_save;
+ synchronize_kernel();
+
+ pr->flags.power = 0;
+ result = acpi_processor_get_power_info(pr);
+ if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
+ pm_idle = acpi_processor_idle;
+
+ return_VALUE(result);
+}
+
+/* proc interface */
+
+static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ unsigned int i;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_power_seq_show");
+
+ if (!pr)
+ goto end;
+
+ seq_printf(seq, "active state: C%zd\n"
+ "max_cstate: C%d\n"
+ "bus master activity: %08x\n",
+ pr->power.state ? pr->power.state - pr->power.states : 0,
+ max_cstate,
+ (unsigned)pr->power.bm_activity);
+
+ seq_puts(seq, "states:\n");
+
+ for (i = 1; i <= pr->power.count; i++) {
+ seq_printf(seq, " %cC%d: ",
+ (&pr->power.states[i] == pr->power.state?'*':' '), i);
+
+ if (!pr->power.states[i].valid) {
+ seq_puts(seq, "<not supported>\n");
+ continue;
+ }
+
+ switch (pr->power.states[i].type) {
+ case ACPI_STATE_C1:
+ seq_printf(seq, "type[C1] ");
+ break;
+ case ACPI_STATE_C2:
+ seq_printf(seq, "type[C2] ");
+ break;
+ case ACPI_STATE_C3:
+ seq_printf(seq, "type[C3] ");
+ break;
+ default:
+ seq_printf(seq, "type[--] ");
+ break;
+ }
+
+ if (pr->power.states[i].promotion.state)
+ seq_printf(seq, "promotion[C%zd] ",
+ (pr->power.states[i].promotion.state -
+ pr->power.states));
+ else
+ seq_puts(seq, "promotion[--] ");
+
+ if (pr->power.states[i].demotion.state)
+ seq_printf(seq, "demotion[C%zd] ",
+ (pr->power.states[i].demotion.state -
+ pr->power.states));
+ else
+ seq_puts(seq, "demotion[--] ");
+
+ seq_printf(seq, "latency[%03d] usage[%08d]\n",
+ pr->power.states[i].latency,
+ pr->power.states[i].usage);
+ }
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_processor_power_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_processor_power_seq_show,
+ PDE(inode)->data);
+}
+
+static struct file_operations acpi_processor_power_fops = {
+ .open = acpi_processor_power_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device)
+{
+ acpi_status status = 0;
+ static int first_run = 0;
+ struct proc_dir_entry *entry = NULL;
+ unsigned int i;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_power_init");
+
+ if (!first_run) {
+ dmi_check_system(processor_power_dmi_table);
+ if (max_cstate < ACPI_C_STATES_MAX)
+ printk(KERN_NOTICE "ACPI: processor limited to max C-state %d\n", max_cstate);
+ first_run++;
+ }
+
+ if (!errata.smp && (pr->id == 0) && acpi_fadt.cst_cnt && !nocst) {
+ status = acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Notifying BIOS of _CST ability failed\n"));
+ }
+ }
+
+ acpi_processor_get_power_info(pr);
+
+ /*
+ * Install the idle handler if processor power management is supported.
+ * Note that we use previously set idle handler will be used on
+ * platforms that only support C1.
+ */
+ if ((pr->flags.power) && (!boot_option_idle_override)) {
+ printk(KERN_INFO PREFIX "CPU%d (power states:", pr->id);
+ for (i = 1; i <= pr->power.count; i++)
+ if (pr->power.states[i].valid)
+ printk(" C%d[C%d]", i, pr->power.states[i].type);
+ printk(")\n");
+
+ if (pr->id == 0) {
+ pm_idle_save = pm_idle;
+ pm_idle = acpi_processor_idle;
+ }
+ }
+
+ /* 'power' [R] */
+ entry = create_proc_entry(ACPI_PROCESSOR_FILE_POWER,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_PROCESSOR_FILE_POWER));
+ else {
+ entry->proc_fops = &acpi_processor_power_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ pr->flags.power_setup_done = 1;
+
+ return_VALUE(0);
+}
+
+int acpi_processor_power_exit(struct acpi_processor *pr, struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_power_exit");
+
+ pr->flags.power_setup_done = 0;
+
+ if (acpi_device_dir(device))
+ remove_proc_entry(ACPI_PROCESSOR_FILE_POWER,acpi_device_dir(device));
+
+ /* Unregister the idle handler when processor #0 is removed. */
+ if (pr->id == 0) {
+ pm_idle = pm_idle_save;
+
+ /*
+ * We are about to unload the current idle thread pm callback
+ * (pm_idle), Wait for all processors to update cached/local
+ * copies of pm_idle before proceeding.
+ */
+ cpu_idle_wait();
+ }
+
+ return_VALUE(0);
+}
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
new file mode 100644
index 000000000000..a9a1a8fe3199
--- /dev/null
+++ b/drivers/acpi/processor_perflib.c
@@ -0,0 +1,666 @@
+/*
+ * processor_perflib.c - ACPI Processor P-States Library ($Revision: 71 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * - Added processor hotplug support
+ *
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/cpufreq.h>
+
+#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/uaccess.h>
+#endif
+
+#include <acpi/acpi_bus.h>
+#include <acpi/processor.h>
+
+
+#define ACPI_PROCESSOR_COMPONENT 0x01000000
+#define ACPI_PROCESSOR_CLASS "processor"
+#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
+#define ACPI_PROCESSOR_FILE_PERFORMANCE "performance"
+#define _COMPONENT ACPI_PROCESSOR_COMPONENT
+ACPI_MODULE_NAME ("acpi_processor")
+
+
+static DECLARE_MUTEX(performance_sem);
+
+/*
+ * _PPC support is implemented as a CPUfreq policy notifier:
+ * This means each time a CPUfreq driver registered also with
+ * the ACPI core is asked to change the speed policy, the maximum
+ * value is adjusted so that it is within the platform limit.
+ *
+ * Also, when a new platform limit value is detected, the CPUfreq
+ * policy is adjusted accordingly.
+ */
+
+#define PPC_REGISTERED 1
+#define PPC_IN_USE 2
+
+static int acpi_processor_ppc_status = 0;
+
+static int acpi_processor_ppc_notifier(struct notifier_block *nb,
+ unsigned long event,
+ void *data)
+{
+ struct cpufreq_policy *policy = data;
+ struct acpi_processor *pr;
+ unsigned int ppc = 0;
+
+ down(&performance_sem);
+
+ if (event != CPUFREQ_INCOMPATIBLE)
+ goto out;
+
+ pr = processors[policy->cpu];
+ if (!pr || !pr->performance)
+ goto out;
+
+ ppc = (unsigned int) pr->performance_platform_limit;
+ if (!ppc)
+ goto out;
+
+ if (ppc > pr->performance->state_count)
+ goto out;
+
+ cpufreq_verify_within_limits(policy, 0,
+ pr->performance->states[ppc].core_frequency * 1000);
+
+ out:
+ up(&performance_sem);
+
+ return 0;
+}
+
+
+static struct notifier_block acpi_ppc_notifier_block = {
+ .notifier_call = acpi_processor_ppc_notifier,
+};
+
+
+static int
+acpi_processor_get_platform_limit (
+ struct acpi_processor* pr)
+{
+ acpi_status status = 0;
+ unsigned long ppc = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_platform_limit");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ /*
+ * _PPC indicates the maximum state currently supported by the platform
+ * (e.g. 0 = states 0..n; 1 = states 1..n; etc.
+ */
+ status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
+
+ if (status != AE_NOT_FOUND)
+ acpi_processor_ppc_status |= PPC_IN_USE;
+
+ if(ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PPC\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ pr->performance_platform_limit = (int) ppc;
+
+ return_VALUE(0);
+}
+
+
+int acpi_processor_ppc_has_changed(
+ struct acpi_processor *pr)
+{
+ int ret = acpi_processor_get_platform_limit(pr);
+ if (ret < 0)
+ return (ret);
+ else
+ return cpufreq_update_policy(pr->id);
+}
+
+
+void acpi_processor_ppc_init(void) {
+ if (!cpufreq_register_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER))
+ acpi_processor_ppc_status |= PPC_REGISTERED;
+ else
+ printk(KERN_DEBUG "Warning: Processor Platform Limit not supported.\n");
+}
+
+
+void acpi_processor_ppc_exit(void) {
+ if (acpi_processor_ppc_status & PPC_REGISTERED)
+ cpufreq_unregister_notifier(&acpi_ppc_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+
+ acpi_processor_ppc_status &= ~PPC_REGISTERED;
+}
+
+/*
+ * when registering a cpufreq driver with this ACPI processor driver, the
+ * _PCT and _PSS structures are read out and written into struct
+ * acpi_processor_performance.
+ */
+static int acpi_processor_set_pdc (struct acpi_processor *pr)
+{
+ acpi_status status = AE_OK;
+ u32 arg0_buf[3];
+ union acpi_object arg0 = {ACPI_TYPE_BUFFER};
+ struct acpi_object_list no_object = {1, &arg0};
+ struct acpi_object_list *pdc;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_set_pdc");
+
+ arg0.buffer.length = 12;
+ arg0.buffer.pointer = (u8 *) arg0_buf;
+ arg0_buf[0] = ACPI_PDC_REVISION_ID;
+ arg0_buf[1] = 0;
+ arg0_buf[2] = 0;
+
+ pdc = (pr->performance->pdc) ? pr->performance->pdc : &no_object;
+
+ status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL);
+
+ if ((ACPI_FAILURE(status)) && (pr->performance->pdc))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n"));
+
+ return_VALUE(status);
+}
+
+
+static int
+acpi_processor_get_performance_control (
+ struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *pct = NULL;
+ union acpi_object obj = {0};
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control");
+
+ status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
+ if(ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ pct = (union acpi_object *) buffer.pointer;
+ if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
+ || (pct->package.count != 2)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ /*
+ * control_register
+ */
+
+ obj = pct->package.elements[0];
+
+ if ((obj.type != ACPI_TYPE_BUFFER)
+ || (obj.buffer.length < sizeof(struct acpi_pct_register))
+ || (obj.buffer.pointer == NULL)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid _PCT data (control_register)\n"));
+ result = -EFAULT;
+ goto end;
+ }
+ memcpy(&pr->performance->control_register, obj.buffer.pointer, sizeof(struct acpi_pct_register));
+
+
+ /*
+ * status_register
+ */
+
+ obj = pct->package.elements[1];
+
+ if ((obj.type != ACPI_TYPE_BUFFER)
+ || (obj.buffer.length < sizeof(struct acpi_pct_register))
+ || (obj.buffer.pointer == NULL)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid _PCT data (status_register)\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ memcpy(&pr->performance->status_register, obj.buffer.pointer, sizeof(struct acpi_pct_register));
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_processor_get_performance_states (
+ struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_buffer format = {sizeof("NNNNNN"), "NNNNNN"};
+ struct acpi_buffer state = {0, NULL};
+ union acpi_object *pss = NULL;
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states");
+
+ status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
+ if(ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ pss = (union acpi_object *) buffer.pointer;
+ if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
+ result = -EFAULT;
+ goto end;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n",
+ pss->package.count));
+
+ pr->performance->state_count = pss->package.count;
+ pr->performance->states = kmalloc(sizeof(struct acpi_processor_px) * pss->package.count, GFP_KERNEL);
+ if (!pr->performance->states) {
+ result = -ENOMEM;
+ goto end;
+ }
+
+ for (i = 0; i < pr->performance->state_count; i++) {
+
+ struct acpi_processor_px *px = &(pr->performance->states[i]);
+
+ state.length = sizeof(struct acpi_processor_px);
+ state.pointer = px;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
+
+ status = acpi_extract_package(&(pss->package.elements[i]),
+ &format, &state);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
+ result = -EFAULT;
+ kfree(pr->performance->states);
+ goto end;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n",
+ i,
+ (u32) px->core_frequency,
+ (u32) px->power,
+ (u32) px->transition_latency,
+ (u32) px->bus_master_latency,
+ (u32) px->control,
+ (u32) px->status));
+
+ if (!px->core_frequency) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data: freq is zero\n"));
+ result = -EFAULT;
+ kfree(pr->performance->states);
+ goto end;
+ }
+ }
+
+end:
+ acpi_os_free(buffer.pointer);
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_processor_get_performance_info (
+ struct acpi_processor *pr)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ acpi_handle handle = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info");
+
+ if (!pr || !pr->performance || !pr->handle)
+ return_VALUE(-EINVAL);
+
+ acpi_processor_set_pdc(pr);
+
+ status = acpi_get_handle(pr->handle, "_PCT", &handle);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "ACPI-based processor performance control unavailable\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ result = acpi_processor_get_performance_control(pr);
+ if (result)
+ return_VALUE(result);
+
+ result = acpi_processor_get_performance_states(pr);
+ if (result)
+ return_VALUE(result);
+
+ result = acpi_processor_get_platform_limit(pr);
+ if (result)
+ return_VALUE(result);
+
+ return_VALUE(0);
+}
+
+
+int acpi_processor_notify_smm(struct module *calling_module) {
+ acpi_status status;
+ static int is_done = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_notify_smm");
+
+ if (!(acpi_processor_ppc_status & PPC_REGISTERED))
+ return_VALUE(-EBUSY);
+
+ if (!try_module_get(calling_module))
+ return_VALUE(-EINVAL);
+
+ /* is_done is set to negative if an error occured,
+ * and to postitive if _no_ error occured, but SMM
+ * was already notified. This avoids double notification
+ * which might lead to unexpected results...
+ */
+ if (is_done > 0) {
+ module_put(calling_module);
+ return_VALUE(0);
+ }
+ else if (is_done < 0) {
+ module_put(calling_module);
+ return_VALUE(is_done);
+ }
+
+ is_done = -EIO;
+
+ /* Can't write pstate_cnt to smi_cmd if either value is zero */
+ if ((!acpi_fadt.smi_cmd) ||
+ (!acpi_fadt.pstate_cnt)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "No SMI port or pstate_cnt\n"));
+ module_put(calling_module);
+ return_VALUE(0);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n", acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+
+ /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
+ * it anyway, so we need to support it... */
+ if (acpi_fadt_is_v1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Using v1.0 FADT reserved value for pstate_cnt\n"));
+ }
+
+ status = acpi_os_write_port (acpi_fadt.smi_cmd,
+ (u32) acpi_fadt.pstate_cnt, 8);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Failed to write pstate_cnt [0x%x] to "
+ "smi_cmd [0x%x]\n", acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+ module_put(calling_module);
+ return_VALUE(status);
+ }
+
+ /* Success. If there's no _PPC, we need to fear nothing, so
+ * we can allow the cpufreq driver to be rmmod'ed. */
+ is_done = 1;
+
+ if (!(acpi_processor_ppc_status & PPC_IN_USE))
+ module_put(calling_module);
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_processor_notify_smm);
+
+
+#ifdef CONFIG_X86_ACPI_CPUFREQ_PROC_INTF
+/* /proc/acpi/processor/../performance interface (DEPRECATED) */
+
+static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_processor_perf_fops = {
+ .open = acpi_processor_perf_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int acpi_processor_perf_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_perf_seq_show");
+
+ if (!pr)
+ goto end;
+
+ if (!pr->performance) {
+ seq_puts(seq, "<not supported>\n");
+ goto end;
+ }
+
+ seq_printf(seq, "state count: %d\n"
+ "active state: P%d\n",
+ pr->performance->state_count,
+ pr->performance->state);
+
+ seq_puts(seq, "states:\n");
+ for (i = 0; i < pr->performance->state_count; i++)
+ seq_printf(seq, " %cP%d: %d MHz, %d mW, %d uS\n",
+ (i == pr->performance->state?'*':' '), i,
+ (u32) pr->performance->states[i].core_frequency,
+ (u32) pr->performance->states[i].power,
+ (u32) pr->performance->states[i].transition_latency);
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_processor_perf_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_processor_perf_seq_show,
+ PDE(inode)->data);
+}
+
+static ssize_t
+acpi_processor_write_performance (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *data)
+{
+ int result = 0;
+ struct seq_file *m = (struct seq_file *) file->private_data;
+ struct acpi_processor *pr = (struct acpi_processor *) m->private;
+ struct acpi_processor_performance *perf;
+ char state_string[12] = {'\0'};
+ unsigned int new_state = 0;
+ struct cpufreq_policy policy;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_write_performance");
+
+ if (!pr || (count > sizeof(state_string) - 1))
+ return_VALUE(-EINVAL);
+
+ perf = pr->performance;
+ if (!perf)
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(state_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ state_string[count] = '\0';
+ new_state = simple_strtoul(state_string, NULL, 0);
+
+ if (new_state >= perf->state_count)
+ return_VALUE(-EINVAL);
+
+ cpufreq_get_policy(&policy, pr->id);
+
+ policy.cpu = pr->id;
+ policy.min = perf->states[new_state].core_frequency * 1000;
+ policy.max = perf->states[new_state].core_frequency * 1000;
+
+ result = cpufreq_set_policy(&policy);
+ if (result)
+ return_VALUE(result);
+
+ return_VALUE(count);
+}
+
+static void
+acpi_cpufreq_add_file (
+ struct acpi_processor *pr)
+{
+ struct proc_dir_entry *entry = NULL;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile");
+
+ if (acpi_bus_get_device(pr->handle, &device))
+ return_VOID;
+
+ /* add file 'performance' [R/W] */
+ entry = create_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_PROCESSOR_FILE_PERFORMANCE));
+ else {
+ entry->proc_fops = &acpi_processor_perf_fops;
+ entry->proc_fops->write = acpi_processor_write_performance;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+ return_VOID;
+}
+
+static void
+acpi_cpufreq_remove_file (
+ struct acpi_processor *pr)
+{
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_cpufreq_addfile");
+
+ if (acpi_bus_get_device(pr->handle, &device))
+ return_VOID;
+
+ /* remove file 'performance' */
+ remove_proc_entry(ACPI_PROCESSOR_FILE_PERFORMANCE,
+ acpi_device_dir(device));
+
+ return_VOID;
+}
+
+#else
+static void acpi_cpufreq_add_file (struct acpi_processor *pr) { return; }
+static void acpi_cpufreq_remove_file (struct acpi_processor *pr) { return; }
+#endif /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
+
+
+int
+acpi_processor_register_performance (
+ struct acpi_processor_performance * performance,
+ unsigned int cpu)
+{
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_register_performance");
+
+ if (!(acpi_processor_ppc_status & PPC_REGISTERED))
+ return_VALUE(-EINVAL);
+
+ down(&performance_sem);
+
+ pr = processors[cpu];
+ if (!pr) {
+ up(&performance_sem);
+ return_VALUE(-ENODEV);
+ }
+
+ if (pr->performance) {
+ up(&performance_sem);
+ return_VALUE(-EBUSY);
+ }
+
+ pr->performance = performance;
+
+ if (acpi_processor_get_performance_info(pr)) {
+ pr->performance = NULL;
+ up(&performance_sem);
+ return_VALUE(-EIO);
+ }
+
+ acpi_cpufreq_add_file(pr);
+
+ up(&performance_sem);
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_processor_register_performance);
+
+
+void
+acpi_processor_unregister_performance (
+ struct acpi_processor_performance * performance,
+ unsigned int cpu)
+{
+ struct acpi_processor *pr;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_unregister_performance");
+
+ down(&performance_sem);
+
+ pr = processors[cpu];
+ if (!pr) {
+ up(&performance_sem);
+ return_VOID;
+ }
+
+ kfree(pr->performance->states);
+ pr->performance = NULL;
+
+ acpi_cpufreq_remove_file(pr);
+
+ up(&performance_sem);
+
+ return_VOID;
+}
+EXPORT_SYMBOL(acpi_processor_unregister_performance);
diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c
new file mode 100644
index 000000000000..12bd980a12e9
--- /dev/null
+++ b/drivers/acpi/processor_thermal.c
@@ -0,0 +1,406 @@
+/*
+ * processor_thermal.c - Passive cooling submodule of the ACPI processor driver
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * - Added processor hotplug support
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/cpufreq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/processor.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_PROCESSOR_COMPONENT 0x01000000
+#define ACPI_PROCESSOR_CLASS "processor"
+#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
+#define _COMPONENT ACPI_PROCESSOR_COMPONENT
+ACPI_MODULE_NAME ("acpi_processor")
+
+
+/* --------------------------------------------------------------------------
+ Limit Interface
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_processor_apply_limit (
+ struct acpi_processor* pr)
+{
+ int result = 0;
+ u16 px = 0;
+ u16 tx = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_apply_limit");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if (!pr->flags.limit)
+ return_VALUE(-ENODEV);
+
+ if (pr->flags.throttling) {
+ if (pr->limit.user.tx > tx)
+ tx = pr->limit.user.tx;
+ if (pr->limit.thermal.tx > tx)
+ tx = pr->limit.thermal.tx;
+
+ result = acpi_processor_set_throttling(pr, tx);
+ if (result)
+ goto end;
+ }
+
+ pr->limit.state.px = px;
+ pr->limit.state.tx = tx;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d] limit set to (P%d:T%d)\n",
+ pr->id,
+ pr->limit.state.px,
+ pr->limit.state.tx));
+
+end:
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n"));
+
+ return_VALUE(result);
+}
+
+
+#ifdef CONFIG_CPU_FREQ
+
+/* If a passive cooling situation is detected, primarily CPUfreq is used, as it
+ * offers (in most cases) voltage scaling in addition to frequency scaling, and
+ * thus a cubic (instead of linear) reduction of energy. Also, we allow for
+ * _any_ cpufreq driver and not only the acpi-cpufreq driver.
+ */
+
+static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
+static unsigned int acpi_thermal_cpufreq_is_init = 0;
+
+
+static int cpu_has_cpufreq(unsigned int cpu)
+{
+ struct cpufreq_policy policy;
+ if (!acpi_thermal_cpufreq_is_init)
+ return -ENODEV;
+ if (!cpufreq_get_policy(&policy, cpu))
+ return -ENODEV;
+ return 0;
+}
+
+
+static int acpi_thermal_cpufreq_increase(unsigned int cpu)
+{
+ if (!cpu_has_cpufreq(cpu))
+ return -ENODEV;
+
+ if (cpufreq_thermal_reduction_pctg[cpu] < 60) {
+ cpufreq_thermal_reduction_pctg[cpu] += 20;
+ cpufreq_update_policy(cpu);
+ return 0;
+ }
+
+ return -ERANGE;
+}
+
+
+static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
+{
+ if (!cpu_has_cpufreq(cpu))
+ return -ENODEV;
+
+ if (cpufreq_thermal_reduction_pctg[cpu] >= 20) {
+ cpufreq_thermal_reduction_pctg[cpu] -= 20;
+ cpufreq_update_policy(cpu);
+ return 0;
+ }
+
+ return -ERANGE;
+}
+
+
+static int acpi_thermal_cpufreq_notifier(
+ struct notifier_block *nb,
+ unsigned long event,
+ void *data)
+{
+ struct cpufreq_policy *policy = data;
+ unsigned long max_freq = 0;
+
+ if (event != CPUFREQ_ADJUST)
+ goto out;
+
+ max_freq = (policy->cpuinfo.max_freq * (100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100;
+
+ cpufreq_verify_within_limits(policy, 0, max_freq);
+
+ out:
+ return 0;
+}
+
+
+static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
+ .notifier_call = acpi_thermal_cpufreq_notifier,
+};
+
+
+void acpi_thermal_cpufreq_init(void) {
+ int i;
+
+ for (i=0; i<NR_CPUS; i++)
+ cpufreq_thermal_reduction_pctg[i] = 0;
+
+ i = cpufreq_register_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+ if (!i)
+ acpi_thermal_cpufreq_is_init = 1;
+}
+
+void acpi_thermal_cpufreq_exit(void) {
+ if (acpi_thermal_cpufreq_is_init)
+ cpufreq_unregister_notifier(&acpi_thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER);
+
+ acpi_thermal_cpufreq_is_init = 0;
+}
+
+#else /* ! CONFIG_CPU_FREQ */
+
+static int acpi_thermal_cpufreq_increase(unsigned int cpu) { return -ENODEV; }
+static int acpi_thermal_cpufreq_decrease(unsigned int cpu) { return -ENODEV; }
+
+
+#endif
+
+
+int
+acpi_processor_set_thermal_limit (
+ acpi_handle handle,
+ int type)
+{
+ int result = 0;
+ struct acpi_processor *pr = NULL;
+ struct acpi_device *device = NULL;
+ int tx = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit");
+
+ if ((type < ACPI_PROCESSOR_LIMIT_NONE)
+ || (type > ACPI_PROCESSOR_LIMIT_DECREMENT))
+ return_VALUE(-EINVAL);
+
+ result = acpi_bus_get_device(handle, &device);
+ if (result)
+ return_VALUE(result);
+
+ pr = (struct acpi_processor *) acpi_driver_data(device);
+ if (!pr)
+ return_VALUE(-ENODEV);
+
+ /* Thermal limits are always relative to the current Px/Tx state. */
+ if (pr->flags.throttling)
+ pr->limit.thermal.tx = pr->throttling.state;
+
+ /*
+ * Our default policy is to only use throttling at the lowest
+ * performance state.
+ */
+
+ tx = pr->limit.thermal.tx;
+
+ switch (type) {
+
+ case ACPI_PROCESSOR_LIMIT_NONE:
+ do {
+ result = acpi_thermal_cpufreq_decrease(pr->id);
+ } while (!result);
+ tx = 0;
+ break;
+
+ case ACPI_PROCESSOR_LIMIT_INCREMENT:
+ /* if going up: P-states first, T-states later */
+
+ result = acpi_thermal_cpufreq_increase(pr->id);
+ if (!result)
+ goto end;
+ else if (result == -ERANGE)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "At maximum performance state\n"));
+
+ if (pr->flags.throttling) {
+ if (tx == (pr->throttling.state_count - 1))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "At maximum throttling state\n"));
+ else
+ tx++;
+ }
+ break;
+
+ case ACPI_PROCESSOR_LIMIT_DECREMENT:
+ /* if going down: T-states first, P-states later */
+
+ if (pr->flags.throttling) {
+ if (tx == 0)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "At minimum throttling state\n"));
+ else {
+ tx--;
+ goto end;
+ }
+ }
+
+ result = acpi_thermal_cpufreq_decrease(pr->id);
+ if (result == -ERANGE)
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "At minimum performance state\n"));
+
+ break;
+ }
+
+end:
+ if (pr->flags.throttling) {
+ pr->limit.thermal.px = 0;
+ pr->limit.thermal.tx = tx;
+
+ result = acpi_processor_apply_limit(pr);
+ if (result)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to set thermal limit\n"));
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
+ pr->limit.thermal.px,
+ pr->limit.thermal.tx));
+ } else
+ result = 0;
+
+ return_VALUE(result);
+}
+
+
+int
+acpi_processor_get_limit_info (
+ struct acpi_processor *pr)
+{
+ ACPI_FUNCTION_TRACE("acpi_processor_get_limit_info");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if (pr->flags.throttling)
+ pr->flags.limit = 1;
+
+ return_VALUE(0);
+}
+
+
+/* /proc interface */
+
+static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_limit_seq_show");
+
+ if (!pr)
+ goto end;
+
+ if (!pr->flags.limit) {
+ seq_puts(seq, "<not supported>\n");
+ goto end;
+ }
+
+ seq_printf(seq, "active limit: P%d:T%d\n"
+ "user limit: P%d:T%d\n"
+ "thermal limit: P%d:T%d\n",
+ pr->limit.state.px, pr->limit.state.tx,
+ pr->limit.user.px, pr->limit.user.tx,
+ pr->limit.thermal.px, pr->limit.thermal.tx);
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_processor_limit_seq_show,
+ PDE(inode)->data);
+}
+
+ssize_t acpi_processor_write_limit (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *data)
+{
+ int result = 0;
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_processor *pr = (struct acpi_processor *)m->private;
+ char limit_string[25] = {'\0'};
+ int px = 0;
+ int tx = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_write_limit");
+
+ if (!pr || (count > sizeof(limit_string) - 1)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ if (copy_from_user(limit_string, buffer, count)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
+ return_VALUE(-EFAULT);
+ }
+
+ limit_string[count] = '\0';
+
+ if (sscanf(limit_string, "%d:%d", &px, &tx) != 2) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ if (pr->flags.throttling) {
+ if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n"));
+ return_VALUE(-EINVAL);
+ }
+ pr->limit.user.tx = tx;
+ }
+
+ result = acpi_processor_apply_limit(pr);
+
+ return_VALUE(count);
+}
+
+
+struct file_operations acpi_processor_limit_fops = {
+ .open = acpi_processor_limit_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c
new file mode 100644
index 000000000000..be9f569d39d3
--- /dev/null
+++ b/drivers/acpi/processor_throttling.c
@@ -0,0 +1,351 @@
+/*
+ * processor_throttling.c - Throttling submodule of the ACPI processor driver
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
+ * Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
+ * Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
+ * - Added processor hotplug support
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/cpufreq.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/processor.h>
+
+#define ACPI_PROCESSOR_COMPONENT 0x01000000
+#define ACPI_PROCESSOR_CLASS "processor"
+#define ACPI_PROCESSOR_DRIVER_NAME "ACPI Processor Driver"
+#define _COMPONENT ACPI_PROCESSOR_COMPONENT
+ACPI_MODULE_NAME ("acpi_processor")
+
+
+/* --------------------------------------------------------------------------
+ Throttling Control
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_processor_get_throttling (
+ struct acpi_processor *pr)
+{
+ int state = 0;
+ u32 value = 0;
+ u32 duty_mask = 0;
+ u32 duty_value = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_throttling");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if (!pr->flags.throttling)
+ return_VALUE(-ENODEV);
+
+ pr->throttling.state = 0;
+
+ duty_mask = pr->throttling.state_count - 1;
+
+ duty_mask <<= pr->throttling.duty_offset;
+
+ local_irq_disable();
+
+ value = inl(pr->throttling.address);
+
+ /*
+ * Compute the current throttling state when throttling is enabled
+ * (bit 4 is on).
+ */
+ if (value & 0x10) {
+ duty_value = value & duty_mask;
+ duty_value >>= pr->throttling.duty_offset;
+
+ if (duty_value)
+ state = pr->throttling.state_count-duty_value;
+ }
+
+ pr->throttling.state = state;
+
+ local_irq_enable();
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Throttling state is T%d (%d%% throttling applied)\n",
+ state, pr->throttling.states[state].performance));
+
+ return_VALUE(0);
+}
+
+
+int acpi_processor_set_throttling (
+ struct acpi_processor *pr,
+ int state)
+{
+ u32 value = 0;
+ u32 duty_mask = 0;
+ u32 duty_value = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_set_throttling");
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if ((state < 0) || (state > (pr->throttling.state_count - 1)))
+ return_VALUE(-EINVAL);
+
+ if (!pr->flags.throttling)
+ return_VALUE(-ENODEV);
+
+ if (state == pr->throttling.state)
+ return_VALUE(0);
+
+ /*
+ * Calculate the duty_value and duty_mask.
+ */
+ if (state) {
+ duty_value = pr->throttling.state_count - state;
+
+ duty_value <<= pr->throttling.duty_offset;
+
+ /* Used to clear all duty_value bits */
+ duty_mask = pr->throttling.state_count - 1;
+
+ duty_mask <<= acpi_fadt.duty_offset;
+ duty_mask = ~duty_mask;
+ }
+
+ local_irq_disable();
+
+ /*
+ * Disable throttling by writing a 0 to bit 4. Note that we must
+ * turn it off before you can change the duty_value.
+ */
+ value = inl(pr->throttling.address);
+ if (value & 0x10) {
+ value &= 0xFFFFFFEF;
+ outl(value, pr->throttling.address);
+ }
+
+ /*
+ * Write the new duty_value and then enable throttling. Note
+ * that a state value of 0 leaves throttling disabled.
+ */
+ if (state) {
+ value &= duty_mask;
+ value |= duty_value;
+ outl(value, pr->throttling.address);
+
+ value |= 0x00000010;
+ outl(value, pr->throttling.address);
+ }
+
+ pr->throttling.state = state;
+
+ local_irq_enable();
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Throttling state set to T%d (%d%%)\n", state,
+ (pr->throttling.states[state].performance?pr->throttling.states[state].performance/10:0)));
+
+ return_VALUE(0);
+}
+
+
+int
+acpi_processor_get_throttling_info (
+ struct acpi_processor *pr)
+{
+ int result = 0;
+ int step = 0;
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_throttling_info");
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
+ pr->throttling.address,
+ pr->throttling.duty_offset,
+ pr->throttling.duty_width));
+
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ /* TBD: Support ACPI 2.0 objects */
+
+ if (!pr->throttling.address) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
+ return_VALUE(0);
+ }
+ else if (!pr->throttling.duty_width) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
+ return_VALUE(0);
+ }
+ /* TBD: Support duty_cycle values that span bit 4. */
+ else if ((pr->throttling.duty_offset
+ + pr->throttling.duty_width) > 4) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "duty_cycle spans bit 4\n"));
+ return_VALUE(0);
+ }
+
+ /*
+ * PIIX4 Errata: We don't support throttling on the original PIIX4.
+ * This shouldn't be an issue as few (if any) mobile systems ever
+ * used this part.
+ */
+ if (errata.piix4.throttle) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Throttling not supported on PIIX4 A- or B-step\n"));
+ return_VALUE(0);
+ }
+
+ pr->throttling.state_count = 1 << acpi_fadt.duty_width;
+
+ /*
+ * Compute state values. Note that throttling displays a linear power/
+ * performance relationship (at 50% performance the CPU will consume
+ * 50% power). Values are in 1/10th of a percent to preserve accuracy.
+ */
+
+ step = (1000 / pr->throttling.state_count);
+
+ for (i=0; i<pr->throttling.state_count; i++) {
+ pr->throttling.states[i].performance = step * i;
+ pr->throttling.states[i].power = step * i;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
+ pr->throttling.state_count));
+
+ pr->flags.throttling = 1;
+
+ /*
+ * Disable throttling (if enabled). We'll let subsequent policy (e.g.
+ * thermal) decide to lower performance if it so chooses, but for now
+ * we'll crank up the speed.
+ */
+
+ result = acpi_processor_get_throttling(pr);
+ if (result)
+ goto end;
+
+ if (pr->throttling.state) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabling throttling (was T%d)\n",
+ pr->throttling.state));
+ result = acpi_processor_set_throttling(pr, 0);
+ if (result)
+ goto end;
+ }
+
+end:
+ if (result)
+ pr->flags.throttling = 0;
+
+ return_VALUE(result);
+}
+
+
+/* proc interface */
+
+static int acpi_processor_throttling_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_processor *pr = (struct acpi_processor *)seq->private;
+ int i = 0;
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_throttling_seq_show");
+
+ if (!pr)
+ goto end;
+
+ if (!(pr->throttling.state_count > 0)) {
+ seq_puts(seq, "<not supported>\n");
+ goto end;
+ }
+
+ result = acpi_processor_get_throttling(pr);
+
+ if (result) {
+ seq_puts(seq, "Could not determine current throttling state.\n");
+ goto end;
+ }
+
+ seq_printf(seq, "state count: %d\n"
+ "active state: T%d\n",
+ pr->throttling.state_count,
+ pr->throttling.state);
+
+ seq_puts(seq, "states:\n");
+ for (i = 0; i < pr->throttling.state_count; i++)
+ seq_printf(seq, " %cT%d: %02d%%\n",
+ (i == pr->throttling.state?'*':' '), i,
+ (pr->throttling.states[i].performance?pr->throttling.states[i].performance/10:0));
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_processor_throttling_seq_show,
+ PDE(inode)->data);
+}
+
+ssize_t acpi_processor_write_throttling (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *data)
+{
+ int result = 0;
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_processor *pr = (struct acpi_processor *)m->private;
+ char state_string[12] = {'\0'};
+
+ ACPI_FUNCTION_TRACE("acpi_processor_write_throttling");
+
+ if (!pr || (count > sizeof(state_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(state_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ state_string[count] = '\0';
+
+ result = acpi_processor_set_throttling(pr,
+ simple_strtoul(state_string, NULL, 0));
+ if (result)
+ return_VALUE(result);
+
+ return_VALUE(count);
+}
+
+struct file_operations acpi_processor_throttling_fops = {
+ .open = acpi_processor_throttling_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
diff --git a/drivers/acpi/resources/Makefile b/drivers/acpi/resources/Makefile
new file mode 100644
index 000000000000..2130b74170c3
--- /dev/null
+++ b/drivers/acpi/resources/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := rsaddr.o rscreate.o rsio.o rslist.o rsmisc.o rsxface.o \
+ rscalc.o rsirq.o rsmemory.o rsutils.o
+
+obj-$(ACPI_FUTURE_USAGE) += rsdump.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
new file mode 100644
index 000000000000..4788c079735d
--- /dev/null
+++ b/drivers/acpi/resources/rsaddr.c
@@ -0,0 +1,1225 @@
+/*******************************************************************************
+ *
+ * Module Name: rsaddr - Address resource descriptors (16/32/64)
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsaddr")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_address16_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_address16_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u8 *temp_ptr;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16);
+ u32 index;
+ u16 temp16;
+ u8 temp8;
+
+
+ ACPI_FUNCTION_TRACE ("rs_address16_resource");
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ /* Validate minimum descriptor length */
+
+ if (temp16 < 13) {
+ return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
+ *bytes_consumed = temp16 + 3;
+ output_struct->id = ACPI_RSTYPE_ADDRESS16;
+
+ /*
+ * Get the Resource Type (Byte3)
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ /* Values 0-2 and 0xC0-0xFF are valid */
+
+ if ((temp8 > 2) && (temp8 < 0xC0)) {
+ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
+ }
+
+ output_struct->data.address16.resource_type = temp8;
+
+ /*
+ * Get the General Flags (Byte4)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /* Producer / Consumer */
+
+ output_struct->data.address16.producer_consumer = temp8 & 0x01;
+
+ /* Decode */
+
+ output_struct->data.address16.decode = (temp8 >> 1) & 0x01;
+
+ /* Min Address Fixed */
+
+ output_struct->data.address16.min_address_fixed = (temp8 >> 2) & 0x01;
+
+ /* Max Address Fixed */
+
+ output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01;
+
+ /*
+ * Get the Type Specific Flags (Byte5)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ if (ACPI_MEMORY_RANGE == output_struct->data.address16.resource_type) {
+ output_struct->data.address16.attribute.memory.read_write_attribute =
+ (u16) (temp8 & 0x01);
+ output_struct->data.address16.attribute.memory.cache_attribute =
+ (u16) ((temp8 >> 1) & 0x03);
+ }
+ else {
+ if (ACPI_IO_RANGE == output_struct->data.address16.resource_type) {
+ output_struct->data.address16.attribute.io.range_attribute =
+ (u16) (temp8 & 0x03);
+ output_struct->data.address16.attribute.io.translation_attribute =
+ (u16) ((temp8 >> 4) & 0x03);
+ }
+ else {
+ /* BUS_NUMBER_RANGE == Address16.Data->resource_type */
+ /* Nothing needs to be filled in */
+ }
+ }
+
+ /*
+ * Get Granularity (Bytes 6-7)
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_32 (&output_struct->data.address16.granularity, buffer);
+
+ /*
+ * Get min_address_range (Bytes 8-9)
+ */
+ buffer += 2;
+ ACPI_MOVE_16_TO_32 (&output_struct->data.address16.min_address_range, buffer);
+
+ /*
+ * Get max_address_range (Bytes 10-11)
+ */
+ buffer += 2;
+ ACPI_MOVE_16_TO_32 (&output_struct->data.address16.max_address_range, buffer);
+
+ /*
+ * Get address_translation_offset (Bytes 12-13)
+ */
+ buffer += 2;
+ ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_translation_offset, buffer);
+
+ /*
+ * Get address_length (Bytes 14-15)
+ */
+ buffer += 2;
+ ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_length, buffer);
+
+ /*
+ * Resource Source Index (if present)
+ */
+ buffer += 2;
+
+ /*
+ * This will leave us pointing to the Resource Source Index
+ * If it is present, then save it off and calculate the
+ * pointer to where the null terminated string goes:
+ * Each Interrupt takes 32-bits + the 5 bytes of the
+ * stream that are default.
+ *
+ * Note: Some resource descriptors will have an additional null, so
+ * we add 1 to the length.
+ */
+ if (*bytes_consumed > (16 + 1)) {
+ /* Dereference the Index */
+
+ temp8 = *buffer;
+ output_struct->data.address16.resource_source.index = (u32) temp8;
+
+ /* Point to the String */
+
+ buffer += 1;
+
+ /* Point the String pointer to the end of this structure */
+
+ output_struct->data.address16.resource_source.string_ptr =
+ (char *)((u8 * )output_struct + struct_size);
+
+ temp_ptr = (u8 *) output_struct->data.address16.resource_source.string_ptr;
+
+ /* Copy the string into the buffer */
+
+ index = 0;
+
+ while (0x00 != *buffer) {
+ *temp_ptr = *buffer;
+
+ temp_ptr += 1;
+ buffer += 1;
+ index += 1;
+ }
+
+ /*
+ * Add the terminating null
+ */
+ *temp_ptr = 0x00;
+
+ output_struct->data.address16.resource_source.string_length = index + 1;
+
+ /*
+ * In order for the struct_size to fall on a 32-bit boundary,
+ * calculate the length of the string and expand the
+ * struct_size to the next 32-bit boundary.
+ */
+ temp8 = (u8) (index + 1);
+ struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
+ }
+ else {
+ output_struct->data.address16.resource_source.index = 0x00;
+ output_struct->data.address16.resource_source.string_length = 0;
+ output_struct->data.address16.resource_source.string_ptr = NULL;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_address16_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_address16_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u8 *length_field;
+ u8 temp8;
+ char *temp_pointer = NULL;
+ acpi_size actual_bytes;
+
+
+ ACPI_FUNCTION_TRACE ("rs_address16_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x88;
+ buffer += 1;
+
+ /*
+ * Save a pointer to the Length field - to be filled in later
+ */
+ length_field = buffer;
+ buffer += 2;
+
+ /*
+ * Set the Resource Type (Memory, Io, bus_number)
+ */
+ temp8 = (u8) (linked_list->data.address16.resource_type & 0x03);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the general flags
+ */
+ temp8 = (u8) (linked_list->data.address16.producer_consumer & 0x01);
+
+ temp8 |= (linked_list->data.address16.decode & 0x01) << 1;
+ temp8 |= (linked_list->data.address16.min_address_fixed & 0x01) << 2;
+ temp8 |= (linked_list->data.address16.max_address_fixed & 0x01) << 3;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the type specific flags
+ */
+ temp8 = 0;
+
+ if (ACPI_MEMORY_RANGE == linked_list->data.address16.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address16.attribute.memory.read_write_attribute &
+ 0x01);
+
+ temp8 |=
+ (linked_list->data.address16.attribute.memory.cache_attribute &
+ 0x03) << 1;
+ }
+ else if (ACPI_IO_RANGE == linked_list->data.address16.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address16.attribute.io.range_attribute &
+ 0x03);
+ temp8 |=
+ (linked_list->data.address16.attribute.io.translation_attribute &
+ 0x03) << 4;
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the address space granularity
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.granularity);
+ buffer += 2;
+
+ /*
+ * Set the address range minimum
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.min_address_range);
+ buffer += 2;
+
+ /*
+ * Set the address range maximum
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.max_address_range);
+ buffer += 2;
+
+ /*
+ * Set the address translation offset
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_translation_offset);
+ buffer += 2;
+
+ /*
+ * Set the address length
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_length);
+ buffer += 2;
+
+ /*
+ * Resource Source Index and Resource Source are optional
+ */
+ if (0 != linked_list->data.address16.resource_source.string_length) {
+ temp8 = (u8) linked_list->data.address16.resource_source.index;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ temp_pointer = (char *) buffer;
+
+ /*
+ * Copy the string
+ */
+ ACPI_STRCPY (temp_pointer,
+ linked_list->data.address16.resource_source.string_ptr);
+
+ /*
+ * Buffer needs to be set to the length of the sting + one for the
+ * terminating null
+ */
+ buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address16.resource_source.string_ptr) + 1);
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ actual_bytes = ACPI_PTR_DIFF (buffer, *output_buffer);
+ *bytes_consumed = actual_bytes;
+
+ /*
+ * Set the length field to the number of bytes consumed
+ * minus the header size (3 bytes)
+ */
+ actual_bytes -= 3;
+ ACPI_MOVE_SIZE_TO_16 (length_field, &actual_bytes);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_address32_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_address32_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer;
+ struct acpi_resource *output_struct= (void *) *output_buffer;
+ u16 temp16;
+ u8 temp8;
+ u8 *temp_ptr;
+ acpi_size struct_size;
+ u32 index;
+
+
+ ACPI_FUNCTION_TRACE ("rs_address32_resource");
+
+
+ buffer = byte_stream_buffer;
+ struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32);
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ /* Validate minimum descriptor length */
+
+ if (temp16 < 23) {
+ return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
+ *bytes_consumed = temp16 + 3;
+ output_struct->id = ACPI_RSTYPE_ADDRESS32;
+
+ /*
+ * Get the Resource Type (Byte3)
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ /* Values 0-2 and 0xC0-0xFF are valid */
+
+ if ((temp8 > 2) && (temp8 < 0xC0)) {
+ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
+ }
+
+ output_struct->data.address32.resource_type = temp8;
+
+ /*
+ * Get the General Flags (Byte4)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /*
+ * Producer / Consumer
+ */
+ output_struct->data.address32.producer_consumer = temp8 & 0x01;
+
+ /*
+ * Decode
+ */
+ output_struct->data.address32.decode = (temp8 >> 1) & 0x01;
+
+ /*
+ * Min Address Fixed
+ */
+ output_struct->data.address32.min_address_fixed = (temp8 >> 2) & 0x01;
+
+ /*
+ * Max Address Fixed
+ */
+ output_struct->data.address32.max_address_fixed = (temp8 >> 3) & 0x01;
+
+ /*
+ * Get the Type Specific Flags (Byte5)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ if (ACPI_MEMORY_RANGE == output_struct->data.address32.resource_type) {
+ output_struct->data.address32.attribute.memory.read_write_attribute =
+ (u16) (temp8 & 0x01);
+
+ output_struct->data.address32.attribute.memory.cache_attribute =
+ (u16) ((temp8 >> 1) & 0x03);
+ }
+ else {
+ if (ACPI_IO_RANGE == output_struct->data.address32.resource_type) {
+ output_struct->data.address32.attribute.io.range_attribute =
+ (u16) (temp8 & 0x03);
+ output_struct->data.address32.attribute.io.translation_attribute =
+ (u16) ((temp8 >> 4) & 0x03);
+ }
+ else {
+ /* BUS_NUMBER_RANGE == output_struct->Data.Address32.resource_type */
+ /* Nothing needs to be filled in */
+ }
+ }
+
+ /*
+ * Get Granularity (Bytes 6-9)
+ */
+ buffer += 1;
+ ACPI_MOVE_32_TO_32 (&output_struct->data.address32.granularity, buffer);
+
+ /*
+ * Get min_address_range (Bytes 10-13)
+ */
+ buffer += 4;
+ ACPI_MOVE_32_TO_32 (&output_struct->data.address32.min_address_range, buffer);
+
+ /*
+ * Get max_address_range (Bytes 14-17)
+ */
+ buffer += 4;
+ ACPI_MOVE_32_TO_32 (&output_struct->data.address32.max_address_range, buffer);
+
+ /*
+ * Get address_translation_offset (Bytes 18-21)
+ */
+ buffer += 4;
+ ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_translation_offset, buffer);
+
+ /*
+ * Get address_length (Bytes 22-25)
+ */
+ buffer += 4;
+ ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_length, buffer);
+
+ /*
+ * Resource Source Index (if present)
+ */
+ buffer += 4;
+
+ /*
+ * This will leave us pointing to the Resource Source Index
+ * If it is present, then save it off and calculate the
+ * pointer to where the null terminated string goes:
+ *
+ * Note: Some resource descriptors will have an additional null, so
+ * we add 1 to the length.
+ */
+ if (*bytes_consumed > (26 + 1)) {
+ /* Dereference the Index */
+
+ temp8 = *buffer;
+ output_struct->data.address32.resource_source.index =
+ (u32) temp8;
+
+ /* Point to the String */
+
+ buffer += 1;
+
+ /* Point the String pointer to the end of this structure */
+
+ output_struct->data.address32.resource_source.string_ptr =
+ (char *)((u8 *)output_struct + struct_size);
+
+ temp_ptr = (u8 *) output_struct->data.address32.resource_source.string_ptr;
+
+ /* Copy the string into the buffer */
+
+ index = 0;
+ while (0x00 != *buffer) {
+ *temp_ptr = *buffer;
+
+ temp_ptr += 1;
+ buffer += 1;
+ index += 1;
+ }
+
+ /*
+ * Add the terminating null
+ */
+ *temp_ptr = 0x00;
+ output_struct->data.address32.resource_source.string_length = index + 1;
+
+ /*
+ * In order for the struct_size to fall on a 32-bit boundary,
+ * calculate the length of the string and expand the
+ * struct_size to the next 32-bit boundary.
+ */
+ temp8 = (u8) (index + 1);
+ struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
+ }
+ else {
+ output_struct->data.address32.resource_source.index = 0x00;
+ output_struct->data.address32.resource_source.string_length = 0;
+ output_struct->data.address32.resource_source.string_ptr = NULL;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_address32_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_address32_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer;
+ u16 *length_field;
+ u8 temp8;
+ char *temp_pointer;
+
+
+ ACPI_FUNCTION_TRACE ("rs_address32_stream");
+
+
+ buffer = *output_buffer;
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x87;
+ buffer += 1;
+
+ /*
+ * Set a pointer to the Length field - to be filled in later
+ */
+ length_field = ACPI_CAST_PTR (u16, buffer);
+ buffer += 2;
+
+ /*
+ * Set the Resource Type (Memory, Io, bus_number)
+ */
+ temp8 = (u8) (linked_list->data.address32.resource_type & 0x03);
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the general flags
+ */
+ temp8 = (u8) (linked_list->data.address32.producer_consumer & 0x01);
+ temp8 |= (linked_list->data.address32.decode & 0x01) << 1;
+ temp8 |= (linked_list->data.address32.min_address_fixed & 0x01) << 2;
+ temp8 |= (linked_list->data.address32.max_address_fixed & 0x01) << 3;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the type specific flags
+ */
+ temp8 = 0;
+
+ if (ACPI_MEMORY_RANGE == linked_list->data.address32.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address32.attribute.memory.read_write_attribute &
+ 0x01);
+
+ temp8 |=
+ (linked_list->data.address32.attribute.memory.cache_attribute &
+ 0x03) << 1;
+ }
+ else if (ACPI_IO_RANGE == linked_list->data.address32.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address32.attribute.io.range_attribute &
+ 0x03);
+ temp8 |=
+ (linked_list->data.address32.attribute.io.translation_attribute &
+ 0x03) << 4;
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the address space granularity
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.granularity);
+ buffer += 4;
+
+ /*
+ * Set the address range minimum
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.min_address_range);
+ buffer += 4;
+
+ /*
+ * Set the address range maximum
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.max_address_range);
+ buffer += 4;
+
+ /*
+ * Set the address translation offset
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_translation_offset);
+ buffer += 4;
+
+ /*
+ * Set the address length
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_length);
+ buffer += 4;
+
+ /*
+ * Resource Source Index and Resource Source are optional
+ */
+ if (0 != linked_list->data.address32.resource_source.string_length) {
+ temp8 = (u8) linked_list->data.address32.resource_source.index;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ temp_pointer = (char *) buffer;
+
+ /*
+ * Copy the string
+ */
+ ACPI_STRCPY (temp_pointer,
+ linked_list->data.address32.resource_source.string_ptr);
+
+ /*
+ * Buffer needs to be set to the length of the sting + one for the
+ * terminating null
+ */
+ buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address32.resource_source.string_ptr) + 1);
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+
+ /*
+ * Set the length field to the number of bytes consumed
+ * minus the header size (3 bytes)
+ */
+ *length_field = (u16) (*bytes_consumed - 3);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_address64_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_address64_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16;
+ u8 temp8;
+ u8 resource_type;
+ u8 *temp_ptr;
+ acpi_size struct_size;
+ u32 index;
+
+
+ ACPI_FUNCTION_TRACE ("rs_address64_resource");
+
+
+ buffer = byte_stream_buffer;
+ struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64);
+ resource_type = *buffer;
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ /* Validate minimum descriptor length */
+
+ if (temp16 < 43) {
+ return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
+ *bytes_consumed = temp16 + 3;
+ output_struct->id = ACPI_RSTYPE_ADDRESS64;
+
+ /*
+ * Get the Resource Type (Byte3)
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ /* Values 0-2 and 0xC0-0xFF are valid */
+
+ if ((temp8 > 2) && (temp8 < 0xC0)) {
+ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
+ }
+
+ output_struct->data.address64.resource_type = temp8;
+
+ /*
+ * Get the General Flags (Byte4)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /*
+ * Producer / Consumer
+ */
+ output_struct->data.address64.producer_consumer = temp8 & 0x01;
+
+ /*
+ * Decode
+ */
+ output_struct->data.address64.decode = (temp8 >> 1) & 0x01;
+
+ /*
+ * Min Address Fixed
+ */
+ output_struct->data.address64.min_address_fixed = (temp8 >> 2) & 0x01;
+
+ /*
+ * Max Address Fixed
+ */
+ output_struct->data.address64.max_address_fixed = (temp8 >> 3) & 0x01;
+
+ /*
+ * Get the Type Specific Flags (Byte5)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ if (ACPI_MEMORY_RANGE == output_struct->data.address64.resource_type) {
+ output_struct->data.address64.attribute.memory.read_write_attribute =
+ (u16) (temp8 & 0x01);
+
+ output_struct->data.address64.attribute.memory.cache_attribute =
+ (u16) ((temp8 >> 1) & 0x03);
+ }
+ else {
+ if (ACPI_IO_RANGE == output_struct->data.address64.resource_type) {
+ output_struct->data.address64.attribute.io.range_attribute =
+ (u16) (temp8 & 0x03);
+ output_struct->data.address64.attribute.io.translation_attribute =
+ (u16) ((temp8 >> 4) & 0x03);
+ }
+ else {
+ /* BUS_NUMBER_RANGE == output_struct->Data.Address64.resource_type */
+ /* Nothing needs to be filled in */
+ }
+ }
+
+ if (resource_type == ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE) {
+ /* Move past revision_id and Reserved byte */
+
+ buffer += 2;
+ }
+
+ /*
+ * Get Granularity (Bytes 6-13) or (Bytes 8-15)
+ */
+ buffer += 1;
+ ACPI_MOVE_64_TO_64 (&output_struct->data.address64.granularity, buffer);
+
+ /*
+ * Get min_address_range (Bytes 14-21) or (Bytes 16-23)
+ */
+ buffer += 8;
+ ACPI_MOVE_64_TO_64 (&output_struct->data.address64.min_address_range, buffer);
+
+ /*
+ * Get max_address_range (Bytes 22-29) or (Bytes 24-31)
+ */
+ buffer += 8;
+ ACPI_MOVE_64_TO_64 (&output_struct->data.address64.max_address_range, buffer);
+
+ /*
+ * Get address_translation_offset (Bytes 30-37) or (Bytes 32-39)
+ */
+ buffer += 8;
+ ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset, buffer);
+
+ /*
+ * Get address_length (Bytes 38-45) or (Bytes 40-47)
+ */
+ buffer += 8;
+ ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_length, buffer);
+
+ output_struct->data.address64.resource_source.index = 0x00;
+ output_struct->data.address64.resource_source.string_length = 0;
+ output_struct->data.address64.resource_source.string_ptr = NULL;
+
+ if (resource_type == ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE) {
+ /* Get type_specific_attribute (Bytes 48-55) */
+
+ buffer += 8;
+ ACPI_MOVE_64_TO_64 (&output_struct->data.address64.type_specific_attributes, buffer);
+ }
+ else {
+ output_struct->data.address64.type_specific_attributes = 0;
+
+ /*
+ * Resource Source Index (if present)
+ */
+ buffer += 8;
+
+ /*
+ * This will leave us pointing to the Resource Source Index
+ * If it is present, then save it off and calculate the
+ * pointer to where the null terminated string goes:
+ * Each Interrupt takes 32-bits + the 5 bytes of the
+ * stream that are default.
+ *
+ * Note: Some resource descriptors will have an additional null, so
+ * we add 1 to the length.
+ */
+ if (*bytes_consumed > (46 + 1)) {
+ /* Dereference the Index */
+
+ temp8 = *buffer;
+ output_struct->data.address64.resource_source.index =
+ (u32) temp8;
+
+ /* Point to the String */
+
+ buffer += 1;
+
+ /* Point the String pointer to the end of this structure */
+
+ output_struct->data.address64.resource_source.string_ptr =
+ (char *)((u8 *)output_struct + struct_size);
+
+ temp_ptr = (u8 *) output_struct->data.address64.resource_source.string_ptr;
+
+ /* Copy the string into the buffer */
+
+ index = 0;
+ while (0x00 != *buffer) {
+ *temp_ptr = *buffer;
+
+ temp_ptr += 1;
+ buffer += 1;
+ index += 1;
+ }
+
+ /*
+ * Add the terminating null
+ */
+ *temp_ptr = 0x00;
+ output_struct->data.address64.resource_source.string_length = index + 1;
+
+ /*
+ * In order for the struct_size to fall on a 32-bit boundary,
+ * calculate the length of the string and expand the
+ * struct_size to the next 32-bit boundary.
+ */
+ temp8 = (u8) (index + 1);
+ struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
+ }
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_address64_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_address64_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer;
+ u16 *length_field;
+ u8 temp8;
+ char *temp_pointer;
+
+
+ ACPI_FUNCTION_TRACE ("rs_address64_stream");
+
+
+ buffer = *output_buffer;
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x8A;
+ buffer += 1;
+
+ /*
+ * Set a pointer to the Length field - to be filled in later
+ */
+ length_field = ACPI_CAST_PTR (u16, buffer);
+ buffer += 2;
+
+ /*
+ * Set the Resource Type (Memory, Io, bus_number)
+ */
+ temp8 = (u8) (linked_list->data.address64.resource_type & 0x03);
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the general flags
+ */
+ temp8 = (u8) (linked_list->data.address64.producer_consumer & 0x01);
+ temp8 |= (linked_list->data.address64.decode & 0x01) << 1;
+ temp8 |= (linked_list->data.address64.min_address_fixed & 0x01) << 2;
+ temp8 |= (linked_list->data.address64.max_address_fixed & 0x01) << 3;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the type specific flags
+ */
+ temp8 = 0;
+
+ if (ACPI_MEMORY_RANGE == linked_list->data.address64.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address64.attribute.memory.read_write_attribute &
+ 0x01);
+
+ temp8 |=
+ (linked_list->data.address64.attribute.memory.cache_attribute &
+ 0x03) << 1;
+ }
+ else if (ACPI_IO_RANGE == linked_list->data.address64.resource_type) {
+ temp8 = (u8)
+ (linked_list->data.address64.attribute.io.range_attribute &
+ 0x03);
+ temp8 |=
+ (linked_list->data.address64.attribute.io.range_attribute &
+ 0x03) << 4;
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the address space granularity
+ */
+ ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.granularity);
+ buffer += 8;
+
+ /*
+ * Set the address range minimum
+ */
+ ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.min_address_range);
+ buffer += 8;
+
+ /*
+ * Set the address range maximum
+ */
+ ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.max_address_range);
+ buffer += 8;
+
+ /*
+ * Set the address translation offset
+ */
+ ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_translation_offset);
+ buffer += 8;
+
+ /*
+ * Set the address length
+ */
+ ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_length);
+ buffer += 8;
+
+ /*
+ * Resource Source Index and Resource Source are optional
+ */
+ if (0 != linked_list->data.address64.resource_source.string_length) {
+ temp8 = (u8) linked_list->data.address64.resource_source.index;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ temp_pointer = (char *) buffer;
+
+ /*
+ * Copy the string
+ */
+ ACPI_STRCPY (temp_pointer, linked_list->data.address64.resource_source.string_ptr);
+
+ /*
+ * Buffer needs to be set to the length of the sting + one for the
+ * terminating null
+ */
+ buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1);
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+
+ /*
+ * Set the length field to the number of bytes consumed
+ * minus the header size (3 bytes)
+ */
+ *length_field = (u16) (*bytes_consumed - 3);
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
new file mode 100644
index 000000000000..8a5f0a52371d
--- /dev/null
+++ b/drivers/acpi/resources/rscalc.c
@@ -0,0 +1,841 @@
+/*******************************************************************************
+ *
+ * Module Name: rscalc - Calculate stream and list lengths
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rscalc")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_byte_stream_length
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * size_needed - u32 pointer of the size buffer needed
+ * to properly return the parsed data
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
+ * the size buffer needed to hold the linked list that conveys
+ * the resource data.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_get_byte_stream_length (
+ struct acpi_resource *linked_list,
+ acpi_size *size_needed)
+{
+ acpi_size byte_stream_size_needed = 0;
+ acpi_size segment_size;
+ u8 done = FALSE;
+
+
+ ACPI_FUNCTION_TRACE ("rs_get_byte_stream_length");
+
+
+ while (!done) {
+ /*
+ * Init the variable that will hold the size to add to the total.
+ */
+ segment_size = 0;
+
+ switch (linked_list->id) {
+ case ACPI_RSTYPE_IRQ:
+ /*
+ * IRQ Resource
+ * For an IRQ Resource, Byte 3, although optional, will always be
+ * created - it holds IRQ information.
+ */
+ segment_size = 4;
+ break;
+
+ case ACPI_RSTYPE_DMA:
+ /*
+ * DMA Resource
+ * For this resource the size is static
+ */
+ segment_size = 3;
+ break;
+
+ case ACPI_RSTYPE_START_DPF:
+ /*
+ * Start Dependent Functions Resource
+ * For a start_dependent_functions Resource, Byte 1, although
+ * optional, will always be created.
+ */
+ segment_size = 2;
+ break;
+
+ case ACPI_RSTYPE_END_DPF:
+ /*
+ * End Dependent Functions Resource
+ * For this resource the size is static
+ */
+ segment_size = 1;
+ break;
+
+ case ACPI_RSTYPE_IO:
+ /*
+ * IO Port Resource
+ * For this resource the size is static
+ */
+ segment_size = 8;
+ break;
+
+ case ACPI_RSTYPE_FIXED_IO:
+ /*
+ * Fixed IO Port Resource
+ * For this resource the size is static
+ */
+ segment_size = 4;
+ break;
+
+ case ACPI_RSTYPE_VENDOR:
+ /*
+ * Vendor Defined Resource
+ * For a Vendor Specific resource, if the Length is between 1 and 7
+ * it will be created as a Small Resource data type, otherwise it
+ * is a Large Resource data type.
+ */
+ if (linked_list->data.vendor_specific.length > 7) {
+ segment_size = 3;
+ }
+ else {
+ segment_size = 1;
+ }
+ segment_size += linked_list->data.vendor_specific.length;
+ break;
+
+ case ACPI_RSTYPE_END_TAG:
+ /*
+ * End Tag
+ * For this resource the size is static
+ */
+ segment_size = 2;
+ done = TRUE;
+ break;
+
+ case ACPI_RSTYPE_MEM24:
+ /*
+ * 24-Bit Memory Resource
+ * For this resource the size is static
+ */
+ segment_size = 12;
+ break;
+
+ case ACPI_RSTYPE_MEM32:
+ /*
+ * 32-Bit Memory Range Resource
+ * For this resource the size is static
+ */
+ segment_size = 20;
+ break;
+
+ case ACPI_RSTYPE_FIXED_MEM32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ * For this resource the size is static
+ */
+ segment_size = 12;
+ break;
+
+ case ACPI_RSTYPE_ADDRESS16:
+ /*
+ * 16-Bit Address Resource
+ * The base size of this byte stream is 16. If a Resource Source
+ * string is not NULL, add 1 for the Index + the length of the null
+ * terminated string Resource Source + 1 for the null.
+ */
+ segment_size = 16;
+
+ if (linked_list->data.address16.resource_source.string_ptr) {
+ segment_size += linked_list->data.address16.resource_source.string_length;
+ segment_size++;
+ }
+ break;
+
+ case ACPI_RSTYPE_ADDRESS32:
+ /*
+ * 32-Bit Address Resource
+ * The base size of this byte stream is 26. If a Resource
+ * Source string is not NULL, add 1 for the Index + the
+ * length of the null terminated string Resource Source +
+ * 1 for the null.
+ */
+ segment_size = 26;
+
+ if (linked_list->data.address32.resource_source.string_ptr) {
+ segment_size += linked_list->data.address32.resource_source.string_length;
+ segment_size++;
+ }
+ break;
+
+ case ACPI_RSTYPE_ADDRESS64:
+ /*
+ * 64-Bit Address Resource
+ * The base size of this byte stream is 46. If a resource_source
+ * string is not NULL, add 1 for the Index + the length of the null
+ * terminated string Resource Source + 1 for the null.
+ */
+ segment_size = 46;
+
+ if (linked_list->data.address64.resource_source.string_ptr) {
+ segment_size += linked_list->data.address64.resource_source.string_length;
+ segment_size++;
+ }
+ break;
+
+ case ACPI_RSTYPE_EXT_IRQ:
+ /*
+ * Extended IRQ Resource
+ * The base size of this byte stream is 9. This is for an Interrupt
+ * table length of 1. For each additional interrupt, add 4.
+ * If a Resource Source string is not NULL, add 1 for the
+ * Index + the length of the null terminated string
+ * Resource Source + 1 for the null.
+ */
+ segment_size = 9 +
+ (((acpi_size) linked_list->data.extended_irq.number_of_interrupts - 1) * 4);
+
+ if (linked_list->data.extended_irq.resource_source.string_ptr) {
+ segment_size += linked_list->data.extended_irq.resource_source.string_length;
+ segment_size++;
+ }
+ break;
+
+ default:
+ /*
+ * If we get here, everything is out of sync, exit with error
+ */
+ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
+
+ } /* switch (linked_list->Id) */
+
+ /*
+ * Update the total
+ */
+ byte_stream_size_needed += segment_size;
+
+ /*
+ * Point to the next object
+ */
+ linked_list = ACPI_PTR_ADD (struct acpi_resource,
+ linked_list, linked_list->length);
+ }
+
+ /*
+ * This is the data the caller needs
+ */
+ *size_needed = byte_stream_size_needed;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_list_length
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource byte stream
+ * byte_stream_buffer_length - Size of byte_stream_buffer
+ * size_needed - u32 pointer of the size buffer
+ * needed to properly return the
+ * parsed data
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Takes the resource byte stream and parses it once, calculating
+ * the size buffer needed to hold the linked list that conveys
+ * the resource data.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_get_list_length (
+ u8 *byte_stream_buffer,
+ u32 byte_stream_buffer_length,
+ acpi_size *size_needed)
+{
+ u32 buffer_size = 0;
+ u32 bytes_parsed = 0;
+ u8 number_of_interrupts = 0;
+ u8 number_of_channels = 0;
+ u8 resource_type;
+ u32 structure_size;
+ u32 bytes_consumed;
+ u8 *buffer;
+ u8 temp8;
+ u16 temp16;
+ u8 index;
+ u8 additional_bytes;
+
+
+ ACPI_FUNCTION_TRACE ("rs_get_list_length");
+
+
+ while (bytes_parsed < byte_stream_buffer_length) {
+ /*
+ * The next byte in the stream is the resource type
+ */
+ resource_type = acpi_rs_get_resource_type (*byte_stream_buffer);
+
+ switch (resource_type) {
+ case ACPI_RDESC_TYPE_MEMORY_24:
+ /*
+ * 24-Bit Memory Resource
+ */
+ bytes_consumed = 12;
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem24);
+ break;
+
+
+ case ACPI_RDESC_TYPE_LARGE_VENDOR:
+ /*
+ * Vendor Defined Resource
+ */
+ buffer = byte_stream_buffer;
+ ++buffer;
+
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Ensure a 32-bit boundary for the structure
+ */
+ temp16 = (u16) ACPI_ROUND_UP_to_32_bITS (temp16);
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) +
+ (temp16 * sizeof (u8));
+ break;
+
+
+ case ACPI_RDESC_TYPE_MEMORY_32:
+ /*
+ * 32-Bit Memory Range Resource
+ */
+ bytes_consumed = 20;
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem32);
+ break;
+
+
+ case ACPI_RDESC_TYPE_FIXED_MEMORY_32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ */
+ bytes_consumed = 12;
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_mem32);
+ break;
+
+
+ case ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE:
+ /*
+ * 64-Bit Address Resource
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64);
+ break;
+
+
+ case ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE:
+ /*
+ * 64-Bit Address Resource
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Resource Source Index and Resource Source are optional elements.
+ * Check the length of the Bytestream. If it is greater than 43,
+ * that means that an Index exists and is followed by a null
+ * terminated string. Therefore, set the temp variable to the
+ * length minus the minimum byte stream length plus the byte for
+ * the Index to determine the size of the NULL terminated string.
+ */
+ if (43 < temp16) {
+ temp8 = (u8) (temp16 - 44);
+ }
+ else {
+ temp8 = 0;
+ }
+
+ /*
+ * Ensure a 64-bit boundary for the structure
+ */
+ temp8 = (u8) ACPI_ROUND_UP_to_64_bITS (temp8);
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64) +
+ (temp8 * sizeof (u8));
+ break;
+
+
+ case ACPI_RDESC_TYPE_DWORD_ADDRESS_SPACE:
+ /*
+ * 32-Bit Address Resource
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Resource Source Index and Resource Source are optional elements.
+ * Check the length of the Bytestream. If it is greater than 23,
+ * that means that an Index exists and is followed by a null
+ * terminated string. Therefore, set the temp variable to the
+ * length minus the minimum byte stream length plus the byte for
+ * the Index to determine the size of the NULL terminated string.
+ */
+ if (23 < temp16) {
+ temp8 = (u8) (temp16 - 24);
+ }
+ else {
+ temp8 = 0;
+ }
+
+ /*
+ * Ensure a 32-bit boundary for the structure
+ */
+ temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32) +
+ (temp8 * sizeof (u8));
+ break;
+
+
+ case ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE:
+ /*
+ * 16-Bit Address Resource
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Resource Source Index and Resource Source are optional elements.
+ * Check the length of the Bytestream. If it is greater than 13,
+ * that means that an Index exists and is followed by a null
+ * terminated string. Therefore, set the temp variable to the
+ * length minus the minimum byte stream length plus the byte for
+ * the Index to determine the size of the NULL terminated string.
+ */
+ if (13 < temp16) {
+ temp8 = (u8) (temp16 - 14);
+ }
+ else {
+ temp8 = 0;
+ }
+
+ /*
+ * Ensure a 32-bit boundary for the structure
+ */
+ temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16) +
+ (temp8 * sizeof (u8));
+ break;
+
+
+ case ACPI_RDESC_TYPE_EXTENDED_XRUPT:
+ /*
+ * Extended IRQ
+ */
+ buffer = byte_stream_buffer;
+
+ ++buffer;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ bytes_consumed = temp16 + 3;
+
+ /*
+ * Point past the length field and the Interrupt vector flags to
+ * save off the Interrupt table length to the Temp8 variable.
+ */
+ buffer += 3;
+ temp8 = *buffer;
+
+ /*
+ * To compensate for multiple interrupt numbers, add 4 bytes for
+ * each additional interrupts greater than 1
+ */
+ additional_bytes = (u8) ((temp8 - 1) * 4);
+
+ /*
+ * Resource Source Index and Resource Source are optional elements.
+ * Check the length of the Bytestream. If it is greater than 9,
+ * that means that an Index exists and is followed by a null
+ * terminated string. Therefore, set the temp variable to the
+ * length minus the minimum byte stream length plus the byte for
+ * the Index to determine the size of the NULL terminated string.
+ */
+ if (9 + additional_bytes < temp16) {
+ temp8 = (u8) (temp16 - (9 + additional_bytes));
+ }
+ else {
+ temp8 = 0;
+ }
+
+ /*
+ * Ensure a 32-bit boundary for the structure
+ */
+ temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq) +
+ (additional_bytes * sizeof (u8)) +
+ (temp8 * sizeof (u8));
+ break;
+
+
+ case ACPI_RDESC_TYPE_IRQ_FORMAT:
+ /*
+ * IRQ Resource.
+ * Determine if it there are two or three trailing bytes
+ */
+ buffer = byte_stream_buffer;
+ temp8 = *buffer;
+
+ if(temp8 & 0x01) {
+ bytes_consumed = 4;
+ }
+ else {
+ bytes_consumed = 3;
+ }
+
+ /* Point past the descriptor */
+
+ ++buffer;
+
+ /*
+ * Look at the number of bits set
+ */
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ for (index = 0; index < 16; index++) {
+ if (temp16 & 0x1) {
+ ++number_of_interrupts;
+ }
+
+ temp16 >>= 1;
+ }
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io) +
+ (number_of_interrupts * sizeof (u32));
+ break;
+
+
+ case ACPI_RDESC_TYPE_DMA_FORMAT:
+ /*
+ * DMA Resource
+ */
+ buffer = byte_stream_buffer;
+ bytes_consumed = 3;
+
+ /* Point past the descriptor */
+
+ ++buffer;
+
+ /*
+ * Look at the number of bits set
+ */
+ temp8 = *buffer;
+
+ for(index = 0; index < 8; index++) {
+ if(temp8 & 0x1) {
+ ++number_of_channels;
+ }
+
+ temp8 >>= 1;
+ }
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_dma) +
+ (number_of_channels * sizeof (u32));
+ break;
+
+
+ case ACPI_RDESC_TYPE_START_DEPENDENT:
+ /*
+ * Start Dependent Functions Resource
+ * Determine if it there are two or three trailing bytes
+ */
+ buffer = byte_stream_buffer;
+ temp8 = *buffer;
+
+ if(temp8 & 0x01) {
+ bytes_consumed = 2;
+ }
+ else {
+ bytes_consumed = 1;
+ }
+
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_start_dpf);
+ break;
+
+
+ case ACPI_RDESC_TYPE_END_DEPENDENT:
+ /*
+ * End Dependent Functions Resource
+ */
+ bytes_consumed = 1;
+ structure_size = ACPI_RESOURCE_LENGTH;
+ break;
+
+
+ case ACPI_RDESC_TYPE_IO_PORT:
+ /*
+ * IO Port Resource
+ */
+ bytes_consumed = 8;
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io);
+ break;
+
+
+ case ACPI_RDESC_TYPE_FIXED_IO_PORT:
+ /*
+ * Fixed IO Port Resource
+ */
+ bytes_consumed = 4;
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_io);
+ break;
+
+
+ case ACPI_RDESC_TYPE_SMALL_VENDOR:
+ /*
+ * Vendor Specific Resource
+ */
+ buffer = byte_stream_buffer;
+
+ temp8 = *buffer;
+ temp8 = (u8) (temp8 & 0x7);
+ bytes_consumed = temp8 + 1;
+
+ /*
+ * Ensure a 32-bit boundary for the structure
+ */
+ temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
+ structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) +
+ (temp8 * sizeof (u8));
+ break;
+
+
+ case ACPI_RDESC_TYPE_END_TAG:
+ /*
+ * End Tag
+ */
+ bytes_consumed = 2;
+ structure_size = ACPI_RESOURCE_LENGTH;
+ byte_stream_buffer_length = bytes_parsed;
+ break;
+
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * exit with an error
+ */
+ return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
+ }
+
+ /*
+ * Update the return value and counter
+ */
+ buffer_size += (u32) ACPI_ALIGN_RESOURCE_SIZE (structure_size);
+ bytes_parsed += bytes_consumed;
+
+ /*
+ * Set the byte stream to point to the next resource
+ */
+ byte_stream_buffer += bytes_consumed;
+ }
+
+ /*
+ * This is the data the caller needs
+ */
+ *size_needed = buffer_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_pci_routing_table_length
+ *
+ * PARAMETERS: package_object - Pointer to the package object
+ * buffer_size_needed - u32 pointer of the size buffer
+ * needed to properly return the
+ * parsed data
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Given a package representing a PCI routing table, this
+ * calculates the size of the corresponding linked list of
+ * descriptions.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_get_pci_routing_table_length (
+ union acpi_operand_object *package_object,
+ acpi_size *buffer_size_needed)
+{
+ u32 number_of_elements;
+ acpi_size temp_size_needed = 0;
+ union acpi_operand_object **top_object_list;
+ u32 index;
+ union acpi_operand_object *package_element;
+ union acpi_operand_object **sub_object_list;
+ u8 name_found;
+ u32 table_index;
+
+
+ ACPI_FUNCTION_TRACE ("rs_get_pci_routing_table_length");
+
+
+ number_of_elements = package_object->package.count;
+
+ /*
+ * Calculate the size of the return buffer.
+ * The base size is the number of elements * the sizes of the
+ * structures. Additional space for the strings is added below.
+ * The minus one is to subtract the size of the u8 Source[1]
+ * member because it is added below.
+ *
+ * But each PRT_ENTRY structure has a pointer to a string and
+ * the size of that string must be found.
+ */
+ top_object_list = package_object->package.elements;
+
+ for (index = 0; index < number_of_elements; index++) {
+ /*
+ * Dereference the sub-package
+ */
+ package_element = *top_object_list;
+
+ /*
+ * The sub_object_list will now point to an array of the
+ * four IRQ elements: Address, Pin, Source and source_index
+ */
+ sub_object_list = package_element->package.elements;
+
+ /*
+ * Scan the irq_table_elements for the Source Name String
+ */
+ name_found = FALSE;
+
+ for (table_index = 0; table_index < 4 && !name_found; table_index++) {
+ if ((ACPI_TYPE_STRING == ACPI_GET_OBJECT_TYPE (*sub_object_list)) ||
+ ((ACPI_TYPE_LOCAL_REFERENCE == ACPI_GET_OBJECT_TYPE (*sub_object_list)) &&
+ ((*sub_object_list)->reference.opcode == AML_INT_NAMEPATH_OP))) {
+ name_found = TRUE;
+ }
+ else {
+ /*
+ * Look at the next element
+ */
+ sub_object_list++;
+ }
+ }
+
+ temp_size_needed += (sizeof (struct acpi_pci_routing_table) - 4);
+
+ /*
+ * Was a String type found?
+ */
+ if (name_found) {
+ if (ACPI_GET_OBJECT_TYPE (*sub_object_list) == ACPI_TYPE_STRING) {
+ /*
+ * The length String.Length field does not include the
+ * terminating NULL, add 1
+ */
+ temp_size_needed += ((acpi_size) (*sub_object_list)->string.length + 1);
+ }
+ else {
+ temp_size_needed += acpi_ns_get_pathname_length (
+ (*sub_object_list)->reference.node);
+ }
+ }
+ else {
+ /*
+ * If no name was found, then this is a NULL, which is
+ * translated as a u32 zero.
+ */
+ temp_size_needed += sizeof (u32);
+ }
+
+ /* Round up the size since each element must be aligned */
+
+ temp_size_needed = ACPI_ROUND_UP_to_64_bITS (temp_size_needed);
+
+ /*
+ * Point to the next union acpi_operand_object
+ */
+ top_object_list++;
+ }
+
+ /*
+ * Adding an extra element to the end of the list, essentially a NULL terminator
+ */
+ *buffer_size_needed = temp_size_needed + sizeof (struct acpi_pci_routing_table);
+ return_ACPI_STATUS (AE_OK);
+}
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
new file mode 100644
index 000000000000..a3a0cbfda68d
--- /dev/null
+++ b/drivers/acpi/resources/rscreate.c
@@ -0,0 +1,428 @@
+/*******************************************************************************
+ *
+ * Module Name: rscreate - Create resource lists/tables
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+#include <acpi/amlcode.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rscreate")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_create_resource_list
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource byte stream
+ * output_buffer - Pointer to the user's buffer
+ *
+ * RETURN: Status - AE_OK if okay, else a valid acpi_status code
+ * If output_buffer is not large enough, output_buffer_length
+ * indicates how large output_buffer should be, else it
+ * indicates how may u8 elements of output_buffer are valid.
+ *
+ * DESCRIPTION: Takes the byte stream returned from a _CRS, _PRS control method
+ * execution and parses the stream to create a linked list
+ * of device resources.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_create_resource_list (
+ union acpi_operand_object *byte_stream_buffer,
+ struct acpi_buffer *output_buffer)
+{
+
+ acpi_status status;
+ u8 *byte_stream_start;
+ acpi_size list_size_needed = 0;
+ u32 byte_stream_buffer_length;
+
+
+ ACPI_FUNCTION_TRACE ("rs_create_resource_list");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "byte_stream_buffer = %p\n",
+ byte_stream_buffer));
+
+ /*
+ * Params already validated, so we don't re-validate here
+ */
+ byte_stream_buffer_length = byte_stream_buffer->buffer.length;
+ byte_stream_start = byte_stream_buffer->buffer.pointer;
+
+ /*
+ * Pass the byte_stream_buffer into a module that can calculate
+ * the buffer size needed for the linked list
+ */
+ status = acpi_rs_get_list_length (byte_stream_start, byte_stream_buffer_length,
+ &list_size_needed);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Status=%X list_size_needed=%X\n",
+ status, (u32) list_size_needed));
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (output_buffer, list_size_needed);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Do the conversion */
+
+ status = acpi_rs_byte_stream_to_list (byte_stream_start, byte_stream_buffer_length,
+ output_buffer->pointer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "output_buffer %p Length %X\n",
+ output_buffer->pointer, (u32) output_buffer->length));
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_create_pci_routing_table
+ *
+ * PARAMETERS: package_object - Pointer to an union acpi_operand_object
+ * package
+ * output_buffer - Pointer to the user's buffer
+ *
+ * RETURN: Status AE_OK if okay, else a valid acpi_status code.
+ * If the output_buffer is too small, the error will be
+ * AE_BUFFER_OVERFLOW and output_buffer->Length will point
+ * to the size buffer needed.
+ *
+ * DESCRIPTION: Takes the union acpi_operand_object package and creates a
+ * linked list of PCI interrupt descriptions
+ *
+ * NOTE: It is the caller's responsibility to ensure that the start of the
+ * output buffer is aligned properly (if necessary).
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_create_pci_routing_table (
+ union acpi_operand_object *package_object,
+ struct acpi_buffer *output_buffer)
+{
+ u8 *buffer;
+ union acpi_operand_object **top_object_list;
+ union acpi_operand_object **sub_object_list;
+ union acpi_operand_object *obj_desc;
+ acpi_size buffer_size_needed = 0;
+ u32 number_of_elements;
+ u32 index;
+ struct acpi_pci_routing_table *user_prt;
+ struct acpi_namespace_node *node;
+ acpi_status status;
+ struct acpi_buffer path_buffer;
+
+
+ ACPI_FUNCTION_TRACE ("rs_create_pci_routing_table");
+
+
+ /* Params already validated, so we don't re-validate here */
+
+ /*
+ * Get the required buffer length
+ */
+ status = acpi_rs_get_pci_routing_table_length (package_object,
+ &buffer_size_needed);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "buffer_size_needed = %X\n",
+ (u32) buffer_size_needed));
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (output_buffer, buffer_size_needed);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Loop through the ACPI_INTERNAL_OBJECTS - Each object
+ * should be a package that in turn contains an
+ * acpi_integer Address, a u8 Pin, a Name and a u8 source_index.
+ */
+ top_object_list = package_object->package.elements;
+ number_of_elements = package_object->package.count;
+ buffer = output_buffer->pointer;
+ user_prt = ACPI_CAST_PTR (struct acpi_pci_routing_table, buffer);
+
+ for (index = 0; index < number_of_elements; index++) {
+ /*
+ * Point user_prt past this current structure
+ *
+ * NOTE: On the first iteration, user_prt->Length will
+ * be zero because we cleared the return buffer earlier
+ */
+ buffer += user_prt->length;
+ user_prt = ACPI_CAST_PTR (struct acpi_pci_routing_table, buffer);
+
+ /*
+ * Fill in the Length field with the information we have at this point.
+ * The minus four is to subtract the size of the u8 Source[4] member
+ * because it is added below.
+ */
+ user_prt->length = (sizeof (struct acpi_pci_routing_table) - 4);
+
+ /*
+ * Each element of the top-level package must also be a package
+ */
+ if (ACPI_GET_OBJECT_TYPE (*top_object_list) != ACPI_TYPE_PACKAGE) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(PRT[%X]) Need sub-package, found %s\n",
+ index, acpi_ut_get_object_type_name (*top_object_list)));
+ return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
+ }
+
+ /* Each sub-package must be of length 4 */
+
+ if ((*top_object_list)->package.count != 4) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(PRT[%X]) Need package of length 4, found length %d\n",
+ index, (*top_object_list)->package.count));
+ return_ACPI_STATUS (AE_AML_PACKAGE_LIMIT);
+ }
+
+ /*
+ * Dereference the sub-package.
+ * The sub_object_list will now point to an array of the four IRQ
+ * elements: [Address, Pin, Source, source_index]
+ */
+ sub_object_list = (*top_object_list)->package.elements;
+
+ /*
+ * 1) First subobject: Dereference the PRT.Address
+ */
+ obj_desc = sub_object_list[0];
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ user_prt->address = obj_desc->integer.value;
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(PRT[%X].Address) Need Integer, found %s\n",
+ index, acpi_ut_get_object_type_name (obj_desc)));
+ return_ACPI_STATUS (AE_BAD_DATA);
+ }
+
+ /*
+ * 2) Second subobject: Dereference the PRT.Pin
+ */
+ obj_desc = sub_object_list[1];
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ user_prt->pin = (u32) obj_desc->integer.value;
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(PRT[%X].Pin) Need Integer, found %s\n",
+ index, acpi_ut_get_object_type_name (obj_desc)));
+ return_ACPI_STATUS (AE_BAD_DATA);
+ }
+
+ /*
+ * 3) Third subobject: Dereference the PRT.source_name
+ */
+ obj_desc = sub_object_list[2];
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ if (obj_desc->reference.opcode != AML_INT_NAMEPATH_OP) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(PRT[%X].Source) Need name, found reference op %X\n",
+ index, obj_desc->reference.opcode));
+ return_ACPI_STATUS (AE_BAD_DATA);
+ }
+
+ node = obj_desc->reference.node;
+
+ /* Use *remaining* length of the buffer as max for pathname */
+
+ path_buffer.length = output_buffer->length -
+ (u32) ((u8 *) user_prt->source -
+ (u8 *) output_buffer->pointer);
+ path_buffer.pointer = user_prt->source;
+
+ status = acpi_ns_handle_to_pathname ((acpi_handle) node, &path_buffer);
+
+ user_prt->length += (u32) ACPI_STRLEN (user_prt->source) + 1; /* include null terminator */
+ break;
+
+
+ case ACPI_TYPE_STRING:
+
+ ACPI_STRCPY (user_prt->source, obj_desc->string.pointer);
+
+ /* Add to the Length field the length of the string (add 1 for terminator) */
+
+ user_prt->length += obj_desc->string.length + 1;
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+ /*
+ * If this is a number, then the Source Name is NULL, since the
+ * entire buffer was zeroed out, we can leave this alone.
+ *
+ * Add to the Length field the length of the u32 NULL
+ */
+ user_prt->length += sizeof (u32);
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(PRT[%X].Source) Need Ref/String/Integer, found %s\n",
+ index, acpi_ut_get_object_type_name (obj_desc)));
+ return_ACPI_STATUS (AE_BAD_DATA);
+ }
+
+ /* Now align the current length */
+
+ user_prt->length = (u32) ACPI_ROUND_UP_to_64_bITS (user_prt->length);
+
+ /*
+ * 4) Fourth subobject: Dereference the PRT.source_index
+ */
+ obj_desc = sub_object_list[3];
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ user_prt->source_index = (u32) obj_desc->integer.value;
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(PRT[%X].source_index) Need Integer, found %s\n",
+ index, acpi_ut_get_object_type_name (obj_desc)));
+ return_ACPI_STATUS (AE_BAD_DATA);
+ }
+
+ /* Point to the next union acpi_operand_object in the top level package */
+
+ top_object_list++;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "output_buffer %p Length %X\n",
+ output_buffer->pointer, (u32) output_buffer->length));
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_create_byte_stream
+ *
+ * PARAMETERS: linked_list_buffer - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's buffer
+ *
+ * RETURN: Status AE_OK if okay, else a valid acpi_status code.
+ * If the output_buffer is too small, the error will be
+ * AE_BUFFER_OVERFLOW and output_buffer->Length will point
+ * to the size buffer needed.
+ *
+ * DESCRIPTION: Takes the linked list of device resources and
+ * creates a bytestream to be used as input for the
+ * _SRS control method.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_create_byte_stream (
+ struct acpi_resource *linked_list_buffer,
+ struct acpi_buffer *output_buffer)
+{
+ acpi_status status;
+ acpi_size byte_stream_size_needed = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_create_byte_stream");
+
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "linked_list_buffer = %p\n",
+ linked_list_buffer));
+
+ /*
+ * Params already validated, so we don't re-validate here
+ *
+ * Pass the linked_list_buffer into a module that calculates
+ * the buffer size needed for the byte stream.
+ */
+ status = acpi_rs_get_byte_stream_length (linked_list_buffer,
+ &byte_stream_size_needed);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "byte_stream_size_needed=%X, %s\n",
+ (u32) byte_stream_size_needed, acpi_format_exception (status)));
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (output_buffer, byte_stream_size_needed);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Do the conversion */
+
+ status = acpi_rs_list_to_byte_stream (linked_list_buffer, byte_stream_size_needed,
+ output_buffer->pointer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "output_buffer %p Length %X\n",
+ output_buffer->pointer, (u32) output_buffer->length));
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
new file mode 100644
index 000000000000..eef1b1f2c685
--- /dev/null
+++ b/drivers/acpi/resources/rsdump.c
@@ -0,0 +1,1150 @@
+/*******************************************************************************
+ *
+ * Module Name: rsdump - Functions to display the resource structures.
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsdump")
+
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_irq
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_irq (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_irq *irq_data = (struct acpi_resource_irq *) data;
+ u8 index = 0;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("IRQ Resource\n");
+
+ acpi_os_printf (" %s Triggered\n",
+ ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge");
+
+ acpi_os_printf (" Active %s\n",
+ ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High");
+
+ acpi_os_printf (" %s\n",
+ ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive");
+
+ acpi_os_printf (" %X Interrupts ( ", irq_data->number_of_interrupts);
+
+ for (index = 0; index < irq_data->number_of_interrupts; index++) {
+ acpi_os_printf ("%X ", irq_data->interrupts[index]);
+ }
+
+ acpi_os_printf (")\n");
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_dma
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_dma (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_dma *dma_data = (struct acpi_resource_dma *) data;
+ u8 index = 0;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("DMA Resource\n");
+
+ switch (dma_data->type) {
+ case ACPI_COMPATIBILITY:
+ acpi_os_printf (" Compatibility mode\n");
+ break;
+
+ case ACPI_TYPE_A:
+ acpi_os_printf (" Type A\n");
+ break;
+
+ case ACPI_TYPE_B:
+ acpi_os_printf (" Type B\n");
+ break;
+
+ case ACPI_TYPE_F:
+ acpi_os_printf (" Type F\n");
+ break;
+
+ default:
+ acpi_os_printf (" Invalid DMA type\n");
+ break;
+ }
+
+ acpi_os_printf (" %sBus Master\n",
+ ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a ");
+
+
+ switch (dma_data->transfer) {
+ case ACPI_TRANSFER_8:
+ acpi_os_printf (" 8-bit only transfer\n");
+ break;
+
+ case ACPI_TRANSFER_8_16:
+ acpi_os_printf (" 8 and 16-bit transfer\n");
+ break;
+
+ case ACPI_TRANSFER_16:
+ acpi_os_printf (" 16 bit only transfer\n");
+ break;
+
+ default:
+ acpi_os_printf (" Invalid transfer preference\n");
+ break;
+ }
+
+ acpi_os_printf (" Number of Channels: %X ( ", dma_data->number_of_channels);
+
+ for (index = 0; index < dma_data->number_of_channels; index++) {
+ acpi_os_printf ("%X ", dma_data->channels[index]);
+ }
+
+ acpi_os_printf (")\n");
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_start_depend_fns
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_start_depend_fns (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_start_dpf *sdf_data = (struct acpi_resource_start_dpf *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("Start Dependent Functions Resource\n");
+
+ switch (sdf_data->compatibility_priority) {
+ case ACPI_GOOD_CONFIGURATION:
+ acpi_os_printf (" Good configuration\n");
+ break;
+
+ case ACPI_ACCEPTABLE_CONFIGURATION:
+ acpi_os_printf (" Acceptable configuration\n");
+ break;
+
+ case ACPI_SUB_OPTIMAL_CONFIGURATION:
+ acpi_os_printf (" Sub-optimal configuration\n");
+ break;
+
+ default:
+ acpi_os_printf (" Invalid compatibility priority\n");
+ break;
+ }
+
+ switch(sdf_data->performance_robustness) {
+ case ACPI_GOOD_CONFIGURATION:
+ acpi_os_printf (" Good configuration\n");
+ break;
+
+ case ACPI_ACCEPTABLE_CONFIGURATION:
+ acpi_os_printf (" Acceptable configuration\n");
+ break;
+
+ case ACPI_SUB_OPTIMAL_CONFIGURATION:
+ acpi_os_printf (" Sub-optimal configuration\n");
+ break;
+
+ default:
+ acpi_os_printf (" Invalid performance "
+ "robustness preference\n");
+ break;
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_io
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_io (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_io *io_data = (struct acpi_resource_io *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("Io Resource\n");
+
+ acpi_os_printf (" %d bit decode\n",
+ ACPI_DECODE_16 == io_data->io_decode ? 16 : 10);
+
+ acpi_os_printf (" Range minimum base: %08X\n",
+ io_data->min_base_address);
+
+ acpi_os_printf (" Range maximum base: %08X\n",
+ io_data->max_base_address);
+
+ acpi_os_printf (" Alignment: %08X\n",
+ io_data->alignment);
+
+ acpi_os_printf (" Range Length: %08X\n",
+ io_data->range_length);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_fixed_io
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_fixed_io (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_fixed_io *fixed_io_data = (struct acpi_resource_fixed_io *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("Fixed Io Resource\n");
+ acpi_os_printf (" Range base address: %08X",
+ fixed_io_data->base_address);
+
+ acpi_os_printf (" Range length: %08X",
+ fixed_io_data->range_length);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_vendor_specific
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_vendor_specific (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_vendor *vendor_data = (struct acpi_resource_vendor *) data;
+ u16 index = 0;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("Vendor Specific Resource\n");
+
+ acpi_os_printf (" Length: %08X\n", vendor_data->length);
+
+ for (index = 0; index < vendor_data->length; index++) {
+ acpi_os_printf (" Byte %X: %08X\n",
+ index, vendor_data->reserved[index]);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_memory24
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_memory24 (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_mem24 *memory24_data = (struct acpi_resource_mem24 *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("24-Bit Memory Range Resource\n");
+
+ acpi_os_printf (" Read%s\n",
+ ACPI_READ_WRITE_MEMORY ==
+ memory24_data->read_write_attribute ?
+ "/Write" : " only");
+
+ acpi_os_printf (" Range minimum base: %08X\n",
+ memory24_data->min_base_address);
+
+ acpi_os_printf (" Range maximum base: %08X\n",
+ memory24_data->max_base_address);
+
+ acpi_os_printf (" Alignment: %08X\n",
+ memory24_data->alignment);
+
+ acpi_os_printf (" Range length: %08X\n",
+ memory24_data->range_length);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_memory32
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_memory32 (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_mem32 *memory32_data = (struct acpi_resource_mem32 *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("32-Bit Memory Range Resource\n");
+
+ acpi_os_printf (" Read%s\n",
+ ACPI_READ_WRITE_MEMORY ==
+ memory32_data->read_write_attribute ?
+ "/Write" : " only");
+
+ acpi_os_printf (" Range minimum base: %08X\n",
+ memory32_data->min_base_address);
+
+ acpi_os_printf (" Range maximum base: %08X\n",
+ memory32_data->max_base_address);
+
+ acpi_os_printf (" Alignment: %08X\n",
+ memory32_data->alignment);
+
+ acpi_os_printf (" Range length: %08X\n",
+ memory32_data->range_length);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_fixed_memory32
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_fixed_memory32 (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_fixed_mem32 *fixed_memory32_data = (struct acpi_resource_fixed_mem32 *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("32-Bit Fixed Location Memory Range Resource\n");
+
+ acpi_os_printf (" Read%s\n",
+ ACPI_READ_WRITE_MEMORY ==
+ fixed_memory32_data->read_write_attribute ?
+ "/Write" : " Only");
+
+ acpi_os_printf (" Range base address: %08X\n",
+ fixed_memory32_data->range_base_address);
+
+ acpi_os_printf (" Range length: %08X\n",
+ fixed_memory32_data->range_length);
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_address16
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_address16 (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_address16 *address16_data = (struct acpi_resource_address16 *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("16-Bit Address Space Resource\n");
+ acpi_os_printf (" Resource Type: ");
+
+ switch (address16_data->resource_type) {
+ case ACPI_MEMORY_RANGE:
+
+ acpi_os_printf ("Memory Range\n");
+
+ switch (address16_data->attribute.memory.cache_attribute) {
+ case ACPI_NON_CACHEABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Noncacheable memory\n");
+ break;
+
+ case ACPI_CACHABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Cacheable memory\n");
+ break;
+
+ case ACPI_WRITE_COMBINING_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Write-combining memory\n");
+ break;
+
+ case ACPI_PREFETCHABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Prefetchable memory\n");
+ break;
+
+ default:
+ acpi_os_printf (" Type Specific: "
+ "Invalid cache attribute\n");
+ break;
+ }
+
+ acpi_os_printf (" Type Specific: Read%s\n",
+ ACPI_READ_WRITE_MEMORY ==
+ address16_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
+ break;
+
+ case ACPI_IO_RANGE:
+
+ acpi_os_printf ("I/O Range\n");
+
+ switch (address16_data->attribute.io.range_attribute) {
+ case ACPI_NON_ISA_ONLY_RANGES:
+ acpi_os_printf (" Type Specific: "
+ "Non-ISA Io Addresses\n");
+ break;
+
+ case ACPI_ISA_ONLY_RANGES:
+ acpi_os_printf (" Type Specific: "
+ "ISA Io Addresses\n");
+ break;
+
+ case ACPI_ENTIRE_RANGE:
+ acpi_os_printf (" Type Specific: "
+ "ISA and non-ISA Io Addresses\n");
+ break;
+
+ default:
+ acpi_os_printf (" Type Specific: "
+ "Invalid range attribute\n");
+ break;
+ }
+
+ acpi_os_printf (" Type Specific: %s Translation\n",
+ ACPI_SPARSE_TRANSLATION ==
+ address16_data->attribute.io.translation_attribute ?
+ "Sparse" : "Dense");
+ break;
+
+ case ACPI_BUS_NUMBER_RANGE:
+
+ acpi_os_printf ("Bus Number Range\n");
+ break;
+
+ default:
+
+ acpi_os_printf ("0x%2.2X\n", address16_data->resource_type);
+ break;
+ }
+
+ acpi_os_printf (" Resource %s\n",
+ ACPI_CONSUMER == address16_data->producer_consumer ?
+ "Consumer" : "Producer");
+
+ acpi_os_printf (" %s decode\n",
+ ACPI_SUB_DECODE == address16_data->decode ?
+ "Subtractive" : "Positive");
+
+ acpi_os_printf (" Min address is %s fixed\n",
+ ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ?
+ "" : "not");
+
+ acpi_os_printf (" Max address is %s fixed\n",
+ ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ?
+ "" : "not");
+
+ acpi_os_printf (" Granularity: %08X\n",
+ address16_data->granularity);
+
+ acpi_os_printf (" Address range min: %08X\n",
+ address16_data->min_address_range);
+
+ acpi_os_printf (" Address range max: %08X\n",
+ address16_data->max_address_range);
+
+ acpi_os_printf (" Address translation offset: %08X\n",
+ address16_data->address_translation_offset);
+
+ acpi_os_printf (" Address Length: %08X\n",
+ address16_data->address_length);
+
+ if (0xFF != address16_data->resource_source.index) {
+ acpi_os_printf (" Resource Source Index: %X\n",
+ address16_data->resource_source.index);
+ acpi_os_printf (" Resource Source: %s\n",
+ address16_data->resource_source.string_ptr);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_address32
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_address32 (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_address32 *address32_data = (struct acpi_resource_address32 *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("32-Bit Address Space Resource\n");
+
+ switch (address32_data->resource_type) {
+ case ACPI_MEMORY_RANGE:
+
+ acpi_os_printf (" Resource Type: Memory Range\n");
+
+ switch (address32_data->attribute.memory.cache_attribute) {
+ case ACPI_NON_CACHEABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Noncacheable memory\n");
+ break;
+
+ case ACPI_CACHABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Cacheable memory\n");
+ break;
+
+ case ACPI_WRITE_COMBINING_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Write-combining memory\n");
+ break;
+
+ case ACPI_PREFETCHABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Prefetchable memory\n");
+ break;
+
+ default:
+ acpi_os_printf (" Type Specific: "
+ "Invalid cache attribute\n");
+ break;
+ }
+
+ acpi_os_printf (" Type Specific: Read%s\n",
+ ACPI_READ_WRITE_MEMORY ==
+ address32_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
+ break;
+
+ case ACPI_IO_RANGE:
+
+ acpi_os_printf (" Resource Type: Io Range\n");
+
+ switch (address32_data->attribute.io.range_attribute) {
+ case ACPI_NON_ISA_ONLY_RANGES:
+ acpi_os_printf (" Type Specific: "
+ "Non-ISA Io Addresses\n");
+ break;
+
+ case ACPI_ISA_ONLY_RANGES:
+ acpi_os_printf (" Type Specific: "
+ "ISA Io Addresses\n");
+ break;
+
+ case ACPI_ENTIRE_RANGE:
+ acpi_os_printf (" Type Specific: "
+ "ISA and non-ISA Io Addresses\n");
+ break;
+
+ default:
+ acpi_os_printf (" Type Specific: "
+ "Invalid Range attribute");
+ break;
+ }
+
+ acpi_os_printf (" Type Specific: %s Translation\n",
+ ACPI_SPARSE_TRANSLATION ==
+ address32_data->attribute.io.translation_attribute ?
+ "Sparse" : "Dense");
+ break;
+
+ case ACPI_BUS_NUMBER_RANGE:
+
+ acpi_os_printf (" Resource Type: Bus Number Range\n");
+ break;
+
+ default:
+
+ acpi_os_printf (" Resource Type: 0x%2.2X\n", address32_data->resource_type);
+ break;
+ }
+
+ acpi_os_printf (" Resource %s\n",
+ ACPI_CONSUMER == address32_data->producer_consumer ?
+ "Consumer" : "Producer");
+
+ acpi_os_printf (" %s decode\n",
+ ACPI_SUB_DECODE == address32_data->decode ?
+ "Subtractive" : "Positive");
+
+ acpi_os_printf (" Min address is %s fixed\n",
+ ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ?
+ "" : "not ");
+
+ acpi_os_printf (" Max address is %s fixed\n",
+ ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ?
+ "" : "not ");
+
+ acpi_os_printf (" Granularity: %08X\n",
+ address32_data->granularity);
+
+ acpi_os_printf (" Address range min: %08X\n",
+ address32_data->min_address_range);
+
+ acpi_os_printf (" Address range max: %08X\n",
+ address32_data->max_address_range);
+
+ acpi_os_printf (" Address translation offset: %08X\n",
+ address32_data->address_translation_offset);
+
+ acpi_os_printf (" Address Length: %08X\n",
+ address32_data->address_length);
+
+ if(0xFF != address32_data->resource_source.index) {
+ acpi_os_printf (" Resource Source Index: %X\n",
+ address32_data->resource_source.index);
+ acpi_os_printf (" Resource Source: %s\n",
+ address32_data->resource_source.string_ptr);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_address64
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_address64 (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_address64 *address64_data = (struct acpi_resource_address64 *) data;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("64-Bit Address Space Resource\n");
+
+ switch (address64_data->resource_type) {
+ case ACPI_MEMORY_RANGE:
+
+ acpi_os_printf (" Resource Type: Memory Range\n");
+
+ switch (address64_data->attribute.memory.cache_attribute) {
+ case ACPI_NON_CACHEABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Noncacheable memory\n");
+ break;
+
+ case ACPI_CACHABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Cacheable memory\n");
+ break;
+
+ case ACPI_WRITE_COMBINING_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Write-combining memory\n");
+ break;
+
+ case ACPI_PREFETCHABLE_MEMORY:
+ acpi_os_printf (" Type Specific: "
+ "Prefetchable memory\n");
+ break;
+
+ default:
+ acpi_os_printf (" Type Specific: "
+ "Invalid cache attribute\n");
+ break;
+ }
+
+ acpi_os_printf (" Type Specific: Read%s\n",
+ ACPI_READ_WRITE_MEMORY ==
+ address64_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
+ break;
+
+ case ACPI_IO_RANGE:
+
+ acpi_os_printf (" Resource Type: Io Range\n");
+
+ switch (address64_data->attribute.io.range_attribute) {
+ case ACPI_NON_ISA_ONLY_RANGES:
+ acpi_os_printf (" Type Specific: "
+ "Non-ISA Io Addresses\n");
+ break;
+
+ case ACPI_ISA_ONLY_RANGES:
+ acpi_os_printf (" Type Specific: "
+ "ISA Io Addresses\n");
+ break;
+
+ case ACPI_ENTIRE_RANGE:
+ acpi_os_printf (" Type Specific: "
+ "ISA and non-ISA Io Addresses\n");
+ break;
+
+ default:
+ acpi_os_printf (" Type Specific: "
+ "Invalid Range attribute");
+ break;
+ }
+
+ acpi_os_printf (" Type Specific: %s Translation\n",
+ ACPI_SPARSE_TRANSLATION ==
+ address64_data->attribute.io.translation_attribute ?
+ "Sparse" : "Dense");
+ break;
+
+ case ACPI_BUS_NUMBER_RANGE:
+
+ acpi_os_printf (" Resource Type: Bus Number Range\n");
+ break;
+
+ default:
+
+ acpi_os_printf (" Resource Type: 0x%2.2X\n", address64_data->resource_type);
+ break;
+ }
+
+ acpi_os_printf (" Resource %s\n",
+ ACPI_CONSUMER == address64_data->producer_consumer ?
+ "Consumer" : "Producer");
+
+ acpi_os_printf (" %s decode\n",
+ ACPI_SUB_DECODE == address64_data->decode ?
+ "Subtractive" : "Positive");
+
+ acpi_os_printf (" Min address is %s fixed\n",
+ ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ?
+ "" : "not ");
+
+ acpi_os_printf (" Max address is %s fixed\n",
+ ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ?
+ "" : "not ");
+
+ acpi_os_printf (" Granularity: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (address64_data->granularity));
+
+ acpi_os_printf (" Address range min: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (address64_data->min_address_range));
+
+ acpi_os_printf (" Address range max: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (address64_data->max_address_range));
+
+ acpi_os_printf (" Address translation offset: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (address64_data->address_translation_offset));
+
+ acpi_os_printf (" Address Length: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (address64_data->address_length));
+
+ acpi_os_printf (" Type Specific Attributes: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes));
+
+ if (0xFF != address64_data->resource_source.index) {
+ acpi_os_printf (" Resource Source Index: %X\n",
+ address64_data->resource_source.index);
+ acpi_os_printf (" Resource Source: %s\n",
+ address64_data->resource_source.string_ptr);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_extended_irq
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Prints out the various members of the Data structure type.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_extended_irq (
+ union acpi_resource_data *data)
+{
+ struct acpi_resource_ext_irq *ext_irq_data = (struct acpi_resource_ext_irq *) data;
+ u8 index = 0;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ acpi_os_printf ("Extended IRQ Resource\n");
+
+ acpi_os_printf (" Resource %s\n",
+ ACPI_CONSUMER == ext_irq_data->producer_consumer ?
+ "Consumer" : "Producer");
+
+ acpi_os_printf (" %s\n",
+ ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ?
+ "Level" : "Edge");
+
+ acpi_os_printf (" Active %s\n",
+ ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ?
+ "low" : "high");
+
+ acpi_os_printf (" %s\n",
+ ACPI_SHARED == ext_irq_data->shared_exclusive ?
+ "Shared" : "Exclusive");
+
+ acpi_os_printf (" Interrupts : %X ( ",
+ ext_irq_data->number_of_interrupts);
+
+ for (index = 0; index < ext_irq_data->number_of_interrupts; index++) {
+ acpi_os_printf ("%X ", ext_irq_data->interrupts[index]);
+ }
+
+ acpi_os_printf (")\n");
+
+ if(0xFF != ext_irq_data->resource_source.index) {
+ acpi_os_printf (" Resource Source Index: %X",
+ ext_irq_data->resource_source.index);
+ acpi_os_printf (" Resource Source: %s",
+ ext_irq_data->resource_source.string_ptr);
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_resource_list
+ *
+ * PARAMETERS: Data - pointer to the resource structure to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Dispatches the structure to the correct dump routine.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_resource_list (
+ struct acpi_resource *resource)
+{
+ u8 count = 0;
+ u8 done = FALSE;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (acpi_dbg_level & ACPI_LV_RESOURCES && _COMPONENT & acpi_dbg_layer) {
+ while (!done) {
+ acpi_os_printf ("Resource structure %X.\n", count++);
+
+ switch (resource->id) {
+ case ACPI_RSTYPE_IRQ:
+ acpi_rs_dump_irq (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_DMA:
+ acpi_rs_dump_dma (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_START_DPF:
+ acpi_rs_dump_start_depend_fns (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_END_DPF:
+ acpi_os_printf ("end_dependent_functions Resource\n");
+ /* acpi_rs_dump_end_dependent_functions (Resource->Data);*/
+ break;
+
+ case ACPI_RSTYPE_IO:
+ acpi_rs_dump_io (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_FIXED_IO:
+ acpi_rs_dump_fixed_io (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_VENDOR:
+ acpi_rs_dump_vendor_specific (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_END_TAG:
+ /*rs_dump_end_tag (Resource->Data);*/
+ acpi_os_printf ("end_tag Resource\n");
+ done = TRUE;
+ break;
+
+ case ACPI_RSTYPE_MEM24:
+ acpi_rs_dump_memory24 (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_MEM32:
+ acpi_rs_dump_memory32 (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_FIXED_MEM32:
+ acpi_rs_dump_fixed_memory32 (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_ADDRESS16:
+ acpi_rs_dump_address16 (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_ADDRESS32:
+ acpi_rs_dump_address32 (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_ADDRESS64:
+ acpi_rs_dump_address64 (&resource->data);
+ break;
+
+ case ACPI_RSTYPE_EXT_IRQ:
+ acpi_rs_dump_extended_irq (&resource->data);
+ break;
+
+ default:
+ acpi_os_printf ("Invalid resource type\n");
+ break;
+
+ }
+
+ resource = ACPI_PTR_ADD (struct acpi_resource, resource, resource->length);
+ }
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dump_irq_list
+ *
+ * PARAMETERS: Data - pointer to the routing table to dump.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Dispatches the structures to the correct dump routine.
+ *
+ ******************************************************************************/
+
+void
+acpi_rs_dump_irq_list (
+ u8 *route_table)
+{
+ u8 *buffer = route_table;
+ u8 count = 0;
+ u8 done = FALSE;
+ struct acpi_pci_routing_table *prt_element;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (acpi_dbg_level & ACPI_LV_RESOURCES && _COMPONENT & acpi_dbg_layer) {
+ prt_element = ACPI_CAST_PTR (struct acpi_pci_routing_table, buffer);
+
+ while (!done) {
+ acpi_os_printf ("PCI IRQ Routing Table structure %X.\n", count++);
+
+ acpi_os_printf (" Address: %8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (prt_element->address));
+
+ acpi_os_printf (" Pin: %X\n", prt_element->pin);
+
+ acpi_os_printf (" Source: %s\n", prt_element->source);
+
+ acpi_os_printf (" source_index: %X\n",
+ prt_element->source_index);
+
+ buffer += prt_element->length;
+
+ prt_element = ACPI_CAST_PTR (struct acpi_pci_routing_table, buffer);
+
+ if(0 == prt_element->length) {
+ done = TRUE;
+ }
+ }
+ }
+
+ return;
+}
+
+#endif
+
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
new file mode 100644
index 000000000000..972c746d37e4
--- /dev/null
+++ b/drivers/acpi/resources/rsio.c
@@ -0,0 +1,545 @@
+/*******************************************************************************
+ *
+ * Module Name: rsio - IO and DMA resource descriptors
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsio")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_io_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_io_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io);
+
+
+ ACPI_FUNCTION_TRACE ("rs_io_resource");
+
+
+ /*
+ * The number of bytes consumed are Constant
+ */
+ *bytes_consumed = 8;
+
+ output_struct->id = ACPI_RSTYPE_IO;
+
+ /*
+ * Check Decode
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ output_struct->data.io.io_decode = temp8 & 0x01;
+
+ /*
+ * Check min_base Address
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ output_struct->data.io.min_base_address = temp16;
+
+ /*
+ * Check max_base Address
+ */
+ buffer += 2;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ output_struct->data.io.max_base_address = temp16;
+
+ /*
+ * Check Base alignment
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ output_struct->data.io.alignment = temp8;
+
+ /*
+ * Check range_length
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ output_struct->data.io.range_length = temp8;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_fixed_io_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_fixed_io_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_io);
+
+
+ ACPI_FUNCTION_TRACE ("rs_fixed_io_resource");
+
+
+ /*
+ * The number of bytes consumed are Constant
+ */
+ *bytes_consumed = 4;
+
+ output_struct->id = ACPI_RSTYPE_FIXED_IO;
+
+ /*
+ * Check Range Base Address
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ output_struct->data.fixed_io.base_address = temp16;
+
+ /*
+ * Check range_length
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ output_struct->data.fixed_io.range_length = temp8;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_io_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_io_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_io_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x47;
+ buffer += 1;
+
+ /*
+ * Io Information Byte
+ */
+ temp8 = (u8) (linked_list->data.io.io_decode & 0x01);
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Range minimum base address
+ */
+ temp16 = (u16) linked_list->data.io.min_base_address;
+
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the Range maximum base address
+ */
+ temp16 = (u16) linked_list->data.io.max_base_address;
+
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the base alignment
+ */
+ temp8 = (u8) linked_list->data.io.alignment;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the range length
+ */
+ temp8 = (u8) linked_list->data.io.range_length;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_fixed_io_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_fixed_io_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_fixed_io_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x4B;
+
+ buffer += 1;
+
+ /*
+ * Set the Range base address
+ */
+ temp16 = (u16) linked_list->data.fixed_io.base_address;
+
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the range length
+ */
+ temp8 = (u8) linked_list->data.fixed_io.range_length;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dma_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_dma_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u8 temp8 = 0;
+ u8 index;
+ u8 i;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_dma);
+
+
+ ACPI_FUNCTION_TRACE ("rs_dma_resource");
+
+
+ /*
+ * The number of bytes consumed are Constant
+ */
+ *bytes_consumed = 3;
+ output_struct->id = ACPI_RSTYPE_DMA;
+
+ /*
+ * Point to the 8-bits of Byte 1
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /* Decode the DMA channel bits */
+
+ for (i = 0, index = 0; index < 8; index++) {
+ if ((temp8 >> index) & 0x01) {
+ output_struct->data.dma.channels[i] = index;
+ i++;
+ }
+ }
+
+ /* Zero DMA channels is valid */
+
+ output_struct->data.dma.number_of_channels = i;
+ if (i > 0) {
+ /*
+ * Calculate the structure size based upon the number of interrupts
+ */
+ struct_size += ((acpi_size) i - 1) * 4;
+ }
+
+ /*
+ * Point to Byte 2
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /*
+ * Check for transfer preference (Bits[1:0])
+ */
+ output_struct->data.dma.transfer = temp8 & 0x03;
+
+ if (0x03 == output_struct->data.dma.transfer) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid DMA.Transfer preference (3)\n"));
+ return_ACPI_STATUS (AE_BAD_DATA);
+ }
+
+ /*
+ * Get bus master preference (Bit[2])
+ */
+ output_struct->data.dma.bus_master = (temp8 >> 2) & 0x01;
+
+ /*
+ * Get channel speed support (Bits[6:5])
+ */
+ output_struct->data.dma.type = (temp8 >> 5) & 0x03;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_dma_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_dma_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+
+
+ ACPI_FUNCTION_TRACE ("rs_dma_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x2A;
+ buffer += 1;
+ temp8 = 0;
+
+ /*
+ * Loop through all of the Channels and set the mask bits
+ */
+ for (index = 0;
+ index < linked_list->data.dma.number_of_channels;
+ index++) {
+ temp16 = (u16) linked_list->data.dma.channels[index];
+ temp8 |= 0x1 << temp16;
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the DMA Info
+ */
+ temp8 = (u8) ((linked_list->data.dma.type & 0x03) << 5);
+ temp8 |= ((linked_list->data.dma.bus_master & 0x01) << 2);
+ temp8 |= (linked_list->data.dma.transfer & 0x03);
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
new file mode 100644
index 000000000000..fd07a8702fbe
--- /dev/null
+++ b/drivers/acpi/resources/rsirq.c
@@ -0,0 +1,592 @@
+/*******************************************************************************
+ *
+ * Module Name: rsirq - IRQ resource descriptors
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsirq")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_irq_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_irq_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+ u8 i;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_irq);
+
+
+ ACPI_FUNCTION_TRACE ("rs_irq_resource");
+
+
+ /*
+ * The number of bytes consumed are contained in the descriptor
+ * (Bits:0-1)
+ */
+ temp8 = *buffer;
+ *bytes_consumed = (temp8 & 0x03) + 1;
+ output_struct->id = ACPI_RSTYPE_IRQ;
+
+ /*
+ * Point to the 16-bits of Bytes 1 and 2
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ output_struct->data.irq.number_of_interrupts = 0;
+
+ /* Decode the IRQ bits */
+
+ for (i = 0, index = 0; index < 16; index++) {
+ if ((temp16 >> index) & 0x01) {
+ output_struct->data.irq.interrupts[i] = index;
+ i++;
+ }
+ }
+
+ /* Zero interrupts is valid */
+
+ output_struct->data.irq.number_of_interrupts = i;
+ if (i > 0) {
+ /*
+ * Calculate the structure size based upon the number of interrupts
+ */
+ struct_size += ((acpi_size) i - 1) * 4;
+ }
+
+ /*
+ * Point to Byte 3 if it is used
+ */
+ if (4 == *bytes_consumed) {
+ buffer += 2;
+ temp8 = *buffer;
+
+ /*
+ * Check for HE, LL interrupts
+ */
+ switch (temp8 & 0x09) {
+ case 0x01: /* HE */
+ output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE;
+ output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH;
+ break;
+
+ case 0x08: /* LL */
+ output_struct->data.irq.edge_level = ACPI_LEVEL_SENSITIVE;
+ output_struct->data.irq.active_high_low = ACPI_ACTIVE_LOW;
+ break;
+
+ default:
+ /*
+ * Only _LL and _HE polarity/trigger interrupts
+ * are allowed (ACPI spec, section "IRQ Format")
+ * so 0x00 and 0x09 are illegal.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid interrupt polarity/trigger in resource list, %X\n", temp8));
+ return_ACPI_STATUS (AE_BAD_DATA);
+ }
+
+ /*
+ * Check for sharable
+ */
+ output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01;
+ }
+ else {
+ /*
+ * Assume Edge Sensitive, Active High, Non-Sharable
+ * per ACPI Specification
+ */
+ output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE;
+ output_struct->data.irq.active_high_low = ACPI_ACTIVE_HIGH;
+ output_struct->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_irq_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_irq_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+ u8 IRqinfo_byte_needed;
+
+
+ ACPI_FUNCTION_TRACE ("rs_irq_stream");
+
+
+ /*
+ * The descriptor field is set based upon whether a third byte is
+ * needed to contain the IRQ Information.
+ */
+ if (ACPI_EDGE_SENSITIVE == linked_list->data.irq.edge_level &&
+ ACPI_ACTIVE_HIGH == linked_list->data.irq.active_high_low &&
+ ACPI_EXCLUSIVE == linked_list->data.irq.shared_exclusive) {
+ *buffer = 0x22;
+ IRqinfo_byte_needed = FALSE;
+ }
+ else {
+ *buffer = 0x23;
+ IRqinfo_byte_needed = TRUE;
+ }
+
+ buffer += 1;
+ temp16 = 0;
+
+ /*
+ * Loop through all of the interrupts and set the mask bits
+ */
+ for(index = 0;
+ index < linked_list->data.irq.number_of_interrupts;
+ index++) {
+ temp8 = (u8) linked_list->data.irq.interrupts[index];
+ temp16 |= 0x1 << temp8;
+ }
+
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the IRQ Info byte if needed.
+ */
+ if (IRqinfo_byte_needed) {
+ temp8 = 0;
+ temp8 = (u8) ((linked_list->data.irq.shared_exclusive &
+ 0x01) << 4);
+
+ if (ACPI_LEVEL_SENSITIVE == linked_list->data.irq.edge_level &&
+ ACPI_ACTIVE_LOW == linked_list->data.irq.active_high_low) {
+ temp8 |= 0x08;
+ }
+ else {
+ temp8 |= 0x01;
+ }
+
+ *buffer = temp8;
+ buffer += 1;
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_extended_irq_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_extended_irq_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 *temp_ptr;
+ u8 index;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq);
+
+
+ ACPI_FUNCTION_TRACE ("rs_extended_irq_resource");
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ /* Validate minimum descriptor length */
+
+ if (temp16 < 6) {
+ return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
+ *bytes_consumed = temp16 + 3;
+ output_struct->id = ACPI_RSTYPE_EXT_IRQ;
+
+ /*
+ * Point to the Byte3
+ */
+ buffer += 2;
+ temp8 = *buffer;
+
+ output_struct->data.extended_irq.producer_consumer = temp8 & 0x01;
+
+ /*
+ * Check for Interrupt Mode
+ *
+ * The definition of an Extended IRQ changed between ACPI spec v1.0b
+ * and ACPI spec 2.0 (section 6.4.3.6 in both).
+ *
+ * - Edge/Level are defined opposite in the table vs the headers
+ */
+ output_struct->data.extended_irq.edge_level =
+ (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
+
+ /*
+ * Check Interrupt Polarity
+ */
+ output_struct->data.extended_irq.active_high_low = (temp8 >> 2) & 0x1;
+
+ /*
+ * Check for sharable
+ */
+ output_struct->data.extended_irq.shared_exclusive = (temp8 >> 3) & 0x01;
+
+ /*
+ * Point to Byte4 (IRQ Table length)
+ */
+ buffer += 1;
+ temp8 = *buffer;
+
+ /* Must have at least one IRQ */
+
+ if (temp8 < 1) {
+ return_ACPI_STATUS (AE_AML_BAD_RESOURCE_LENGTH);
+ }
+
+ output_struct->data.extended_irq.number_of_interrupts = temp8;
+
+ /*
+ * Add any additional structure size to properly calculate
+ * the next pointer at the end of this function
+ */
+ struct_size += (temp8 - 1) * 4;
+
+ /*
+ * Point to Byte5 (First IRQ Number)
+ */
+ buffer += 1;
+
+ /*
+ * Cycle through every IRQ in the table
+ */
+ for (index = 0; index < temp8; index++) {
+ ACPI_MOVE_32_TO_32 (
+ &output_struct->data.extended_irq.interrupts[index], buffer);
+
+ /* Point to the next IRQ */
+
+ buffer += 4;
+ }
+
+ /*
+ * This will leave us pointing to the Resource Source Index
+ * If it is present, then save it off and calculate the
+ * pointer to where the null terminated string goes:
+ * Each Interrupt takes 32-bits + the 5 bytes of the
+ * stream that are default.
+ *
+ * Note: Some resource descriptors will have an additional null, so
+ * we add 1 to the length.
+ */
+ if (*bytes_consumed >
+ ((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + (5 + 1)) {
+ /* Dereference the Index */
+
+ temp8 = *buffer;
+ output_struct->data.extended_irq.resource_source.index = (u32) temp8;
+
+ /* Point to the String */
+
+ buffer += 1;
+
+ /*
+ * Point the String pointer to the end of this structure.
+ */
+ output_struct->data.extended_irq.resource_source.string_ptr =
+ (char *)((char *) output_struct + struct_size);
+
+ temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr;
+
+ /* Copy the string into the buffer */
+
+ index = 0;
+ while (0x00 != *buffer) {
+ *temp_ptr = *buffer;
+
+ temp_ptr += 1;
+ buffer += 1;
+ index += 1;
+ }
+
+ /*
+ * Add the terminating null
+ */
+ *temp_ptr = 0x00;
+ output_struct->data.extended_irq.resource_source.string_length = index + 1;
+
+ /*
+ * In order for the struct_size to fall on a 32-bit boundary,
+ * calculate the length of the string and expand the
+ * struct_size to the next 32-bit boundary.
+ */
+ temp8 = (u8) (index + 1);
+ struct_size += ACPI_ROUND_UP_to_32_bITS (temp8);
+ }
+ else {
+ output_struct->data.extended_irq.resource_source.index = 0x00;
+ output_struct->data.extended_irq.resource_source.string_length = 0;
+ output_struct->data.extended_irq.resource_source.string_ptr = NULL;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_extended_irq_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_extended_irq_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 *length_field;
+ u8 temp8 = 0;
+ u8 index;
+ char *temp_pointer = NULL;
+
+
+ ACPI_FUNCTION_TRACE ("rs_extended_irq_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x89;
+ buffer += 1;
+
+ /*
+ * Set a pointer to the Length field - to be filled in later
+ */
+ length_field = ACPI_CAST_PTR (u16, buffer);
+ buffer += 2;
+
+ /*
+ * Set the Interrupt vector flags
+ */
+ temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01);
+ temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3);
+
+ /*
+ * Set the Interrupt Mode
+ *
+ * The definition of an Extended IRQ changed between ACPI spec v1.0b
+ * and ACPI spec 2.0 (section 6.4.3.6 in both). This code does not
+ * implement the more restrictive definition of 1.0b
+ *
+ * - Edge/Level are defined opposite in the table vs the headers
+ */
+ if (ACPI_EDGE_SENSITIVE == linked_list->data.extended_irq.edge_level) {
+ temp8 |= 0x2;
+ }
+
+ /*
+ * Set the Interrupt Polarity
+ */
+ temp8 |= ((linked_list->data.extended_irq.active_high_low & 0x1) << 2);
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Interrupt table length
+ */
+ temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ for (index = 0; index < linked_list->data.extended_irq.number_of_interrupts;
+ index++) {
+ ACPI_MOVE_32_TO_32 (buffer,
+ &linked_list->data.extended_irq.interrupts[index]);
+ buffer += 4;
+ }
+
+ /*
+ * Resource Source Index and Resource Source are optional
+ */
+ if (0 != linked_list->data.extended_irq.resource_source.string_length) {
+ *buffer = (u8) linked_list->data.extended_irq.resource_source.index;
+ buffer += 1;
+
+ temp_pointer = (char *) buffer;
+
+ /*
+ * Copy the string
+ */
+ ACPI_STRCPY (temp_pointer,
+ linked_list->data.extended_irq.resource_source.string_ptr);
+
+ /*
+ * Buffer needs to be set to the length of the sting + one for the
+ * terminating null
+ */
+ buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1);
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+
+ /*
+ * Set the length field to the number of bytes consumed
+ * minus the header size (3 bytes)
+ */
+ *length_field = (u16) (*bytes_consumed - 3);
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
new file mode 100644
index 000000000000..e49c1e030f99
--- /dev/null
+++ b/drivers/acpi/resources/rslist.c
@@ -0,0 +1,518 @@
+/*******************************************************************************
+ *
+ * Module Name: rslist - Linked list utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rslist")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_resource_type
+ *
+ * PARAMETERS: resource_start_byte - Byte 0 of a resource descriptor
+ *
+ * RETURN: The Resource Type (Name) with no extraneous bits
+ *
+ * DESCRIPTION: Extract the Resource Type/Name from the first byte of
+ * a resource descriptor.
+ *
+ ******************************************************************************/
+
+u8
+acpi_rs_get_resource_type (
+ u8 resource_start_byte)
+{
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /*
+ * Determine if this is a small or large resource
+ */
+ switch (resource_start_byte & ACPI_RDESC_TYPE_MASK) {
+ case ACPI_RDESC_TYPE_SMALL:
+
+ /*
+ * Small Resource Type -- Only bits 6:3 are valid
+ */
+ return ((u8) (resource_start_byte & ACPI_RDESC_SMALL_MASK));
+
+
+ case ACPI_RDESC_TYPE_LARGE:
+
+ /*
+ * Large Resource Type -- All bits are valid
+ */
+ return (resource_start_byte);
+
+
+ default:
+ /* No other types of resource descriptor */
+ break;
+ }
+
+ return (0xFF);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_byte_stream_to_list
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource byte stream
+ * byte_stream_buffer_length - Length of byte_stream_buffer
+ * output_buffer - Pointer to the buffer that will
+ * contain the output structures
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Takes the resource byte stream and parses it, creating a
+ * linked list of resources in the caller's output buffer
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_byte_stream_to_list (
+ u8 *byte_stream_buffer,
+ u32 byte_stream_buffer_length,
+ u8 *output_buffer)
+{
+ acpi_status status;
+ acpi_size bytes_parsed = 0;
+ u8 resource_type = 0;
+ acpi_size bytes_consumed = 0;
+ u8 *buffer = output_buffer;
+ acpi_size structure_size = 0;
+ u8 end_tag_processed = FALSE;
+ struct acpi_resource *resource;
+
+ ACPI_FUNCTION_TRACE ("rs_byte_stream_to_list");
+
+
+ while (bytes_parsed < byte_stream_buffer_length &&
+ !end_tag_processed) {
+ /*
+ * The next byte in the stream is the resource type
+ */
+ resource_type = acpi_rs_get_resource_type (*byte_stream_buffer);
+
+ switch (resource_type) {
+ case ACPI_RDESC_TYPE_MEMORY_24:
+ /*
+ * 24-Bit Memory Resource
+ */
+ status = acpi_rs_memory24_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_LARGE_VENDOR:
+ /*
+ * Vendor Defined Resource
+ */
+ status = acpi_rs_vendor_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_MEMORY_32:
+ /*
+ * 32-Bit Memory Range Resource
+ */
+ status = acpi_rs_memory32_range_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_FIXED_MEMORY_32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ */
+ status = acpi_rs_fixed_memory32_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_QWORD_ADDRESS_SPACE:
+ case ACPI_RDESC_TYPE_EXTENDED_ADDRESS_SPACE:
+ /*
+ * 64-Bit Address Resource
+ */
+ status = acpi_rs_address64_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_DWORD_ADDRESS_SPACE:
+ /*
+ * 32-Bit Address Resource
+ */
+ status = acpi_rs_address32_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_WORD_ADDRESS_SPACE:
+ /*
+ * 16-Bit Address Resource
+ */
+ status = acpi_rs_address16_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_EXTENDED_XRUPT:
+ /*
+ * Extended IRQ
+ */
+ status = acpi_rs_extended_irq_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_IRQ_FORMAT:
+ /*
+ * IRQ Resource
+ */
+ status = acpi_rs_irq_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_DMA_FORMAT:
+ /*
+ * DMA Resource
+ */
+ status = acpi_rs_dma_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_START_DEPENDENT:
+ /*
+ * Start Dependent Functions Resource
+ */
+ status = acpi_rs_start_depend_fns_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_END_DEPENDENT:
+ /*
+ * End Dependent Functions Resource
+ */
+ status = acpi_rs_end_depend_fns_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_IO_PORT:
+ /*
+ * IO Port Resource
+ */
+ status = acpi_rs_io_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_FIXED_IO_PORT:
+ /*
+ * Fixed IO Port Resource
+ */
+ status = acpi_rs_fixed_io_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_SMALL_VENDOR:
+ /*
+ * Vendor Specific Resource
+ */
+ status = acpi_rs_vendor_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ case ACPI_RDESC_TYPE_END_TAG:
+ /*
+ * End Tag
+ */
+ end_tag_processed = TRUE;
+ status = acpi_rs_end_tag_resource (byte_stream_buffer,
+ &bytes_consumed, &buffer, &structure_size);
+ break;
+
+
+ default:
+ /*
+ * Invalid/Unknown resource type
+ */
+ status = AE_AML_INVALID_RESOURCE_TYPE;
+ break;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Update the return value and counter
+ */
+ bytes_parsed += bytes_consumed;
+
+ /*
+ * Set the byte stream to point to the next resource
+ */
+ byte_stream_buffer += bytes_consumed;
+
+ /*
+ * Set the Buffer to the next structure
+ */
+ resource = ACPI_CAST_PTR (struct acpi_resource, buffer);
+ resource->length = (u32) ACPI_ALIGN_RESOURCE_SIZE (resource->length);
+ buffer += ACPI_ALIGN_RESOURCE_SIZE (structure_size);
+
+ } /* end while */
+
+ /*
+ * Check the reason for exiting the while loop
+ */
+ if (!end_tag_processed) {
+ return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_list_to_byte_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * byte_steam_size_needed - Calculated size of the byte stream
+ * needed from calling
+ * acpi_rs_get_byte_stream_length()
+ * The size of the output_buffer is
+ * guaranteed to be >=
+ * byte_stream_size_needed
+ * output_buffer - Pointer to the buffer that will
+ * contain the byte stream
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Takes the resource linked list and parses it, creating a
+ * byte stream of resources in the caller's output buffer
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_list_to_byte_stream (
+ struct acpi_resource *linked_list,
+ acpi_size byte_stream_size_needed,
+ u8 *output_buffer)
+{
+ acpi_status status;
+ u8 *buffer = output_buffer;
+ acpi_size bytes_consumed = 0;
+ u8 done = FALSE;
+
+
+ ACPI_FUNCTION_TRACE ("rs_list_to_byte_stream");
+
+
+ while (!done) {
+ switch (linked_list->id) {
+ case ACPI_RSTYPE_IRQ:
+ /*
+ * IRQ Resource
+ */
+ status = acpi_rs_irq_stream (linked_list, &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_DMA:
+ /*
+ * DMA Resource
+ */
+ status = acpi_rs_dma_stream (linked_list, &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_START_DPF:
+ /*
+ * Start Dependent Functions Resource
+ */
+ status = acpi_rs_start_depend_fns_stream (linked_list,
+ &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_END_DPF:
+ /*
+ * End Dependent Functions Resource
+ */
+ status = acpi_rs_end_depend_fns_stream (linked_list,
+ &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_IO:
+ /*
+ * IO Port Resource
+ */
+ status = acpi_rs_io_stream (linked_list, &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_FIXED_IO:
+ /*
+ * Fixed IO Port Resource
+ */
+ status = acpi_rs_fixed_io_stream (linked_list, &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_VENDOR:
+ /*
+ * Vendor Defined Resource
+ */
+ status = acpi_rs_vendor_stream (linked_list, &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_END_TAG:
+ /*
+ * End Tag
+ */
+ status = acpi_rs_end_tag_stream (linked_list, &buffer, &bytes_consumed);
+
+ /*
+ * An End Tag indicates the end of the Resource Template
+ */
+ done = TRUE;
+ break;
+
+ case ACPI_RSTYPE_MEM24:
+ /*
+ * 24-Bit Memory Resource
+ */
+ status = acpi_rs_memory24_stream (linked_list, &buffer, &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_MEM32:
+ /*
+ * 32-Bit Memory Range Resource
+ */
+ status = acpi_rs_memory32_range_stream (linked_list, &buffer,
+ &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_FIXED_MEM32:
+ /*
+ * 32-Bit Fixed Memory Resource
+ */
+ status = acpi_rs_fixed_memory32_stream (linked_list, &buffer,
+ &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_ADDRESS16:
+ /*
+ * 16-Bit Address Descriptor Resource
+ */
+ status = acpi_rs_address16_stream (linked_list, &buffer,
+ &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_ADDRESS32:
+ /*
+ * 32-Bit Address Descriptor Resource
+ */
+ status = acpi_rs_address32_stream (linked_list, &buffer,
+ &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_ADDRESS64:
+ /*
+ * 64-Bit Address Descriptor Resource
+ */
+ status = acpi_rs_address64_stream (linked_list, &buffer,
+ &bytes_consumed);
+ break;
+
+ case ACPI_RSTYPE_EXT_IRQ:
+ /*
+ * Extended IRQ Resource
+ */
+ status = acpi_rs_extended_irq_stream (linked_list, &buffer,
+ &bytes_consumed);
+ break;
+
+ default:
+ /*
+ * If we get here, everything is out of sync,
+ * so exit with an error
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid descriptor type (%X) in resource list\n",
+ linked_list->id));
+ status = AE_BAD_DATA;
+ break;
+
+ } /* switch (linked_list->Id) */
+
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Set the Buffer to point to the open byte
+ */
+ buffer += bytes_consumed;
+
+ /*
+ * Point to the next object
+ */
+ linked_list = ACPI_PTR_ADD (struct acpi_resource,
+ linked_list, linked_list->length);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
new file mode 100644
index 000000000000..7c935aecf075
--- /dev/null
+++ b/drivers/acpi/resources/rsmemory.c
@@ -0,0 +1,566 @@
+/*******************************************************************************
+ *
+ * Module Name: rsmem24 - Memory resource descriptors
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsmemory")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_memory24_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_memory24_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem24);
+
+
+ ACPI_FUNCTION_TRACE ("rs_memory24_resource");
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+ buffer += 2;
+ *bytes_consumed = (acpi_size) temp16 + 3;
+ output_struct->id = ACPI_RSTYPE_MEM24;
+
+ /*
+ * Check Byte 3 the Read/Write bit
+ */
+ temp8 = *buffer;
+ buffer += 1;
+ output_struct->data.memory24.read_write_attribute = temp8 & 0x01;
+
+ /*
+ * Get min_base_address (Bytes 4-5)
+ */
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+ buffer += 2;
+ output_struct->data.memory24.min_base_address = temp16;
+
+ /*
+ * Get max_base_address (Bytes 6-7)
+ */
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+ buffer += 2;
+ output_struct->data.memory24.max_base_address = temp16;
+
+ /*
+ * Get Alignment (Bytes 8-9)
+ */
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+ buffer += 2;
+ output_struct->data.memory24.alignment = temp16;
+
+ /*
+ * Get range_length (Bytes 10-11)
+ */
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+ output_struct->data.memory24.range_length = temp16;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_memory24_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_memory24_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_memory24_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x81;
+ buffer += 1;
+
+ /*
+ * The length field is static
+ */
+ temp16 = 0x09;
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the Information Byte
+ */
+ temp8 = (u8) (linked_list->data.memory24.read_write_attribute & 0x01);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Range minimum base address
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.min_base_address);
+ buffer += 2;
+
+ /*
+ * Set the Range maximum base address
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.max_base_address);
+ buffer += 2;
+
+ /*
+ * Set the base alignment
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.alignment);
+ buffer += 2;
+
+ /*
+ * Set the range length
+ */
+ ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.range_length);
+ buffer += 2;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_memory32_range_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_memory32_range_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem32);
+
+
+ ACPI_FUNCTION_TRACE ("rs_memory32_range_resource");
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+ buffer += 2;
+ *bytes_consumed = (acpi_size) temp16 + 3;
+
+ output_struct->id = ACPI_RSTYPE_MEM32;
+
+ /*
+ * Point to the place in the output buffer where the data portion will
+ * begin.
+ * 1. Set the RESOURCE_DATA * Data to point to its own address, then
+ * 2. Set the pointer to the next address.
+ *
+ * NOTE: output_struct->Data is cast to u8, otherwise, this addition adds
+ * 4 * sizeof(RESOURCE_DATA) instead of 4 * sizeof(u8)
+ */
+
+ /*
+ * Check Byte 3 the Read/Write bit
+ */
+ temp8 = *buffer;
+ buffer += 1;
+
+ output_struct->data.memory32.read_write_attribute = temp8 & 0x01;
+
+ /*
+ * Get min_base_address (Bytes 4-7)
+ */
+ ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.min_base_address, buffer);
+ buffer += 4;
+
+ /*
+ * Get max_base_address (Bytes 8-11)
+ */
+ ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.max_base_address, buffer);
+ buffer += 4;
+
+ /*
+ * Get Alignment (Bytes 12-15)
+ */
+ ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.alignment, buffer);
+ buffer += 4;
+
+ /*
+ * Get range_length (Bytes 16-19)
+ */
+ ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.range_length, buffer);
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_fixed_memory32_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_fixed_memory32_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_mem32);
+
+
+ ACPI_FUNCTION_TRACE ("rs_fixed_memory32_resource");
+
+
+ /*
+ * Point past the Descriptor to get the number of bytes consumed
+ */
+ buffer += 1;
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ buffer += 2;
+ *bytes_consumed = (acpi_size) temp16 + 3;
+
+ output_struct->id = ACPI_RSTYPE_FIXED_MEM32;
+
+ /*
+ * Check Byte 3 the Read/Write bit
+ */
+ temp8 = *buffer;
+ buffer += 1;
+ output_struct->data.fixed_memory32.read_write_attribute = temp8 & 0x01;
+
+ /*
+ * Get range_base_address (Bytes 4-7)
+ */
+ ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, buffer);
+ buffer += 4;
+
+ /*
+ * Get range_length (Bytes 8-11)
+ */
+ ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_length, buffer);
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_memory32_range_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_memory32_range_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_memory32_range_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x85;
+ buffer += 1;
+
+ /*
+ * The length field is static
+ */
+ temp16 = 0x11;
+
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the Information Byte
+ */
+ temp8 = (u8) (linked_list->data.memory32.read_write_attribute & 0x01);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Range minimum base address
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.min_base_address);
+ buffer += 4;
+
+ /*
+ * Set the Range maximum base address
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.max_base_address);
+ buffer += 4;
+
+ /*
+ * Set the base alignment
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.alignment);
+ buffer += 4;
+
+ /*
+ * Set the range length
+ */
+ ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.range_length);
+ buffer += 4;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_fixed_memory32_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_fixed_memory32_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_fixed_memory32_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x86;
+ buffer += 1;
+
+ /*
+ * The length field is static
+ */
+ temp16 = 0x09;
+
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+
+ /*
+ * Set the Information Byte
+ */
+ temp8 = (u8) (linked_list->data.fixed_memory32.read_write_attribute & 0x01);
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Set the Range base address
+ */
+ ACPI_MOVE_32_TO_32 (buffer,
+ &linked_list->data.fixed_memory32.range_base_address);
+ buffer += 4;
+
+ /*
+ * Set the range length
+ */
+ ACPI_MOVE_32_TO_32 (buffer,
+ &linked_list->data.fixed_memory32.range_length);
+ buffer += 4;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
new file mode 100644
index 000000000000..d16be44b5df7
--- /dev/null
+++ b/drivers/acpi/resources/rsmisc.c
@@ -0,0 +1,597 @@
+/*******************************************************************************
+ *
+ * Module Name: rsmisc - Miscellaneous resource descriptors
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsmisc")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_end_tag_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_end_tag_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ acpi_size struct_size = ACPI_RESOURCE_LENGTH;
+
+
+ ACPI_FUNCTION_TRACE ("rs_end_tag_resource");
+
+
+ /*
+ * The number of bytes consumed is static
+ */
+ *bytes_consumed = 2;
+
+ /*
+ * Fill out the structure
+ */
+ output_struct->id = ACPI_RSTYPE_END_TAG;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = 0;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_end_tag_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_end_tag_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u8 temp8 = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_end_tag_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x79;
+ buffer += 1;
+
+ /*
+ * Set the Checksum - zero means that the resource data is treated as if
+ * the checksum operation succeeded (ACPI Spec 1.0b Section 6.4.2.8)
+ */
+ temp8 = 0;
+
+ *buffer = temp8;
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_vendor_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_vendor_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor);
+
+
+ ACPI_FUNCTION_TRACE ("rs_vendor_resource");
+
+
+ /*
+ * Dereference the Descriptor to find if this is a large or small item.
+ */
+ temp8 = *buffer;
+
+ if (temp8 & 0x80) {
+ /*
+ * Large Item, point to the length field
+ */
+ buffer += 1;
+
+ /* Dereference */
+
+ ACPI_MOVE_16_TO_16 (&temp16, buffer);
+
+ /* Calculate bytes consumed */
+
+ *bytes_consumed = (acpi_size) temp16 + 3;
+
+ /* Point to the first vendor byte */
+
+ buffer += 2;
+ }
+ else {
+ /*
+ * Small Item, dereference the size
+ */
+ temp16 = (u8)(*buffer & 0x07);
+
+ /* Calculate bytes consumed */
+
+ *bytes_consumed = (acpi_size) temp16 + 1;
+
+ /* Point to the first vendor byte */
+
+ buffer += 1;
+ }
+
+ output_struct->id = ACPI_RSTYPE_VENDOR;
+ output_struct->data.vendor_specific.length = temp16;
+
+ for (index = 0; index < temp16; index++) {
+ output_struct->data.vendor_specific.reserved[index] = *buffer;
+ buffer += 1;
+ }
+
+ /*
+ * In order for the struct_size to fall on a 32-bit boundary,
+ * calculate the length of the vendor string and expand the
+ * struct_size to the next 32-bit boundary.
+ */
+ struct_size += ACPI_ROUND_UP_to_32_bITS (temp16);
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_vendor_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_vendor_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u16 temp16 = 0;
+ u8 temp8 = 0;
+ u8 index;
+
+
+ ACPI_FUNCTION_TRACE ("rs_vendor_stream");
+
+
+ /*
+ * Dereference the length to find if this is a large or small item.
+ */
+ if(linked_list->data.vendor_specific.length > 7) {
+ /*
+ * Large Item, Set the descriptor field and length bytes
+ */
+ *buffer = 0x84;
+ buffer += 1;
+
+ temp16 = (u16) linked_list->data.vendor_specific.length;
+
+ ACPI_MOVE_16_TO_16 (buffer, &temp16);
+ buffer += 2;
+ }
+ else {
+ /*
+ * Small Item, Set the descriptor field
+ */
+ temp8 = 0x70;
+ temp8 |= (u8) linked_list->data.vendor_specific.length;
+
+ *buffer = temp8;
+ buffer += 1;
+ }
+
+ /*
+ * Loop through all of the Vendor Specific fields
+ */
+ for (index = 0; index < linked_list->data.vendor_specific.length; index++) {
+ temp8 = linked_list->data.vendor_specific.reserved[index];
+
+ *buffer = temp8;
+ buffer += 1;
+ }
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_start_depend_fns_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_start_depend_fns_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ u8 temp8 = 0;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_start_dpf);
+
+
+ ACPI_FUNCTION_TRACE ("rs_start_depend_fns_resource");
+
+
+ /*
+ * The number of bytes consumed are contained in the descriptor (Bits:0-1)
+ */
+ temp8 = *buffer;
+
+ *bytes_consumed = (temp8 & 0x01) + 1;
+
+ output_struct->id = ACPI_RSTYPE_START_DPF;
+
+ /*
+ * Point to Byte 1 if it is used
+ */
+ if (2 == *bytes_consumed) {
+ buffer += 1;
+ temp8 = *buffer;
+
+ /*
+ * Check Compatibility priority
+ */
+ output_struct->data.start_dpf.compatibility_priority = temp8 & 0x03;
+
+ if (3 == output_struct->data.start_dpf.compatibility_priority) {
+ return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE);
+ }
+
+ /*
+ * Check Performance/Robustness preference
+ */
+ output_struct->data.start_dpf.performance_robustness = (temp8 >> 2) & 0x03;
+
+ if (3 == output_struct->data.start_dpf.performance_robustness) {
+ return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE);
+ }
+ }
+ else {
+ output_struct->data.start_dpf.compatibility_priority =
+ ACPI_ACCEPTABLE_CONFIGURATION;
+
+ output_struct->data.start_dpf.performance_robustness =
+ ACPI_ACCEPTABLE_CONFIGURATION;
+ }
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_end_depend_fns_resource
+ *
+ * PARAMETERS: byte_stream_buffer - Pointer to the resource input byte
+ * stream
+ * bytes_consumed - Pointer to where the number of bytes
+ * consumed the byte_stream_buffer is
+ * returned
+ * output_buffer - Pointer to the return data buffer
+ * structure_size - Pointer to where the number of bytes
+ * in the return data struct is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the resource byte stream and fill out the appropriate
+ * structure pointed to by the output_buffer. Return the
+ * number of bytes consumed from the byte stream.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_end_depend_fns_resource (
+ u8 *byte_stream_buffer,
+ acpi_size *bytes_consumed,
+ u8 **output_buffer,
+ acpi_size *structure_size)
+{
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ acpi_size struct_size = ACPI_RESOURCE_LENGTH;
+
+
+ ACPI_FUNCTION_TRACE ("rs_end_depend_fns_resource");
+
+
+ /*
+ * The number of bytes consumed is static
+ */
+ *bytes_consumed = 1;
+
+ /*
+ * Fill out the structure
+ */
+ output_struct->id = ACPI_RSTYPE_END_DPF;
+
+ /*
+ * Set the Length parameter
+ */
+ output_struct->length = (u32) struct_size;
+
+ /*
+ * Return the final size of the structure
+ */
+ *structure_size = struct_size;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_start_depend_fns_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - u32 pointer that is filled with
+ * the number of bytes of the
+ * output_buffer used
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_start_depend_fns_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+ u8 temp8 = 0;
+
+
+ ACPI_FUNCTION_TRACE ("rs_start_depend_fns_stream");
+
+
+ /*
+ * The descriptor field is set based upon whether a byte is needed
+ * to contain Priority data.
+ */
+ if (ACPI_ACCEPTABLE_CONFIGURATION ==
+ linked_list->data.start_dpf.compatibility_priority &&
+ ACPI_ACCEPTABLE_CONFIGURATION ==
+ linked_list->data.start_dpf.performance_robustness) {
+ *buffer = 0x30;
+ }
+ else {
+ *buffer = 0x31;
+ buffer += 1;
+
+ /*
+ * Set the Priority Byte Definition
+ */
+ temp8 = 0;
+ temp8 = (u8) ((linked_list->data.start_dpf.performance_robustness &
+ 0x03) << 2);
+ temp8 |= (linked_list->data.start_dpf.compatibility_priority &
+ 0x03);
+ *buffer = temp8;
+ }
+
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_end_depend_fns_stream
+ *
+ * PARAMETERS: linked_list - Pointer to the resource linked list
+ * output_buffer - Pointer to the user's return buffer
+ * bytes_consumed - Pointer to where the number of bytes
+ * used in the output_buffer is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Take the linked list resource structure and fills in the
+ * the appropriate bytes in a byte stream
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_end_depend_fns_stream (
+ struct acpi_resource *linked_list,
+ u8 **output_buffer,
+ acpi_size *bytes_consumed)
+{
+ u8 *buffer = *output_buffer;
+
+
+ ACPI_FUNCTION_TRACE ("rs_end_depend_fns_stream");
+
+
+ /*
+ * The descriptor field is static
+ */
+ *buffer = 0x38;
+ buffer += 1;
+
+ /*
+ * Return the number of bytes consumed in this operation
+ */
+ *bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
new file mode 100644
index 000000000000..ee9ce13c053d
--- /dev/null
+++ b/drivers/acpi/resources/rsutils.c
@@ -0,0 +1,356 @@
+/*******************************************************************************
+ *
+ * Module Name: rsutils - Utilities for the resource manager
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acresrc.h>
+
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_prt_method_data
+ *
+ * PARAMETERS: Handle - a handle to the containing object
+ * ret_buffer - a pointer to a buffer structure for the
+ * results
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the _PRT value of an object
+ * contained in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_get_prt_method_data (
+ acpi_handle handle,
+ struct acpi_buffer *ret_buffer)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("rs_get_prt_method_data");
+
+
+ /* Parameters guaranteed valid by caller */
+
+ /*
+ * Execute the method, no parameters
+ */
+ status = acpi_ut_evaluate_object (handle, "_PRT", ACPI_BTYPE_PACKAGE, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Create a resource linked list from the byte stream buffer that comes
+ * back from the _CRS method execution.
+ */
+ status = acpi_rs_create_pci_routing_table (obj_desc, ret_buffer);
+
+ /* On exit, we must delete the object returned by evaluate_object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_crs_method_data
+ *
+ * PARAMETERS: Handle - a handle to the containing object
+ * ret_buffer - a pointer to a buffer structure for the
+ * results
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the _CRS value of an object
+ * contained in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_get_crs_method_data (
+ acpi_handle handle,
+ struct acpi_buffer *ret_buffer)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("rs_get_crs_method_data");
+
+
+ /* Parameters guaranteed valid by caller */
+
+ /*
+ * Execute the method, no parameters
+ */
+ status = acpi_ut_evaluate_object (handle, "_CRS", ACPI_BTYPE_BUFFER, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Make the call to create a resource linked list from the
+ * byte stream buffer that comes back from the _CRS method
+ * execution.
+ */
+ status = acpi_rs_create_resource_list (obj_desc, ret_buffer);
+
+ /* on exit, we must delete the object returned by evaluate_object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_prs_method_data
+ *
+ * PARAMETERS: Handle - a handle to the containing object
+ * ret_buffer - a pointer to a buffer structure for the
+ * results
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the _PRS value of an object
+ * contained in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_rs_get_prs_method_data (
+ acpi_handle handle,
+ struct acpi_buffer *ret_buffer)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("rs_get_prs_method_data");
+
+
+ /* Parameters guaranteed valid by caller */
+
+ /*
+ * Execute the method, no parameters
+ */
+ status = acpi_ut_evaluate_object (handle, "_PRS", ACPI_BTYPE_BUFFER, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Make the call to create a resource linked list from the
+ * byte stream buffer that comes back from the _CRS method
+ * execution.
+ */
+ status = acpi_rs_create_resource_list (obj_desc, ret_buffer);
+
+ /* on exit, we must delete the object returned by evaluate_object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_get_method_data
+ *
+ * PARAMETERS: Handle - a handle to the containing object
+ * ret_buffer - a pointer to a buffer structure for the
+ * results
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the _CRS or _PRS value of an
+ * object contained in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_get_method_data (
+ acpi_handle handle,
+ char *path,
+ struct acpi_buffer *ret_buffer)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("rs_get_method_data");
+
+
+ /* Parameters guaranteed valid by caller */
+
+ /*
+ * Execute the method, no parameters
+ */
+ status = acpi_ut_evaluate_object (handle, path, ACPI_BTYPE_BUFFER, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Make the call to create a resource linked list from the
+ * byte stream buffer that comes back from the method
+ * execution.
+ */
+ status = acpi_rs_create_resource_list (obj_desc, ret_buffer);
+
+ /* On exit, we must delete the object returned by evaluate_object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_rs_set_srs_method_data
+ *
+ * PARAMETERS: Handle - a handle to the containing object
+ * in_buffer - a pointer to a buffer structure of the
+ * parameter
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to set the _SRS of an object contained
+ * in an object specified by the handle passed in
+ *
+ * If the function fails an appropriate status will be returned
+ * and the contents of the callers buffer is undefined.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_rs_set_srs_method_data (
+ acpi_handle handle,
+ struct acpi_buffer *in_buffer)
+{
+ struct acpi_parameter_info info;
+ union acpi_operand_object *params[2];
+ acpi_status status;
+ struct acpi_buffer buffer;
+
+
+ ACPI_FUNCTION_TRACE ("rs_set_srs_method_data");
+
+
+ /* Parameters guaranteed valid by caller */
+
+ /*
+ * The in_buffer parameter will point to a linked list of
+ * resource parameters. It needs to be formatted into a
+ * byte stream to be sent in as an input parameter to _SRS
+ *
+ * Convert the linked list into a byte stream
+ */
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+ status = acpi_rs_create_byte_stream (in_buffer->pointer, &buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Init the param object
+ */
+ params[0] = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
+ if (!params[0]) {
+ acpi_os_free (buffer.pointer);
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Set up the parameter object
+ */
+ params[0]->buffer.length = (u32) buffer.length;
+ params[0]->buffer.pointer = buffer.pointer;
+ params[0]->common.flags = AOPOBJ_DATA_VALID;
+ params[1] = NULL;
+
+ info.node = handle;
+ info.parameters = params;
+ info.parameter_type = ACPI_PARAM_ARGS;
+
+ /*
+ * Execute the method, no return value
+ */
+ status = acpi_ns_evaluate_relative ("_SRS", &info);
+ if (ACPI_SUCCESS (status)) {
+ /* Delete any return object (especially if implicit_return is enabled) */
+
+ if (info.return_object) {
+ acpi_ut_remove_reference (info.return_object);
+ }
+ }
+
+ /*
+ * Clean up and return the status from acpi_ns_evaluate_relative
+ */
+ acpi_ut_remove_reference (params[0]);
+ return_ACPI_STATUS (status);
+}
+
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
new file mode 100644
index 000000000000..a9cdcbeb3432
--- /dev/null
+++ b/drivers/acpi/resources/rsxface.c
@@ -0,0 +1,437 @@
+/*******************************************************************************
+ *
+ * Module Name: rsxface - Public interfaces to the resource manager
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acresrc.h>
+
+#define _COMPONENT ACPI_RESOURCES
+ ACPI_MODULE_NAME ("rsxface")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_irq_routing_table
+ *
+ * PARAMETERS: device_handle - a handle to the Bus device we are querying
+ * ret_buffer - a pointer to a buffer to receive the
+ * current resources for the device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the IRQ routing table for a
+ * specific bus. The caller must first acquire a handle for the
+ * desired bus. The routine table is placed in the buffer pointed
+ * to by the ret_buffer variable parameter.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of ret_buffer is undefined.
+ *
+ * This function attempts to execute the _PRT method contained in
+ * the object indicated by the passed device_handle.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_irq_routing_table (
+ acpi_handle device_handle,
+ struct acpi_buffer *ret_buffer)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_irq_routing_table ");
+
+
+ /*
+ * Must have a valid handle and buffer, So we have to have a handle
+ * and a return buffer structure, and if there is a non-zero buffer length
+ * we also need a valid pointer in the buffer. If it's a zero buffer length,
+ * we'll be returning the needed buffer size, so keep going.
+ */
+ if (!device_handle) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_validate_buffer (ret_buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_rs_get_prt_method_data (device_handle, ret_buffer);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_current_resources
+ *
+ * PARAMETERS: device_handle - a handle to the device object for the
+ * device we are querying
+ * ret_buffer - a pointer to a buffer to receive the
+ * current resources for the device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the current resources for a
+ * specific device. The caller must first acquire a handle for
+ * the desired device. The resource data is placed in the buffer
+ * pointed to by the ret_buffer variable parameter.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of ret_buffer is undefined.
+ *
+ * This function attempts to execute the _CRS method contained in
+ * the object indicated by the passed device_handle.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_current_resources (
+ acpi_handle device_handle,
+ struct acpi_buffer *ret_buffer)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_current_resources");
+
+
+ /*
+ * Must have a valid handle and buffer, So we have to have a handle
+ * and a return buffer structure, and if there is a non-zero buffer length
+ * we also need a valid pointer in the buffer. If it's a zero buffer length,
+ * we'll be returning the needed buffer size, so keep going.
+ */
+ if (!device_handle) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_validate_buffer (ret_buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_rs_get_crs_method_data (device_handle, ret_buffer);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_current_resources);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_possible_resources
+ *
+ * PARAMETERS: device_handle - a handle to the device object for the
+ * device we are querying
+ * ret_buffer - a pointer to a buffer to receive the
+ * resources for the device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get a list of the possible resources
+ * for a specific device. The caller must first acquire a handle
+ * for the desired device. The resource data is placed in the
+ * buffer pointed to by the ret_buffer variable.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of ret_buffer is undefined.
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_get_possible_resources (
+ acpi_handle device_handle,
+ struct acpi_buffer *ret_buffer)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_possible_resources");
+
+
+ /*
+ * Must have a valid handle and buffer, So we have to have a handle
+ * and a return buffer structure, and if there is a non-zero buffer length
+ * we also need a valid pointer in the buffer. If it's a zero buffer length,
+ * we'll be returning the needed buffer size, so keep going.
+ */
+ if (!device_handle) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_validate_buffer (ret_buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_rs_get_prs_method_data (device_handle, ret_buffer);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_possible_resources);
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_walk_resources
+ *
+ * PARAMETERS: device_handle - a handle to the device object for the
+ * device we are querying
+ * Path - method name of the resources we want
+ * (METHOD_NAME__CRS or METHOD_NAME__PRS)
+ * user_function - called for each resource
+ * Context - passed to user_function
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Retrieves the current or possible resource list for the
+ * specified device. The user_function is called once for
+ * each resource in the list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_walk_resources (
+ acpi_handle device_handle,
+ char *path,
+ ACPI_WALK_RESOURCE_CALLBACK user_function,
+ void *context)
+{
+ acpi_status status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ struct acpi_resource *resource;
+ struct acpi_resource *buffer_end;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_walk_resources");
+
+
+ if (!device_handle ||
+ (ACPI_STRNCMP (path, METHOD_NAME__CRS, sizeof (METHOD_NAME__CRS)) &&
+ ACPI_STRNCMP (path, METHOD_NAME__PRS, sizeof (METHOD_NAME__PRS)))) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_rs_get_method_data (device_handle, path, &buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Setup pointers */
+
+ resource = (struct acpi_resource *) buffer.pointer;
+ buffer_end = ACPI_CAST_PTR (struct acpi_resource,
+ ((u8 *) buffer.pointer + buffer.length));
+
+ /* Walk the resource list */
+
+ for (;;) {
+ if (!resource || resource->id == ACPI_RSTYPE_END_TAG) {
+ break;
+ }
+
+ status = user_function (resource, context);
+
+ switch (status) {
+ case AE_OK:
+ case AE_CTRL_DEPTH:
+
+ /* Just keep going */
+
+ status = AE_OK;
+ break;
+
+ case AE_CTRL_TERMINATE:
+
+ /* Exit now, with OK stats */
+
+ status = AE_OK;
+ goto cleanup;
+
+ default:
+
+ /* All others are valid exceptions */
+
+ goto cleanup;
+ }
+
+ /* Get the next resource descriptor */
+
+ resource = ACPI_NEXT_RESOURCE (resource);
+
+ /* Check for end-of-buffer */
+
+ if (resource >= buffer_end) {
+ goto cleanup;
+ }
+ }
+
+cleanup:
+
+ acpi_os_free (buffer.pointer);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_walk_resources);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_set_current_resources
+ *
+ * PARAMETERS: device_handle - a handle to the device object for the
+ * device we are changing the resources of
+ * in_buffer - a pointer to a buffer containing the
+ * resources to be set for the device
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to set the current resources for a
+ * specific device. The caller must first acquire a handle for
+ * the desired device. The resource data is passed to the routine
+ * the buffer pointed to by the in_buffer variable.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_set_current_resources (
+ acpi_handle device_handle,
+ struct acpi_buffer *in_buffer)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_set_current_resources");
+
+
+ /*
+ * Must have a valid handle and buffer
+ */
+ if ((!device_handle) ||
+ (!in_buffer) ||
+ (!in_buffer->pointer) ||
+ (!in_buffer->length)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_rs_set_srs_method_data (device_handle, in_buffer);
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_set_current_resources);
+
+
+#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field)
+#define ACPI_COPY_ADDRESS(out, in) \
+ ACPI_COPY_FIELD(out, in, resource_type); \
+ ACPI_COPY_FIELD(out, in, producer_consumer); \
+ ACPI_COPY_FIELD(out, in, decode); \
+ ACPI_COPY_FIELD(out, in, min_address_fixed); \
+ ACPI_COPY_FIELD(out, in, max_address_fixed); \
+ ACPI_COPY_FIELD(out, in, attribute); \
+ ACPI_COPY_FIELD(out, in, granularity); \
+ ACPI_COPY_FIELD(out, in, min_address_range); \
+ ACPI_COPY_FIELD(out, in, max_address_range); \
+ ACPI_COPY_FIELD(out, in, address_translation_offset); \
+ ACPI_COPY_FIELD(out, in, address_length); \
+ ACPI_COPY_FIELD(out, in, resource_source);
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_resource_to_address64
+ *
+ * PARAMETERS: resource - Pointer to a resource
+ * out - Pointer to the users's return
+ * buffer (a struct
+ * struct acpi_resource_address64)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: If the resource is an address16, address32, or address64,
+ * copy it to the address64 return buffer. This saves the
+ * caller from having to duplicate code for different-sized
+ * addresses.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_resource_to_address64 (
+ struct acpi_resource *resource,
+ struct acpi_resource_address64 *out)
+{
+ struct acpi_resource_address16 *address16;
+ struct acpi_resource_address32 *address32;
+
+
+ switch (resource->id) {
+ case ACPI_RSTYPE_ADDRESS16:
+
+ address16 = (struct acpi_resource_address16 *) &resource->data;
+ ACPI_COPY_ADDRESS(out, address16);
+ break;
+
+
+ case ACPI_RSTYPE_ADDRESS32:
+
+ address32 = (struct acpi_resource_address32 *) &resource->data;
+ ACPI_COPY_ADDRESS(out, address32);
+ break;
+
+
+ case ACPI_RSTYPE_ADDRESS64:
+
+ /* Simple copy for 64 bit source */
+
+ ACPI_MEMCPY (out, &resource->data, sizeof (struct acpi_resource_address64));
+ break;
+
+
+ default:
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (AE_OK);
+}
+EXPORT_SYMBOL(acpi_resource_to_address64);
+
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
new file mode 100644
index 000000000000..e7ca06626566
--- /dev/null
+++ b/drivers/acpi/scan.c
@@ -0,0 +1,1379 @@
+/*
+ * scan.c - support for transforming the ACPI namespace into individual objects
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+
+#include <acpi/acpi_drivers.h>
+#include <acpi/acinterp.h> /* for acpi_ex_eisa_id_to_string() */
+
+
+#define _COMPONENT ACPI_BUS_COMPONENT
+ACPI_MODULE_NAME ("scan")
+
+#define STRUCT_TO_INT(s) (*((int*)&s))
+
+extern struct acpi_device *acpi_root;
+
+
+#define ACPI_BUS_CLASS "system_bus"
+#define ACPI_BUS_HID "ACPI_BUS"
+#define ACPI_BUS_DRIVER_NAME "ACPI Bus Driver"
+#define ACPI_BUS_DEVICE_NAME "System Bus"
+
+static LIST_HEAD(acpi_device_list);
+DEFINE_SPINLOCK(acpi_device_lock);
+LIST_HEAD(acpi_wakeup_device_list);
+
+static int
+acpi_bus_trim(struct acpi_device *start,
+ int rmdevice);
+
+static void acpi_device_release(struct kobject * kobj)
+{
+ struct acpi_device * dev = container_of(kobj,struct acpi_device,kobj);
+ if (dev->pnp.cid_list)
+ kfree(dev->pnp.cid_list);
+ kfree(dev);
+}
+
+struct acpi_device_attribute {
+ struct attribute attr;
+ ssize_t (*show)(struct acpi_device *, char *);
+ ssize_t (*store)(struct acpi_device *, const char *, size_t);
+};
+
+typedef void acpi_device_sysfs_files(struct kobject *,
+ const struct attribute *);
+
+static void setup_sys_fs_device_files(struct acpi_device *dev,
+ acpi_device_sysfs_files *func);
+
+#define create_sysfs_device_files(dev) \
+ setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
+#define remove_sysfs_device_files(dev) \
+ setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
+
+
+#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
+#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
+
+static ssize_t acpi_device_attr_show(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct acpi_device *device = to_acpi_device(kobj);
+ struct acpi_device_attribute *attribute = to_handle_attr(attr);
+ return attribute->show ? attribute->show(device, buf) : 0;
+}
+static ssize_t acpi_device_attr_store(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t len)
+{
+ struct acpi_device *device = to_acpi_device(kobj);
+ struct acpi_device_attribute *attribute = to_handle_attr(attr);
+ return attribute->store ? attribute->store(device, buf, len) : len;
+}
+
+static struct sysfs_ops acpi_device_sysfs_ops = {
+ .show = acpi_device_attr_show,
+ .store = acpi_device_attr_store,
+};
+
+static struct kobj_type ktype_acpi_ns = {
+ .sysfs_ops = &acpi_device_sysfs_ops,
+ .release = acpi_device_release,
+};
+
+static int namespace_hotplug(struct kset *kset, struct kobject *kobj,
+ char **envp, int num_envp, char *buffer,
+ int buffer_size)
+{
+ struct acpi_device *dev = to_acpi_device(kobj);
+ int i = 0;
+ int len = 0;
+
+ if (!dev->driver)
+ return 0;
+
+ if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size, &len,
+ "PHYSDEVDRIVER=%s", dev->driver->name))
+ return -ENOMEM;
+
+ envp[i] = NULL;
+
+ return 0;
+}
+
+static struct kset_hotplug_ops namespace_hotplug_ops = {
+ .hotplug = &namespace_hotplug,
+};
+
+static struct kset acpi_namespace_kset = {
+ .kobj = {
+ .name = "namespace",
+ },
+ .subsys = &acpi_subsys,
+ .ktype = &ktype_acpi_ns,
+ .hotplug_ops = &namespace_hotplug_ops,
+};
+
+
+static void acpi_device_register(struct acpi_device * device, struct acpi_device * parent)
+{
+ /*
+ * Linkage
+ * -------
+ * Link this device to its parent and siblings.
+ */
+ INIT_LIST_HEAD(&device->children);
+ INIT_LIST_HEAD(&device->node);
+ INIT_LIST_HEAD(&device->g_list);
+ INIT_LIST_HEAD(&device->wakeup_list);
+
+ spin_lock(&acpi_device_lock);
+ if (device->parent) {
+ list_add_tail(&device->node, &device->parent->children);
+ list_add_tail(&device->g_list,&device->parent->g_list);
+ } else
+ list_add_tail(&device->g_list,&acpi_device_list);
+ if (device->wakeup.flags.valid)
+ list_add_tail(&device->wakeup_list,&acpi_wakeup_device_list);
+ spin_unlock(&acpi_device_lock);
+
+ strlcpy(device->kobj.name,device->pnp.bus_id,KOBJ_NAME_LEN);
+ if (parent)
+ device->kobj.parent = &parent->kobj;
+ device->kobj.ktype = &ktype_acpi_ns;
+ device->kobj.kset = &acpi_namespace_kset;
+ kobject_register(&device->kobj);
+ create_sysfs_device_files(device);
+}
+
+static int
+acpi_device_unregister (
+ struct acpi_device *device,
+ int type)
+{
+ spin_lock(&acpi_device_lock);
+ if (device->parent) {
+ list_del(&device->node);
+ list_del(&device->g_list);
+ } else
+ list_del(&device->g_list);
+
+ list_del(&device->wakeup_list);
+
+ spin_unlock(&acpi_device_lock);
+
+ acpi_detach_data(device->handle, acpi_bus_data_handler);
+ remove_sysfs_device_files(device);
+ kobject_unregister(&device->kobj);
+ return 0;
+}
+
+void
+acpi_bus_data_handler (
+ acpi_handle handle,
+ u32 function,
+ void *context)
+{
+ ACPI_FUNCTION_TRACE("acpi_bus_data_handler");
+
+ /* TBD */
+
+ return_VOID;
+}
+
+static int
+acpi_bus_get_power_flags (
+ struct acpi_device *device)
+{
+ acpi_status status = 0;
+ acpi_handle handle = NULL;
+ u32 i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_get_power_flags");
+
+ /*
+ * Power Management Flags
+ */
+ status = acpi_get_handle(device->handle, "_PSC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.explicit_get = 1;
+ status = acpi_get_handle(device->handle, "_IRC", &handle);
+ if (ACPI_SUCCESS(status))
+ device->power.flags.inrush_current = 1;
+
+ /*
+ * Enumerate supported power management states
+ */
+ for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
+ struct acpi_device_power_state *ps = &device->power.states[i];
+ char object_name[5] = {'_','P','R','0'+i,'\0'};
+
+ /* Evaluate "_PRx" to se if power resources are referenced */
+ acpi_evaluate_reference(device->handle, object_name, NULL,
+ &ps->resources);
+ if (ps->resources.count) {
+ device->power.flags.power_resources = 1;
+ ps->flags.valid = 1;
+ }
+
+ /* Evaluate "_PSx" to see if we can do explicit sets */
+ object_name[2] = 'S';
+ status = acpi_get_handle(device->handle, object_name, &handle);
+ if (ACPI_SUCCESS(status)) {
+ ps->flags.explicit_set = 1;
+ ps->flags.valid = 1;
+ }
+
+ /* State is valid if we have some power control */
+ if (ps->resources.count || ps->flags.explicit_set)
+ ps->flags.valid = 1;
+
+ ps->power = -1; /* Unknown - driver assigned */
+ ps->latency = -1; /* Unknown - driver assigned */
+ }
+
+ /* Set defaults for D0 and D3 states (always valid) */
+ device->power.states[ACPI_STATE_D0].flags.valid = 1;
+ device->power.states[ACPI_STATE_D0].power = 100;
+ device->power.states[ACPI_STATE_D3].flags.valid = 1;
+ device->power.states[ACPI_STATE_D3].power = 0;
+
+ /* TBD: System wake support and resource requirements. */
+
+ device->power.state = ACPI_STATE_UNKNOWN;
+
+ return_VALUE(0);
+}
+
+int
+acpi_match_ids (
+ struct acpi_device *device,
+ char *ids)
+{
+ int error = 0;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+ if (device->flags.hardware_id)
+ if (strstr(ids, device->pnp.hardware_id))
+ goto Done;
+
+ if (device->flags.compatible_ids) {
+ struct acpi_compatible_id_list *cid_list = device->pnp.cid_list;
+ int i;
+
+ /* compare multiple _CID entries against driver ids */
+ for (i = 0; i < cid_list->count; i++)
+ {
+ if (strstr(ids, cid_list->id[i].value))
+ goto Done;
+ }
+ }
+ error = -ENOENT;
+
+ Done:
+ if (buffer.pointer)
+ acpi_os_free(buffer.pointer);
+ return error;
+}
+
+static acpi_status
+acpi_bus_extract_wakeup_device_power_package (
+ struct acpi_device *device,
+ union acpi_object *package)
+{
+ int i = 0;
+ union acpi_object *element = NULL;
+
+ if (!device || !package || (package->package.count < 2))
+ return AE_BAD_PARAMETER;
+
+ element = &(package->package.elements[0]);
+ if (!element)
+ return AE_BAD_PARAMETER;
+ if (element->type == ACPI_TYPE_PACKAGE) {
+ if ((element->package.count < 2) ||
+ (element->package.elements[0].type != ACPI_TYPE_LOCAL_REFERENCE) ||
+ (element->package.elements[1].type != ACPI_TYPE_INTEGER))
+ return AE_BAD_DATA;
+ device->wakeup.gpe_device = element->package.elements[0].reference.handle;
+ device->wakeup.gpe_number = (u32)element->package.elements[1].integer.value;
+ }else if (element->type == ACPI_TYPE_INTEGER) {
+ device->wakeup.gpe_number = element->integer.value;
+ }else
+ return AE_BAD_DATA;
+
+ element = &(package->package.elements[1]);
+ if (element->type != ACPI_TYPE_INTEGER) {
+ return AE_BAD_DATA;
+ }
+ device->wakeup.sleep_state = element->integer.value;
+
+ if ((package->package.count - 2) > ACPI_MAX_HANDLES) {
+ return AE_NO_MEMORY;
+ }
+ device->wakeup.resources.count = package->package.count - 2;
+ for (i=0; i < device->wakeup.resources.count; i++) {
+ element = &(package->package.elements[i + 2]);
+ if (element->type != ACPI_TYPE_ANY ) {
+ return AE_BAD_DATA;
+ }
+
+ device->wakeup.resources.handles[i] = element->reference.handle;
+ }
+
+ return AE_OK;
+}
+
+static int
+acpi_bus_get_wakeup_device_flags (
+ struct acpi_device *device)
+{
+ acpi_status status = 0;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *package = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_get_wakeup_flags");
+
+ /* _PRW */
+ status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRW\n"));
+ goto end;
+ }
+
+ package = (union acpi_object *) buffer.pointer;
+ status = acpi_bus_extract_wakeup_device_power_package(device, package);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _PRW package\n"));
+ goto end;
+ }
+
+ acpi_os_free(buffer.pointer);
+
+ device->wakeup.flags.valid = 1;
+ /* Power button, Lid switch always enable wakeup*/
+ if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))
+ device->wakeup.flags.run_wake = 1;
+
+end:
+ if (ACPI_FAILURE(status))
+ device->flags.wake_capable = 0;
+ return_VALUE(0);
+}
+
+/* --------------------------------------------------------------------------
+ ACPI hotplug sysfs device file support
+ -------------------------------------------------------------------------- */
+static ssize_t acpi_eject_store(struct acpi_device *device,
+ const char *buf, size_t count);
+
+#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \
+static struct acpi_device_attribute acpi_device_attr_##_name = \
+ __ATTR(_name, _mode, _show, _store)
+
+ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
+
+/**
+ * setup_sys_fs_device_files - sets up the device files under device namespace
+ * @@dev: acpi_device object
+ * @@func: function pointer to create or destroy the device file
+ */
+static void
+setup_sys_fs_device_files (
+ struct acpi_device *dev,
+ acpi_device_sysfs_files *func)
+{
+ acpi_status status;
+ acpi_handle temp = NULL;
+
+ /*
+ * If device has _EJ0, 'eject' file is created that is used to trigger
+ * hot-removal function from userland.
+ */
+ status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ (*(func))(&dev->kobj,&acpi_device_attr_eject.attr);
+}
+
+static int
+acpi_eject_operation(acpi_handle handle, int lockable)
+{
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+ acpi_status status = AE_OK;
+
+ /*
+ * TBD: evaluate _PS3?
+ */
+
+ if (lockable) {
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 0;
+ acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+ }
+
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ /*
+ * TBD: _EJD support.
+ */
+
+ status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+ if (ACPI_FAILURE(status)) {
+ return(-ENODEV);
+ }
+
+ return(0);
+}
+
+
+static ssize_t
+acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
+{
+ int result;
+ int ret = count;
+ int islockable;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_object_type type = 0;
+
+ if ((!count) || (buf[0] != '1')) {
+ return -EINVAL;
+ }
+
+#ifndef FORCE_EJECT
+ if (device->driver == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+#endif
+ status = acpi_get_type(device->handle, &type);
+ if (ACPI_FAILURE(status) || (!device->flags.ejectable) ) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ islockable = device->flags.lockable;
+ handle = device->handle;
+
+ if (type == ACPI_TYPE_PROCESSOR)
+ result = acpi_bus_trim(device, 0);
+ else
+ result = acpi_bus_trim(device, 1);
+
+ if (!result)
+ result = acpi_eject_operation(handle, islockable);
+
+ if (result) {
+ ret = -EBUSY;
+ }
+err:
+ return ret;
+}
+
+
+/* --------------------------------------------------------------------------
+ Performance Management
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_bus_get_perf_flags (
+ struct acpi_device *device)
+{
+ device->performance.state = ACPI_STATE_UNKNOWN;
+ return 0;
+}
+
+/* --------------------------------------------------------------------------
+ Driver Management
+ -------------------------------------------------------------------------- */
+
+static LIST_HEAD(acpi_bus_drivers);
+static DECLARE_MUTEX(acpi_bus_drivers_lock);
+
+
+/**
+ * acpi_bus_match
+ * --------------
+ * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
+ * matches the specified driver's criteria.
+ */
+static int
+acpi_bus_match (
+ struct acpi_device *device,
+ struct acpi_driver *driver)
+{
+ if (driver && driver->ops.match)
+ return driver->ops.match(device, driver);
+ return acpi_match_ids(device, driver->ids);
+}
+
+
+/**
+ * acpi_bus_driver_init
+ * --------------------
+ * Used to initialize a device via its device driver. Called whenever a
+ * driver is bound to a device. Invokes the driver's add() and start() ops.
+ */
+static int
+acpi_bus_driver_init (
+ struct acpi_device *device,
+ struct acpi_driver *driver)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_driver_init");
+
+ if (!device || !driver)
+ return_VALUE(-EINVAL);
+
+ if (!driver->ops.add)
+ return_VALUE(-ENOSYS);
+
+ result = driver->ops.add(device);
+ if (result) {
+ device->driver = NULL;
+ acpi_driver_data(device) = NULL;
+ return_VALUE(result);
+ }
+
+ device->driver = driver;
+
+ /*
+ * TBD - Configuration Management: Assign resources to device based
+ * upon possible configuration and currently allocated resources.
+ */
+
+ if (driver->ops.start) {
+ result = driver->ops.start(device);
+ if (result && driver->ops.remove)
+ driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
+ return_VALUE(result);
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
+
+ if (driver->ops.scan) {
+ driver->ops.scan(device);
+ }
+
+ return_VALUE(0);
+}
+
+static int acpi_driver_attach(struct acpi_driver * drv)
+{
+ struct list_head * node, * next;
+ int count = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_driver_attach");
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node, next, &acpi_device_list) {
+ struct acpi_device * dev = container_of(node, struct acpi_device, g_list);
+
+ if (dev->driver || !dev->status.present)
+ continue;
+ spin_unlock(&acpi_device_lock);
+
+ if (!acpi_bus_match(dev, drv)) {
+ if (!acpi_bus_driver_init(dev, drv)) {
+ atomic_inc(&drv->references);
+ count++;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
+ drv->name, dev->pnp.bus_id));
+ }
+ }
+ spin_lock(&acpi_device_lock);
+ }
+ spin_unlock(&acpi_device_lock);
+ return_VALUE(count);
+}
+
+static int acpi_driver_detach(struct acpi_driver * drv)
+{
+ struct list_head * node, * next;
+
+ ACPI_FUNCTION_TRACE("acpi_driver_detach");
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node,next,&acpi_device_list) {
+ struct acpi_device * dev = container_of(node,struct acpi_device,g_list);
+
+ if (dev->driver == drv) {
+ spin_unlock(&acpi_device_lock);
+ if (drv->ops.remove)
+ drv->ops.remove(dev,ACPI_BUS_REMOVAL_NORMAL);
+ spin_lock(&acpi_device_lock);
+ dev->driver = NULL;
+ dev->driver_data = NULL;
+ atomic_dec(&drv->references);
+ }
+ }
+ spin_unlock(&acpi_device_lock);
+ return_VALUE(0);
+}
+
+/**
+ * acpi_bus_register_driver
+ * ------------------------
+ * Registers a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and binds. Returns the
+ * number of devices that were claimed by the driver, or a negative
+ * error status for failure.
+ */
+int
+acpi_bus_register_driver (
+ struct acpi_driver *driver)
+{
+ int count;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_register_driver");
+
+ if (acpi_disabled)
+ return_VALUE(-ENODEV);
+
+ if (!driver)
+ return_VALUE(-EINVAL);
+
+ spin_lock(&acpi_device_lock);
+ list_add_tail(&driver->node, &acpi_bus_drivers);
+ spin_unlock(&acpi_device_lock);
+ count = acpi_driver_attach(driver);
+
+ return_VALUE(count);
+}
+EXPORT_SYMBOL(acpi_bus_register_driver);
+
+
+/**
+ * acpi_bus_unregister_driver
+ * --------------------------
+ * Unregisters a driver with the ACPI bus. Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+int
+acpi_bus_unregister_driver (
+ struct acpi_driver *driver)
+{
+ int error = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_unregister_driver");
+
+ if (driver) {
+ acpi_driver_detach(driver);
+
+ if (!atomic_read(&driver->references)) {
+ spin_lock(&acpi_device_lock);
+ list_del_init(&driver->node);
+ spin_unlock(&acpi_device_lock);
+ }
+ } else
+ error = -EINVAL;
+ return_VALUE(error);
+}
+EXPORT_SYMBOL(acpi_bus_unregister_driver);
+
+/**
+ * acpi_bus_find_driver
+ * --------------------
+ * Parses the list of registered drivers looking for a driver applicable for
+ * the specified device.
+ */
+static int
+acpi_bus_find_driver (
+ struct acpi_device *device)
+{
+ int result = 0;
+ struct list_head * node, *next;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_find_driver");
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node,next,&acpi_bus_drivers) {
+ struct acpi_driver * driver = container_of(node,struct acpi_driver,node);
+
+ atomic_inc(&driver->references);
+ spin_unlock(&acpi_device_lock);
+ if (!acpi_bus_match(device, driver)) {
+ result = acpi_bus_driver_init(device, driver);
+ if (!result)
+ goto Done;
+ }
+ atomic_dec(&driver->references);
+ spin_lock(&acpi_device_lock);
+ }
+ spin_unlock(&acpi_device_lock);
+
+ Done:
+ return_VALUE(result);
+}
+
+
+/* --------------------------------------------------------------------------
+ Device Enumeration
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_bus_get_flags (
+ struct acpi_device *device)
+{
+ acpi_status status = AE_OK;
+ acpi_handle temp = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_get_flags");
+
+ /* Presence of _STA indicates 'dynamic_status' */
+ status = acpi_get_handle(device->handle, "_STA", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.dynamic_status = 1;
+
+ /* Presence of _CID indicates 'compatible_ids' */
+ status = acpi_get_handle(device->handle, "_CID", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.compatible_ids = 1;
+
+ /* Presence of _RMV indicates 'removable' */
+ status = acpi_get_handle(device->handle, "_RMV", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.removable = 1;
+
+ /* Presence of _EJD|_EJ0 indicates 'ejectable' */
+ status = acpi_get_handle(device->handle, "_EJD", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.ejectable = 1;
+ else {
+ status = acpi_get_handle(device->handle, "_EJ0", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.ejectable = 1;
+ }
+
+ /* Presence of _LCK indicates 'lockable' */
+ status = acpi_get_handle(device->handle, "_LCK", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.lockable = 1;
+
+ /* Presence of _PS0|_PR0 indicates 'power manageable' */
+ status = acpi_get_handle(device->handle, "_PS0", &temp);
+ if (ACPI_FAILURE(status))
+ status = acpi_get_handle(device->handle, "_PR0", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.power_manageable = 1;
+
+ /* Presence of _PRW indicates wake capable */
+ status = acpi_get_handle(device->handle, "_PRW", &temp);
+ if (ACPI_SUCCESS(status))
+ device->flags.wake_capable = 1;
+
+ /* TBD: Peformance management */
+
+ return_VALUE(0);
+}
+
+static void acpi_device_get_busid(struct acpi_device * device, acpi_handle handle, int type)
+{
+ char bus_id[5] = {'?',0};
+ struct acpi_buffer buffer = {sizeof(bus_id), bus_id};
+ int i = 0;
+
+ /*
+ * Bus ID
+ * ------
+ * The device's Bus ID is simply the object name.
+ * TBD: Shouldn't this value be unique (within the ACPI namespace)?
+ */
+ switch (type) {
+ case ACPI_BUS_TYPE_SYSTEM:
+ strcpy(device->pnp.bus_id, "ACPI");
+ break;
+ case ACPI_BUS_TYPE_POWER_BUTTON:
+ strcpy(device->pnp.bus_id, "PWRF");
+ break;
+ case ACPI_BUS_TYPE_SLEEP_BUTTON:
+ strcpy(device->pnp.bus_id, "SLPF");
+ break;
+ default:
+ acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
+ /* Clean up trailing underscores (if any) */
+ for (i = 3; i > 1; i--) {
+ if (bus_id[i] == '_')
+ bus_id[i] = '\0';
+ else
+ break;
+ }
+ strcpy(device->pnp.bus_id, bus_id);
+ break;
+ }
+}
+
+static void acpi_device_set_id(struct acpi_device * device, struct acpi_device * parent,
+ acpi_handle handle, int type)
+{
+ struct acpi_device_info *info;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ char *hid = NULL;
+ char *uid = NULL;
+ struct acpi_compatible_id_list *cid_list = NULL;
+ acpi_status status;
+
+ switch (type) {
+ case ACPI_BUS_TYPE_DEVICE:
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_FAILURE(status)) {
+ printk("%s: Error reading device info\n",__FUNCTION__);
+ return;
+ }
+
+ info = buffer.pointer;
+ if (info->valid & ACPI_VALID_HID)
+ hid = info->hardware_id.value;
+ if (info->valid & ACPI_VALID_UID)
+ uid = info->unique_id.value;
+ if (info->valid & ACPI_VALID_CID)
+ cid_list = &info->compatibility_id;
+ if (info->valid & ACPI_VALID_ADR) {
+ device->pnp.bus_address = info->address;
+ device->flags.bus_address = 1;
+ }
+ break;
+ case ACPI_BUS_TYPE_POWER:
+ hid = ACPI_POWER_HID;
+ break;
+ case ACPI_BUS_TYPE_PROCESSOR:
+ hid = ACPI_PROCESSOR_HID;
+ break;
+ case ACPI_BUS_TYPE_SYSTEM:
+ hid = ACPI_SYSTEM_HID;
+ break;
+ case ACPI_BUS_TYPE_THERMAL:
+ hid = ACPI_THERMAL_HID;
+ break;
+ case ACPI_BUS_TYPE_POWER_BUTTON:
+ hid = ACPI_BUTTON_HID_POWERF;
+ break;
+ case ACPI_BUS_TYPE_SLEEP_BUTTON:
+ hid = ACPI_BUTTON_HID_SLEEPF;
+ break;
+ }
+
+ /*
+ * \_SB
+ * ----
+ * Fix for the system root bus device -- the only root-level device.
+ */
+ if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
+ hid = ACPI_BUS_HID;
+ strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME);
+ strcpy(device->pnp.device_class, ACPI_BUS_CLASS);
+ }
+
+ if (hid) {
+ strcpy(device->pnp.hardware_id, hid);
+ device->flags.hardware_id = 1;
+ }
+ if (uid) {
+ strcpy(device->pnp.unique_id, uid);
+ device->flags.unique_id = 1;
+ }
+ if (cid_list) {
+ device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL);
+ if (device->pnp.cid_list)
+ memcpy(device->pnp.cid_list, cid_list, cid_list->size);
+ else
+ printk(KERN_ERR "Memory allocation error\n");
+ }
+
+ acpi_os_free(buffer.pointer);
+}
+
+static int acpi_device_set_context(struct acpi_device * device, int type)
+{
+ acpi_status status = AE_OK;
+ int result = 0;
+ /*
+ * Context
+ * -------
+ * Attach this 'struct acpi_device' to the ACPI object. This makes
+ * resolutions from handle->device very efficient. Note that we need
+ * to be careful with fixed-feature devices as they all attach to the
+ * root object.
+ */
+ if (type != ACPI_BUS_TYPE_POWER_BUTTON &&
+ type != ACPI_BUS_TYPE_SLEEP_BUTTON) {
+ status = acpi_attach_data(device->handle,
+ acpi_bus_data_handler, device);
+
+ if (ACPI_FAILURE(status)) {
+ printk("Error attaching device data\n");
+ result = -ENODEV;
+ }
+ }
+ return result;
+}
+
+static void acpi_device_get_debug_info(struct acpi_device * device, acpi_handle handle, int type)
+{
+#ifdef CONFIG_ACPI_DEBUG_OUTPUT
+ char *type_string = NULL;
+ char name[80] = {'?','\0'};
+ struct acpi_buffer buffer = {sizeof(name), name};
+
+ switch (type) {
+ case ACPI_BUS_TYPE_DEVICE:
+ type_string = "Device";
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ break;
+ case ACPI_BUS_TYPE_POWER:
+ type_string = "Power Resource";
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ break;
+ case ACPI_BUS_TYPE_PROCESSOR:
+ type_string = "Processor";
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ break;
+ case ACPI_BUS_TYPE_SYSTEM:
+ type_string = "System";
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ break;
+ case ACPI_BUS_TYPE_THERMAL:
+ type_string = "Thermal Zone";
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+ break;
+ case ACPI_BUS_TYPE_POWER_BUTTON:
+ type_string = "Power Button";
+ sprintf(name, "PWRB");
+ break;
+ case ACPI_BUS_TYPE_SLEEP_BUTTON:
+ type_string = "Sleep Button";
+ sprintf(name, "SLPB");
+ break;
+ }
+
+ printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle);
+#endif /*CONFIG_ACPI_DEBUG_OUTPUT*/
+}
+
+
+static int
+acpi_bus_remove (
+ struct acpi_device *dev,
+ int rmdevice)
+{
+ int result = 0;
+ struct acpi_driver *driver;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_remove");
+
+ if (!dev)
+ return_VALUE(-EINVAL);
+
+ driver = dev->driver;
+
+ if ((driver) && (driver->ops.remove)) {
+
+ if (driver->ops.stop) {
+ result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
+ if (result)
+ return_VALUE(result);
+ }
+
+ result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
+ if (result) {
+ return_VALUE(result);
+ }
+
+ atomic_dec(&dev->driver->references);
+ dev->driver = NULL;
+ acpi_driver_data(dev) = NULL;
+ }
+
+ if (!rmdevice)
+ return_VALUE(0);
+
+ if (dev->flags.bus_address) {
+ if ((dev->parent) && (dev->parent->ops.unbind))
+ dev->parent->ops.unbind(dev);
+ }
+
+ acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
+
+ return_VALUE(0);
+}
+
+
+int
+acpi_bus_add (
+ struct acpi_device **child,
+ struct acpi_device *parent,
+ acpi_handle handle,
+ int type)
+{
+ int result = 0;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_add");
+
+ if (!child)
+ return_VALUE(-EINVAL);
+
+ device = kmalloc(sizeof(struct acpi_device), GFP_KERNEL);
+ if (!device) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
+ return_VALUE(-ENOMEM);
+ }
+ memset(device, 0, sizeof(struct acpi_device));
+
+ device->handle = handle;
+ device->parent = parent;
+
+ acpi_device_get_busid(device,handle,type);
+
+ /*
+ * Flags
+ * -----
+ * Get prior to calling acpi_bus_get_status() so we know whether
+ * or not _STA is present. Note that we only look for object
+ * handles -- cannot evaluate objects until we know the device is
+ * present and properly initialized.
+ */
+ result = acpi_bus_get_flags(device);
+ if (result)
+ goto end;
+
+ /*
+ * Status
+ * ------
+ * See if the device is present. We always assume that non-Device()
+ * objects (e.g. thermal zones, power resources, processors, etc.) are
+ * present, functioning, etc. (at least when parent object is present).
+ * Note that _STA has a different meaning for some objects (e.g.
+ * power resources) so we need to be careful how we use it.
+ */
+ switch (type) {
+ case ACPI_BUS_TYPE_DEVICE:
+ result = acpi_bus_get_status(device);
+ if (ACPI_FAILURE(result) || !device->status.present) {
+ result = -ENOENT;
+ goto end;
+ }
+ break;
+ default:
+ STRUCT_TO_INT(device->status) = 0x0F;
+ break;
+ }
+
+ /*
+ * Initialize Device
+ * -----------------
+ * TBD: Synch with Core's enumeration/initialization process.
+ */
+
+ /*
+ * Hardware ID, Unique ID, & Bus Address
+ * -------------------------------------
+ */
+ acpi_device_set_id(device,parent,handle,type);
+
+ /*
+ * Power Management
+ * ----------------
+ */
+ if (device->flags.power_manageable) {
+ result = acpi_bus_get_power_flags(device);
+ if (result)
+ goto end;
+ }
+
+ /*
+ * Wakeup device management
+ *-----------------------
+ */
+ if (device->flags.wake_capable) {
+ result = acpi_bus_get_wakeup_device_flags(device);
+ if (result)
+ goto end;
+ }
+
+ /*
+ * Performance Management
+ * ----------------------
+ */
+ if (device->flags.performance_manageable) {
+ result = acpi_bus_get_perf_flags(device);
+ if (result)
+ goto end;
+ }
+
+ if ((result = acpi_device_set_context(device,type)))
+ goto end;
+
+ acpi_device_get_debug_info(device,handle,type);
+
+ acpi_device_register(device,parent);
+
+ /*
+ * Bind _ADR-Based Devices
+ * -----------------------
+ * If there's a a bus address (_ADR) then we utilize the parent's
+ * 'bind' function (if exists) to bind the ACPI- and natively-
+ * enumerated device representations.
+ */
+ if (device->flags.bus_address) {
+ if (device->parent && device->parent->ops.bind)
+ device->parent->ops.bind(device);
+ }
+
+ /*
+ * Locate & Attach Driver
+ * ----------------------
+ * If there's a hardware id (_HID) or compatible ids (_CID) we check
+ * to see if there's a driver installed for this kind of device. Note
+ * that drivers can install before or after a device is enumerated.
+ *
+ * TBD: Assumes LDM provides driver hot-plug capability.
+ */
+ acpi_bus_find_driver(device);
+
+end:
+ if (!result)
+ *child = device;
+ else {
+ if (device->pnp.cid_list)
+ kfree(device->pnp.cid_list);
+ kfree(device);
+ }
+
+ return_VALUE(result);
+}
+EXPORT_SYMBOL(acpi_bus_add);
+
+
+int acpi_bus_scan (struct acpi_device *start)
+{
+ acpi_status status = AE_OK;
+ struct acpi_device *parent = NULL;
+ struct acpi_device *child = NULL;
+ acpi_handle phandle = NULL;
+ acpi_handle chandle = NULL;
+ acpi_object_type type = 0;
+ u32 level = 1;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_scan");
+
+ if (!start)
+ return_VALUE(-EINVAL);
+
+ parent = start;
+ phandle = start->handle;
+
+ /*
+ * Parse through the ACPI namespace, identify all 'devices', and
+ * create a new 'struct acpi_device' for each.
+ */
+ while ((level > 0) && parent) {
+
+ status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
+ chandle, &chandle);
+
+ /*
+ * If this scope is exhausted then move our way back up.
+ */
+ if (ACPI_FAILURE(status)) {
+ level--;
+ chandle = phandle;
+ acpi_get_parent(phandle, &phandle);
+ if (parent->parent)
+ parent = parent->parent;
+ continue;
+ }
+
+ status = acpi_get_type(chandle, &type);
+ if (ACPI_FAILURE(status))
+ continue;
+
+ /*
+ * If this is a scope object then parse it (depth-first).
+ */
+ if (type == ACPI_TYPE_LOCAL_SCOPE) {
+ level++;
+ phandle = chandle;
+ chandle = NULL;
+ continue;
+ }
+
+ /*
+ * We're only interested in objects that we consider 'devices'.
+ */
+ switch (type) {
+ case ACPI_TYPE_DEVICE:
+ type = ACPI_BUS_TYPE_DEVICE;
+ break;
+ case ACPI_TYPE_PROCESSOR:
+ type = ACPI_BUS_TYPE_PROCESSOR;
+ break;
+ case ACPI_TYPE_THERMAL:
+ type = ACPI_BUS_TYPE_THERMAL;
+ break;
+ case ACPI_TYPE_POWER:
+ type = ACPI_BUS_TYPE_POWER;
+ break;
+ default:
+ continue;
+ }
+
+ status = acpi_bus_add(&child, parent, chandle, type);
+ if (ACPI_FAILURE(status))
+ continue;
+
+ /*
+ * If the device is present, enabled, and functioning then
+ * parse its scope (depth-first). Note that we need to
+ * represent absent devices to facilitate PnP notifications
+ * -- but only the subtree head (not all of its children,
+ * which will be enumerated when the parent is inserted).
+ *
+ * TBD: Need notifications and other detection mechanisms
+ * in place before we can fully implement this.
+ */
+ if (child->status.present) {
+ status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
+ NULL, NULL);
+ if (ACPI_SUCCESS(status)) {
+ level++;
+ phandle = chandle;
+ chandle = NULL;
+ parent = child;
+ }
+ }
+ }
+
+ return_VALUE(0);
+}
+EXPORT_SYMBOL(acpi_bus_scan);
+
+
+static int
+acpi_bus_trim(struct acpi_device *start,
+ int rmdevice)
+{
+ acpi_status status;
+ struct acpi_device *parent, *child;
+ acpi_handle phandle, chandle;
+ acpi_object_type type;
+ u32 level = 1;
+ int err = 0;
+
+ parent = start;
+ phandle = start->handle;
+ child = chandle = NULL;
+
+ while ((level > 0) && parent && (!err)) {
+ status = acpi_get_next_object(ACPI_TYPE_ANY, phandle,
+ chandle, &chandle);
+
+ /*
+ * If this scope is exhausted then move our way back up.
+ */
+ if (ACPI_FAILURE(status)) {
+ level--;
+ chandle = phandle;
+ acpi_get_parent(phandle, &phandle);
+ child = parent;
+ parent = parent->parent;
+
+ if (level == 0)
+ err = acpi_bus_remove(child, rmdevice);
+ else
+ err = acpi_bus_remove(child, 1);
+
+ continue;
+ }
+
+ status = acpi_get_type(chandle, &type);
+ if (ACPI_FAILURE(status)) {
+ continue;
+ }
+ /*
+ * If there is a device corresponding to chandle then
+ * parse it (depth-first).
+ */
+ if (acpi_bus_get_device(chandle, &child) == 0) {
+ level++;
+ phandle = chandle;
+ chandle = NULL;
+ parent = child;
+ }
+ continue;
+ }
+ return err;
+}
+
+static int
+acpi_bus_scan_fixed (
+ struct acpi_device *root)
+{
+ int result = 0;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_scan_fixed");
+
+ if (!root)
+ return_VALUE(-ENODEV);
+
+ /*
+ * Enumerate all fixed-feature devices.
+ */
+ if (acpi_fadt.pwr_button == 0)
+ result = acpi_bus_add(&device, acpi_root,
+ NULL, ACPI_BUS_TYPE_POWER_BUTTON);
+
+ if (acpi_fadt.sleep_button == 0)
+ result = acpi_bus_add(&device, acpi_root,
+ NULL, ACPI_BUS_TYPE_SLEEP_BUTTON);
+
+ return_VALUE(result);
+}
+
+
+static int __init acpi_scan_init(void)
+{
+ int result;
+
+ ACPI_FUNCTION_TRACE("acpi_scan_init");
+
+ if (acpi_disabled)
+ return_VALUE(0);
+
+ kset_register(&acpi_namespace_kset);
+
+ /*
+ * Create the root device in the bus's device tree
+ */
+ result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT,
+ ACPI_BUS_TYPE_SYSTEM);
+ if (result)
+ goto Done;
+
+ /*
+ * Enumerate devices in the ACPI namespace.
+ */
+ result = acpi_bus_scan_fixed(acpi_root);
+ if (!result)
+ result = acpi_bus_scan(acpi_root);
+
+ if (result)
+ acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
+
+ Done:
+ return_VALUE(result);
+}
+
+subsys_initcall(acpi_scan_init);
diff --git a/drivers/acpi/sleep/Makefile b/drivers/acpi/sleep/Makefile
new file mode 100644
index 000000000000..d6c017709c85
--- /dev/null
+++ b/drivers/acpi/sleep/Makefile
@@ -0,0 +1,5 @@
+obj-y := poweroff.o wakeup.o
+obj-$(CONFIG_ACPI_SLEEP) += main.o
+obj-$(CONFIG_ACPI_SLEEP_PROC_FS) += proc.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
new file mode 100644
index 000000000000..0a5d2a94131e
--- /dev/null
+++ b/drivers/acpi/sleep/main.c
@@ -0,0 +1,234 @@
+/*
+ * sleep.c - ACPI sleep support.
+ *
+ * Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
+ * Copyright (c) 2000-2003 Patrick Mochel
+ * Copyright (c) 2003 Open Source Development Lab
+ *
+ * This file is released under the GPLv2.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/dmi.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <asm/io.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include "sleep.h"
+
+u8 sleep_states[ACPI_S_STATE_COUNT];
+
+static struct pm_ops acpi_pm_ops;
+
+extern void do_suspend_lowlevel_s4bios(void);
+extern void do_suspend_lowlevel(void);
+
+static u32 acpi_suspend_states[] = {
+ [PM_SUSPEND_ON] = ACPI_STATE_S0,
+ [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
+ [PM_SUSPEND_MEM] = ACPI_STATE_S3,
+ [PM_SUSPEND_DISK] = ACPI_STATE_S4,
+};
+
+static int init_8259A_after_S1;
+
+/**
+ * acpi_pm_prepare - Do preliminary suspend work.
+ * @pm_state: suspend state we're entering.
+ *
+ * Make sure we support the state. If we do, and we need it, set the
+ * firmware waking vector and do arch-specific nastiness to get the
+ * wakeup code to the waking vector.
+ */
+
+static int acpi_pm_prepare(suspend_state_t pm_state)
+{
+ u32 acpi_state = acpi_suspend_states[pm_state];
+
+ if (!sleep_states[acpi_state])
+ return -EPERM;
+
+ /* do we have a wakeup address for S2 and S3? */
+ /* Here, we support only S4BIOS, those we set the wakeup address */
+ /* S4OS is only supported for now via swsusp.. */
+ if (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) {
+ if (!acpi_wakeup_address)
+ return -EFAULT;
+ acpi_set_firmware_waking_vector(
+ (acpi_physical_address) virt_to_phys(
+ (void *)acpi_wakeup_address));
+ }
+ ACPI_FLUSH_CPU_CACHE();
+ acpi_enable_wakeup_device_prep(acpi_state);
+ acpi_enter_sleep_state_prep(acpi_state);
+ return 0;
+}
+
+
+/**
+ * acpi_pm_enter - Actually enter a sleep state.
+ * @pm_state: State we're entering.
+ *
+ * Flush caches and go to sleep. For STR or STD, we have to call
+ * arch-specific assembly, which in turn call acpi_enter_sleep_state().
+ * It's unfortunate, but it works. Please fix if you're feeling frisky.
+ */
+
+static int acpi_pm_enter(suspend_state_t pm_state)
+{
+ acpi_status status = AE_OK;
+ unsigned long flags = 0;
+ u32 acpi_state = acpi_suspend_states[pm_state];
+
+ ACPI_FLUSH_CPU_CACHE();
+
+ /* Do arch specific saving of state. */
+ if (pm_state > PM_SUSPEND_STANDBY) {
+ int error = acpi_save_state_mem();
+ if (error)
+ return error;
+ }
+
+
+ local_irq_save(flags);
+ acpi_enable_wakeup_device(acpi_state);
+ switch (pm_state)
+ {
+ case PM_SUSPEND_STANDBY:
+ barrier();
+ status = acpi_enter_sleep_state(acpi_state);
+ break;
+
+ case PM_SUSPEND_MEM:
+ do_suspend_lowlevel();
+ break;
+
+ case PM_SUSPEND_DISK:
+ if (acpi_pm_ops.pm_disk_mode == PM_DISK_PLATFORM)
+ status = acpi_enter_sleep_state(acpi_state);
+ else
+ do_suspend_lowlevel_s4bios();
+ break;
+ default:
+ return -EINVAL;
+ }
+ local_irq_restore(flags);
+ printk(KERN_DEBUG "Back to C!\n");
+
+ /* restore processor state
+ * We should only be here if we're coming back from STR or STD.
+ * And, in the case of the latter, the memory image should have already
+ * been loaded from disk.
+ */
+ if (pm_state > PM_SUSPEND_STANDBY)
+ acpi_restore_state_mem();
+
+
+ return ACPI_SUCCESS(status) ? 0 : -EFAULT;
+}
+
+
+/**
+ * acpi_pm_finish - Finish up suspend sequence.
+ * @pm_state: State we're coming out of.
+ *
+ * This is called after we wake back up (or if entering the sleep state
+ * failed).
+ */
+
+static int acpi_pm_finish(suspend_state_t pm_state)
+{
+ u32 acpi_state = acpi_suspend_states[pm_state];
+
+ acpi_leave_sleep_state(acpi_state);
+ acpi_disable_wakeup_device(acpi_state);
+
+ /* reset firmware waking vector */
+ acpi_set_firmware_waking_vector((acpi_physical_address) 0);
+
+ if (init_8259A_after_S1) {
+ printk("Broken toshiba laptop -> kicking interrupts\n");
+ init_8259A(0);
+ }
+ return 0;
+}
+
+
+int acpi_suspend(u32 acpi_state)
+{
+ suspend_state_t states[] = {
+ [1] = PM_SUSPEND_STANDBY,
+ [3] = PM_SUSPEND_MEM,
+ [4] = PM_SUSPEND_DISK,
+ };
+
+ if (acpi_state <= 4 && states[acpi_state])
+ return pm_suspend(states[acpi_state]);
+ return -EINVAL;
+}
+
+static struct pm_ops acpi_pm_ops = {
+ .prepare = acpi_pm_prepare,
+ .enter = acpi_pm_enter,
+ .finish = acpi_pm_finish,
+};
+
+
+/*
+ * Toshiba fails to preserve interrupts over S1, reinitialization
+ * of 8259 is needed after S1 resume.
+ */
+static int __init init_ints_after_s1(struct dmi_system_id *d)
+{
+ printk(KERN_WARNING "%s with broken S1 detected.\n", d->ident);
+ init_8259A_after_S1 = 1;
+ return 0;
+}
+
+static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
+ {
+ .callback = init_ints_after_s1,
+ .ident = "Toshiba Satellite 4030cdt",
+ .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), },
+ },
+ { },
+};
+
+static int __init acpi_sleep_init(void)
+{
+ int i = 0;
+
+ dmi_check_system(acpisleep_dmi_table);
+
+ if (acpi_disabled)
+ return 0;
+
+ printk(KERN_INFO PREFIX "(supports");
+ for (i=0; i < ACPI_S_STATE_COUNT; i++) {
+ acpi_status status;
+ u8 type_a, type_b;
+ status = acpi_get_sleep_type_data(i, &type_a, &type_b);
+ if (ACPI_SUCCESS(status)) {
+ sleep_states[i] = 1;
+ printk(" S%d", i);
+ }
+ if (i == ACPI_STATE_S4) {
+ if (acpi_gbl_FACS->S4bios_f) {
+ sleep_states[i] = 1;
+ printk(" S4bios");
+ acpi_pm_ops.pm_disk_mode = PM_DISK_FIRMWARE;
+ }
+ if (sleep_states[i])
+ acpi_pm_ops.pm_disk_mode = PM_DISK_PLATFORM;
+ }
+ }
+ printk(")\n");
+
+ pm_set_ops(&acpi_pm_ops);
+ return 0;
+}
+
+late_initcall(acpi_sleep_init);
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
new file mode 100644
index 000000000000..da237754ded9
--- /dev/null
+++ b/drivers/acpi/sleep/poweroff.c
@@ -0,0 +1,39 @@
+/*
+ * poweroff.c - ACPI handler for powering off the system.
+ *
+ * AKA S5, but it is independent of whether or not the kernel supports
+ * any other sleep support in the system.
+ */
+
+#include <linux/pm.h>
+#include <linux/init.h>
+#include <acpi/acpi_bus.h>
+#include <linux/sched.h>
+#include "sleep.h"
+
+static void
+acpi_power_off (void)
+{
+ printk("%s called\n",__FUNCTION__);
+ /* Some SMP machines only can poweroff in boot CPU */
+ set_cpus_allowed(current, cpumask_of_cpu(0));
+ acpi_wakeup_gpe_poweroff_prepare();
+ acpi_enter_sleep_state_prep(ACPI_STATE_S5);
+ ACPI_DISABLE_IRQS();
+ acpi_enter_sleep_state(ACPI_STATE_S5);
+}
+
+static int acpi_poweroff_init(void)
+{
+ if (!acpi_disabled) {
+ u8 type_a, type_b;
+ acpi_status status;
+
+ status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
+ if (ACPI_SUCCESS(status))
+ pm_power_off = acpi_power_off;
+ }
+ return 0;
+}
+
+late_initcall(acpi_poweroff_init);
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
new file mode 100644
index 000000000000..fd7c5a0649af
--- /dev/null
+++ b/drivers/acpi/sleep/proc.c
@@ -0,0 +1,509 @@
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/suspend.h>
+#include <linux/bcd.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#ifdef CONFIG_X86
+#include <linux/mc146818rtc.h>
+#endif
+
+#include "sleep.h"
+
+#define ACPI_SYSTEM_FILE_SLEEP "sleep"
+#define ACPI_SYSTEM_FILE_ALARM "alarm"
+#define ACPI_SYSTEM_FILE_WAKEUP_DEVICE "wakeup"
+
+#define _COMPONENT ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME ("sleep")
+
+
+static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
+{
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_system_sleep_seq_show");
+
+ for (i = 0; i <= ACPI_STATE_S5; i++) {
+ if (sleep_states[i]) {
+ seq_printf(seq,"S%d ", i);
+ if (i == ACPI_STATE_S4 && acpi_gbl_FACS->S4bios_f)
+ seq_printf(seq, "S4bios ");
+ }
+ }
+
+ seq_puts(seq, "\n");
+
+ return 0;
+}
+
+static int acpi_system_sleep_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_system_sleep_seq_show, PDE(inode)->data);
+}
+
+static ssize_t
+acpi_system_write_sleep (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ char str[12];
+ u32 state = 0;
+ int error = 0;
+
+ if (count > sizeof(str) - 1)
+ goto Done;
+ memset(str,0,sizeof(str));
+ if (copy_from_user(str, buffer, count))
+ return -EFAULT;
+
+ /* Check for S4 bios request */
+ if (!strcmp(str,"4b")) {
+ error = acpi_suspend(4);
+ goto Done;
+ }
+ state = simple_strtoul(str, NULL, 0);
+#ifdef CONFIG_SOFTWARE_SUSPEND
+ if (state == 4) {
+ error = software_suspend();
+ goto Done;
+ }
+#endif
+ error = acpi_suspend(state);
+ Done:
+ return error ? error : count;
+}
+
+static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
+{
+ u32 sec, min, hr;
+ u32 day, mo, yr;
+ unsigned char rtc_control = 0;
+ unsigned long flags;
+
+ ACPI_FUNCTION_TRACE("acpi_system_alarm_seq_show");
+
+ spin_lock_irqsave(&rtc_lock, flags);
+
+ sec = CMOS_READ(RTC_SECONDS_ALARM);
+ min = CMOS_READ(RTC_MINUTES_ALARM);
+ hr = CMOS_READ(RTC_HOURS_ALARM);
+ rtc_control = CMOS_READ(RTC_CONTROL);
+
+ /* If we ever get an FACP with proper values... */
+ if (acpi_gbl_FADT->day_alrm)
+ /* ACPI spec: only low 6 its should be cared */
+ day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
+ else
+ day = CMOS_READ(RTC_DAY_OF_MONTH);
+ if (acpi_gbl_FADT->mon_alrm)
+ mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+ else
+ mo = CMOS_READ(RTC_MONTH);
+ if (acpi_gbl_FADT->century)
+ yr = CMOS_READ(acpi_gbl_FADT->century) * 100 + CMOS_READ(RTC_YEAR);
+ else
+ yr = CMOS_READ(RTC_YEAR);
+
+ spin_unlock_irqrestore(&rtc_lock, flags);
+
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BCD_TO_BIN(sec);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(hr);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(mo);
+ BCD_TO_BIN(yr);
+ }
+
+ /* we're trusting the FADT (see above)*/
+ if (!acpi_gbl_FADT->century)
+ /* If we're not trusting the FADT, we should at least make it
+ * right for _this_ century... ehm, what is _this_ century?
+ *
+ * TBD:
+ * ASAP: find piece of code in the kernel, e.g. star tracker driver,
+ * which we can trust to determine the century correctly. Atom
+ * watch driver would be nice, too...
+ *
+ * if that has not happened, change for first release in 2050:
+ * if (yr<50)
+ * yr += 2100;
+ * else
+ * yr += 2000; // current line of code
+ *
+ * if that has not happened either, please do on 2099/12/31:23:59:59
+ * s/2000/2100
+ *
+ */
+ yr += 2000;
+
+ seq_printf(seq,"%4.4u-", yr);
+ (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
+ (day > 31) ? seq_puts(seq, "** ") : seq_printf(seq, "%2.2u ", day);
+ (hr > 23) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", hr);
+ (min > 59) ? seq_puts(seq, "**:") : seq_printf(seq, "%2.2u:", min);
+ (sec > 59) ? seq_puts(seq, "**\n") : seq_printf(seq, "%2.2u\n", sec);
+
+ return 0;
+}
+
+static int acpi_system_alarm_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_system_alarm_seq_show, PDE(inode)->data);
+}
+
+
+static int
+get_date_field (
+ char **p,
+ u32 *value)
+{
+ char *next = NULL;
+ char *string_end = NULL;
+ int result = -EINVAL;
+
+ /*
+ * Try to find delimeter, only to insert null. The end of the
+ * string won't have one, but is still valid.
+ */
+ next = strpbrk(*p, "- :");
+ if (next)
+ *next++ = '\0';
+
+ *value = simple_strtoul(*p, &string_end, 10);
+
+ /* Signal success if we got a good digit */
+ if (string_end != *p)
+ result = 0;
+
+ if (next)
+ *p = next;
+
+ return result;
+}
+
+
+static ssize_t
+acpi_system_write_alarm (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ int result = 0;
+ char alarm_string[30] = {'\0'};
+ char *p = alarm_string;
+ u32 sec, min, hr, day, mo, yr;
+ int adjust = 0;
+ unsigned char rtc_control = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_system_write_alarm");
+
+ if (count > sizeof(alarm_string) - 1)
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(alarm_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ alarm_string[count] = '\0';
+
+ /* check for time adjustment */
+ if (alarm_string[0] == '+') {
+ p++;
+ adjust = 1;
+ }
+
+ if ((result = get_date_field(&p, &yr)))
+ goto end;
+ if ((result = get_date_field(&p, &mo)))
+ goto end;
+ if ((result = get_date_field(&p, &day)))
+ goto end;
+ if ((result = get_date_field(&p, &hr)))
+ goto end;
+ if ((result = get_date_field(&p, &min)))
+ goto end;
+ if ((result = get_date_field(&p, &sec)))
+ goto end;
+
+ if (sec > 59) {
+ min += 1;
+ sec -= 60;
+ }
+ if (min > 59) {
+ hr += 1;
+ min -= 60;
+ }
+ if (hr > 23) {
+ day += 1;
+ hr -= 24;
+ }
+ if (day > 31) {
+ mo += 1;
+ day -= 31;
+ }
+ if (mo > 12) {
+ yr += 1;
+ mo -= 12;
+ }
+
+ spin_lock_irq(&rtc_lock);
+
+ rtc_control = CMOS_READ(RTC_CONTROL);
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(yr);
+ BIN_TO_BCD(mo);
+ BIN_TO_BCD(day);
+ BIN_TO_BCD(hr);
+ BIN_TO_BCD(min);
+ BIN_TO_BCD(sec);
+ }
+
+ if (adjust) {
+ yr += CMOS_READ(RTC_YEAR);
+ mo += CMOS_READ(RTC_MONTH);
+ day += CMOS_READ(RTC_DAY_OF_MONTH);
+ hr += CMOS_READ(RTC_HOURS);
+ min += CMOS_READ(RTC_MINUTES);
+ sec += CMOS_READ(RTC_SECONDS);
+ }
+
+ spin_unlock_irq(&rtc_lock);
+
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BCD_TO_BIN(yr);
+ BCD_TO_BIN(mo);
+ BCD_TO_BIN(day);
+ BCD_TO_BIN(hr);
+ BCD_TO_BIN(min);
+ BCD_TO_BIN(sec);
+ }
+
+ if (sec > 59) {
+ min++;
+ sec -= 60;
+ }
+ if (min > 59) {
+ hr++;
+ min -= 60;
+ }
+ if (hr > 23) {
+ day++;
+ hr -= 24;
+ }
+ if (day > 31) {
+ mo++;
+ day -= 31;
+ }
+ if (mo > 12) {
+ yr++;
+ mo -= 12;
+ }
+ if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
+ BIN_TO_BCD(yr);
+ BIN_TO_BCD(mo);
+ BIN_TO_BCD(day);
+ BIN_TO_BCD(hr);
+ BIN_TO_BCD(min);
+ BIN_TO_BCD(sec);
+ }
+
+ spin_lock_irq(&rtc_lock);
+ /*
+ * Disable alarm interrupt before setting alarm timer or else
+ * when ACPI_EVENT_RTC is enabled, a spurious ACPI interrupt occurs
+ */
+ rtc_control &= ~RTC_AIE;
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+
+ /* write the fields the rtc knows about */
+ CMOS_WRITE(hr, RTC_HOURS_ALARM);
+ CMOS_WRITE(min, RTC_MINUTES_ALARM);
+ CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+
+ /*
+ * If the system supports an enhanced alarm it will have non-zero
+ * offsets into the CMOS RAM here -- which for some reason are pointing
+ * to the RTC area of memory.
+ */
+ if (acpi_gbl_FADT->day_alrm)
+ CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
+ if (acpi_gbl_FADT->mon_alrm)
+ CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
+ if (acpi_gbl_FADT->century)
+ CMOS_WRITE(yr/100, acpi_gbl_FADT->century);
+ /* enable the rtc alarm interrupt */
+ rtc_control |= RTC_AIE;
+ CMOS_WRITE(rtc_control, RTC_CONTROL);
+ CMOS_READ(RTC_INTR_FLAGS);
+
+ spin_unlock_irq(&rtc_lock);
+
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_enable_event(ACPI_EVENT_RTC, 0);
+
+ *ppos += count;
+
+ result = 0;
+end:
+ return_VALUE(result ? result : count);
+}
+
+extern struct list_head acpi_wakeup_device_list;
+extern spinlock_t acpi_device_lock;
+
+static int
+acpi_system_wakeup_device_seq_show(struct seq_file *seq, void *offset)
+{
+ struct list_head * node, * next;
+
+ seq_printf(seq, "Device Sleep state Status\n");
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+
+ if (!dev->wakeup.flags.valid)
+ continue;
+ spin_unlock(&acpi_device_lock);
+ if (dev->wakeup.flags.run_wake)
+ seq_printf(seq, "%4s %4d %8s\n",
+ dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
+ dev->wakeup.state.enabled ? "*enabled" : "*disabled");
+ else
+ seq_printf(seq, "%4s %4d %8s\n",
+ dev->pnp.bus_id, (u32) dev->wakeup.sleep_state,
+ dev->wakeup.state.enabled ? "enabled" : "disabled");
+ spin_lock(&acpi_device_lock);
+ }
+ spin_unlock(&acpi_device_lock);
+ return 0;
+}
+
+static ssize_t
+acpi_system_write_wakeup_device (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ struct list_head * node, * next;
+ char strbuf[5];
+ char str[5] = "";
+ int len = count;
+ struct acpi_device *found_dev = NULL;
+
+ if (len > 4) len = 4;
+
+ if (copy_from_user(strbuf, buffer, len))
+ return -EFAULT;
+ strbuf[len] = '\0';
+ sscanf(strbuf, "%s", str);
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node, struct acpi_device, wakeup_list);
+ if (!dev->wakeup.flags.valid)
+ continue;
+
+ if (!strncmp(dev->pnp.bus_id, str, 4)) {
+ dev->wakeup.state.enabled = dev->wakeup.state.enabled ? 0:1;
+ found_dev = dev;
+ break;
+ }
+ }
+ if (found_dev) {
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node,
+ struct acpi_device, wakeup_list);
+
+ if ((dev != found_dev) &&
+ (dev->wakeup.gpe_number == found_dev->wakeup.gpe_number) &&
+ (dev->wakeup.gpe_device == found_dev->wakeup.gpe_device)) {
+ printk(KERN_WARNING "ACPI: '%s' and '%s' have the same GPE, "
+ "can't disable/enable one seperately\n",
+ dev->pnp.bus_id, found_dev->pnp.bus_id);
+ dev->wakeup.state.enabled = found_dev->wakeup.state.enabled;
+ }
+ }
+ }
+ spin_unlock(&acpi_device_lock);
+ return count;
+}
+
+static int
+acpi_system_wakeup_device_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_system_wakeup_device_seq_show, PDE(inode)->data);
+}
+
+static struct file_operations acpi_system_wakeup_device_fops = {
+ .open = acpi_system_wakeup_device_open_fs,
+ .read = seq_read,
+ .write = acpi_system_write_wakeup_device,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct file_operations acpi_system_sleep_fops = {
+ .open = acpi_system_sleep_open_fs,
+ .read = seq_read,
+ .write = acpi_system_write_sleep,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct file_operations acpi_system_alarm_fops = {
+ .open = acpi_system_alarm_open_fs,
+ .read = seq_read,
+ .write = acpi_system_write_alarm,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+static u32 rtc_handler(void * context)
+{
+ acpi_clear_event(ACPI_EVENT_RTC);
+ acpi_disable_event(ACPI_EVENT_RTC, 0);
+
+ return ACPI_INTERRUPT_HANDLED;
+}
+
+static int acpi_sleep_proc_init(void)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ if (acpi_disabled)
+ return 0;
+
+ /* 'sleep' [R/W]*/
+ entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+ if (entry)
+ entry->proc_fops = &acpi_system_sleep_fops;
+
+ /* 'alarm' [R/W] */
+ entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+ if (entry)
+ entry->proc_fops = &acpi_system_alarm_fops;
+
+ /* 'wakeup device' [R/W]*/
+ entry = create_proc_entry(ACPI_SYSTEM_FILE_WAKEUP_DEVICE,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
+ if (entry)
+ entry->proc_fops = &acpi_system_wakeup_device_fops;
+
+ acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+ return 0;
+}
+
+late_initcall(acpi_sleep_proc_init);
diff --git a/drivers/acpi/sleep/sleep.h b/drivers/acpi/sleep/sleep.h
new file mode 100644
index 000000000000..efd0001c6f05
--- /dev/null
+++ b/drivers/acpi/sleep/sleep.h
@@ -0,0 +1,8 @@
+
+extern u8 sleep_states[];
+extern int acpi_suspend (u32 state);
+
+extern void acpi_enable_wakeup_device_prep(u8 sleep_state);
+extern void acpi_enable_wakeup_device(u8 sleep_state);
+extern void acpi_disable_wakeup_device(u8 sleep_state);
+extern void acpi_wakeup_gpe_poweroff_prepare(void);
diff --git a/drivers/acpi/sleep/wakeup.c b/drivers/acpi/sleep/wakeup.c
new file mode 100644
index 000000000000..d9b199969d5d
--- /dev/null
+++ b/drivers/acpi/sleep/wakeup.c
@@ -0,0 +1,209 @@
+/*
+ * wakeup.c - support wakeup devices
+ * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com>
+ */
+
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <acpi/acevents.h>
+#include "sleep.h"
+
+#define _COMPONENT ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME ("wakeup_devices")
+
+extern struct list_head acpi_wakeup_device_list;
+extern spinlock_t acpi_device_lock;
+
+#ifdef CONFIG_ACPI_SLEEP
+/**
+ * acpi_enable_wakeup_device_prep - prepare wakeup devices
+ * @sleep_state: ACPI state
+ * Enable all wakup devices power if the devices' wakeup level
+ * is higher than requested sleep level
+ */
+
+void
+acpi_enable_wakeup_device_prep(
+ u8 sleep_state)
+{
+ struct list_head * node, * next;
+
+ ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device_prep");
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node,
+ struct acpi_device, wakeup_list);
+
+ if (!dev->wakeup.flags.valid ||
+ !dev->wakeup.state.enabled ||
+ (sleep_state > (u32) dev->wakeup.sleep_state))
+ continue;
+
+ spin_unlock(&acpi_device_lock);
+ acpi_enable_wakeup_device_power(dev);
+ spin_lock(&acpi_device_lock);
+ }
+ spin_unlock(&acpi_device_lock);
+}
+
+/**
+ * acpi_enable_wakeup_device - enable wakeup devices
+ * @sleep_state: ACPI state
+ * Enable all wakup devices's GPE
+ */
+void
+acpi_enable_wakeup_device(
+ u8 sleep_state)
+{
+ struct list_head * node, * next;
+
+ /*
+ * Caution: this routine must be invoked when interrupt is disabled
+ * Refer ACPI2.0: P212
+ */
+ ACPI_FUNCTION_TRACE("acpi_enable_wakeup_device");
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node,
+ struct acpi_device, wakeup_list);
+
+ /* If users want to disable run-wake GPE,
+ * we only disable it for wake and leave it for runtime
+ */
+ if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+ spin_unlock(&acpi_device_lock);
+ acpi_set_gpe_type(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME);
+ /* Re-enable it, since set_gpe_type will disable it */
+ acpi_enable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_ISR);
+ spin_lock(&acpi_device_lock);
+ continue;
+ }
+
+ if (!dev->wakeup.flags.valid ||
+ !dev->wakeup.state.enabled ||
+ (sleep_state > (u32) dev->wakeup.sleep_state))
+ continue;
+
+ spin_unlock(&acpi_device_lock);
+ /* run-wake GPE has been enabled */
+ if (!dev->wakeup.flags.run_wake)
+ acpi_enable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_ISR);
+ dev->wakeup.state.active = 1;
+ spin_lock(&acpi_device_lock);
+ }
+ spin_unlock(&acpi_device_lock);
+}
+
+/**
+ * acpi_disable_wakeup_device - disable devices' wakeup capability
+ * @sleep_state: ACPI state
+ * Disable all wakup devices's GPE and wakeup capability
+ */
+void
+acpi_disable_wakeup_device (
+ u8 sleep_state)
+{
+ struct list_head * node, * next;
+
+ ACPI_FUNCTION_TRACE("acpi_disable_wakeup_device");
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node,
+ struct acpi_device, wakeup_list);
+
+ if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+ spin_unlock(&acpi_device_lock);
+ acpi_set_gpe_type(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN);
+ /* Re-enable it, since set_gpe_type will disable it */
+ acpi_enable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_NOT_ISR);
+ spin_lock(&acpi_device_lock);
+ continue;
+ }
+
+ if (!dev->wakeup.flags.valid ||
+ !dev->wakeup.state.active ||
+ (sleep_state > (u32) dev->wakeup.sleep_state))
+ continue;
+
+ spin_unlock(&acpi_device_lock);
+ acpi_disable_wakeup_device_power(dev);
+ /* Never disable run-wake GPE */
+ if (!dev->wakeup.flags.run_wake) {
+ acpi_disable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_NOT_ISR);
+ acpi_clear_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_NOT_ISR);
+ }
+ dev->wakeup.state.active = 0;
+ spin_lock(&acpi_device_lock);
+ }
+ spin_unlock(&acpi_device_lock);
+}
+
+static int __init acpi_wakeup_device_init(void)
+{
+ struct list_head * node, * next;
+
+ if (acpi_disabled)
+ return 0;
+ printk("ACPI wakeup devices: \n");
+
+ spin_lock(&acpi_device_lock);
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node,
+ struct acpi_device, wakeup_list);
+
+ /* In case user doesn't load button driver */
+ if (dev->wakeup.flags.run_wake && !dev->wakeup.state.enabled) {
+ spin_unlock(&acpi_device_lock);
+ acpi_set_gpe_type(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_GPE_TYPE_WAKE_RUN);
+ acpi_enable_gpe(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_NOT_ISR);
+ dev->wakeup.state.enabled = 1;
+ spin_lock(&acpi_device_lock);
+ }
+ printk("%4s ", dev->pnp.bus_id);
+ }
+ spin_unlock(&acpi_device_lock);
+ printk("\n");
+
+ return 0;
+}
+
+late_initcall(acpi_wakeup_device_init);
+#endif
+
+/*
+ * Disable all wakeup GPEs before power off.
+ *
+ * Since acpi_enter_sleep_state() will disable all
+ * RUNTIME GPEs, we simply mark all GPES that
+ * are not enabled for wakeup from S5 as RUNTIME.
+ */
+void acpi_wakeup_gpe_poweroff_prepare(void)
+{
+ struct list_head * node, * next;
+
+ list_for_each_safe(node, next, &acpi_wakeup_device_list) {
+ struct acpi_device * dev = container_of(node,
+ struct acpi_device, wakeup_list);
+
+ /* The GPE can wakeup system from S5, don't touch it */
+ if ((u32)dev->wakeup.sleep_state == ACPI_STATE_S5)
+ continue;
+ /* acpi_set_gpe_type will automatically disable GPE */
+ acpi_set_gpe_type(dev->wakeup.gpe_device,
+ dev->wakeup.gpe_number, ACPI_GPE_TYPE_RUNTIME);
+ }
+}
diff --git a/drivers/acpi/system.c b/drivers/acpi/system.c
new file mode 100644
index 000000000000..8925a6ca5f87
--- /dev/null
+++ b/drivers/acpi/system.c
@@ -0,0 +1,187 @@
+/*
+ * acpi_system.c - ACPI System Driver ($Revision: 63 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_SYSTEM_COMPONENT
+ACPI_MODULE_NAME ("acpi_system")
+
+#define ACPI_SYSTEM_CLASS "system"
+#define ACPI_SYSTEM_DRIVER_NAME "ACPI System Driver"
+#define ACPI_SYSTEM_DEVICE_NAME "System"
+#define ACPI_SYSTEM_FILE_INFO "info"
+#define ACPI_SYSTEM_FILE_EVENT "event"
+#define ACPI_SYSTEM_FILE_DSDT "dsdt"
+#define ACPI_SYSTEM_FILE_FADT "fadt"
+
+extern FADT_DESCRIPTOR acpi_fadt;
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_system_read_info (struct seq_file *seq, void *offset)
+{
+ ACPI_FUNCTION_TRACE("acpi_system_read_info");
+
+ seq_printf(seq, "version: %x\n", ACPI_CA_VERSION);
+ return_VALUE(0);
+}
+
+static int acpi_system_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_system_read_info, PDE(inode)->data);
+}
+
+static struct file_operations acpi_system_info_ops = {
+ .open = acpi_system_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static ssize_t acpi_system_read_dsdt (struct file*, char __user *, size_t, loff_t*);
+
+static struct file_operations acpi_system_dsdt_ops = {
+ .read = acpi_system_read_dsdt,
+};
+
+static ssize_t
+acpi_system_read_dsdt (
+ struct file *file,
+ char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ acpi_status status = AE_OK;
+ struct acpi_buffer dsdt = {ACPI_ALLOCATE_BUFFER, NULL};
+ ssize_t res;
+
+ ACPI_FUNCTION_TRACE("acpi_system_read_dsdt");
+
+ status = acpi_get_table(ACPI_TABLE_DSDT, 1, &dsdt);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ res = simple_read_from_buffer(buffer, count, ppos,
+ dsdt.pointer, dsdt.length);
+ acpi_os_free(dsdt.pointer);
+
+ return_VALUE(res);
+}
+
+
+static ssize_t acpi_system_read_fadt (struct file*, char __user *, size_t, loff_t*);
+
+static struct file_operations acpi_system_fadt_ops = {
+ .read = acpi_system_read_fadt,
+};
+
+static ssize_t
+acpi_system_read_fadt (
+ struct file *file,
+ char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ acpi_status status = AE_OK;
+ struct acpi_buffer fadt = {ACPI_ALLOCATE_BUFFER, NULL};
+ ssize_t res;
+
+ ACPI_FUNCTION_TRACE("acpi_system_read_fadt");
+
+ status = acpi_get_table(ACPI_TABLE_FADT, 1, &fadt);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ res = simple_read_from_buffer(buffer, count, ppos,
+ fadt.pointer, fadt.length);
+ acpi_os_free(fadt.pointer);
+
+ return_VALUE(res);
+}
+
+
+static int __init acpi_system_init (void)
+{
+ struct proc_dir_entry *entry;
+ int error = 0;
+ char * name;
+
+ ACPI_FUNCTION_TRACE("acpi_system_init");
+
+ if (acpi_disabled)
+ return_VALUE(0);
+
+ /* 'info' [R] */
+ name = ACPI_SYSTEM_FILE_INFO;
+ entry = create_proc_entry(name,
+ S_IRUGO, acpi_root_dir);
+ if (!entry)
+ goto Error;
+ else {
+ entry->proc_fops = &acpi_system_info_ops;
+ }
+
+ /* 'dsdt' [R] */
+ name = ACPI_SYSTEM_FILE_DSDT;
+ entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
+ if (entry)
+ entry->proc_fops = &acpi_system_dsdt_ops;
+ else
+ goto Error;
+
+ /* 'fadt' [R] */
+ name = ACPI_SYSTEM_FILE_FADT;
+ entry = create_proc_entry(name, S_IRUSR, acpi_root_dir);
+ if (entry)
+ entry->proc_fops = &acpi_system_fadt_ops;
+ else
+ goto Error;
+
+ Done:
+ return_VALUE(error);
+
+ Error:
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' proc fs entry\n", name));
+
+ remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
+ remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
+ remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
+
+ error = -EFAULT;
+ goto Done;
+}
+
+
+subsys_initcall(acpi_system_init);
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
new file mode 100644
index 000000000000..fb64bd5d2e18
--- /dev/null
+++ b/drivers/acpi/tables.c
@@ -0,0 +1,609 @@
+/*
+ * acpi_tables.c - ACPI Boot-Time Table Parsing
+ *
+ * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@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/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/irq.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/bootmem.h>
+
+#define PREFIX "ACPI: "
+
+#define ACPI_MAX_TABLES 256
+
+static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
+ [ACPI_TABLE_UNKNOWN] = "????",
+ [ACPI_APIC] = "APIC",
+ [ACPI_BOOT] = "BOOT",
+ [ACPI_DBGP] = "DBGP",
+ [ACPI_DSDT] = "DSDT",
+ [ACPI_ECDT] = "ECDT",
+ [ACPI_ETDT] = "ETDT",
+ [ACPI_FADT] = "FACP",
+ [ACPI_FACS] = "FACS",
+ [ACPI_OEMX] = "OEM",
+ [ACPI_PSDT] = "PSDT",
+ [ACPI_SBST] = "SBST",
+ [ACPI_SLIT] = "SLIT",
+ [ACPI_SPCR] = "SPCR",
+ [ACPI_SRAT] = "SRAT",
+ [ACPI_SSDT] = "SSDT",
+ [ACPI_SPMI] = "SPMI",
+ [ACPI_HPET] = "HPET",
+ [ACPI_MCFG] = "MCFG",
+};
+
+static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
+static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
+
+/* System Description Table (RSDT/XSDT) */
+struct acpi_table_sdt {
+ unsigned long pa;
+ enum acpi_table_id id;
+ unsigned long size;
+} __attribute__ ((packed));
+
+static unsigned long sdt_pa; /* Physical Address */
+static unsigned long sdt_count; /* Table count */
+
+static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES];
+
+void
+acpi_table_print (
+ struct acpi_table_header *header,
+ unsigned long phys_addr)
+{
+ char *name = NULL;
+
+ if (!header)
+ return;
+
+ /* Some table signatures aren't good table names */
+
+ if (!strncmp((char *) &header->signature,
+ acpi_table_signatures[ACPI_APIC],
+ sizeof(header->signature))) {
+ name = "MADT";
+ }
+ else if (!strncmp((char *) &header->signature,
+ acpi_table_signatures[ACPI_FADT],
+ sizeof(header->signature))) {
+ name = "FADT";
+ }
+ else
+ name = header->signature;
+
+ printk(KERN_DEBUG PREFIX "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n",
+ name, header->revision, header->oem_id,
+ header->oem_table_id, header->oem_revision,
+ header->asl_compiler_id, header->asl_compiler_revision,
+ (void *) phys_addr);
+}
+
+
+void
+acpi_table_print_madt_entry (
+ acpi_table_entry_header *header)
+{
+ if (!header)
+ return;
+
+ switch (header->type) {
+
+ case ACPI_MADT_LAPIC:
+ {
+ struct acpi_table_lapic *p =
+ (struct acpi_table_lapic*) header;
+ printk(KERN_INFO PREFIX "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
+ p->acpi_id, p->id, p->flags.enabled?"enabled":"disabled");
+ }
+ break;
+
+ case ACPI_MADT_IOAPIC:
+ {
+ struct acpi_table_ioapic *p =
+ (struct acpi_table_ioapic*) header;
+ printk(KERN_INFO PREFIX "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
+ p->id, p->address, p->global_irq_base);
+ }
+ break;
+
+ case ACPI_MADT_INT_SRC_OVR:
+ {
+ struct acpi_table_int_src_ovr *p =
+ (struct acpi_table_int_src_ovr*) header;
+ printk(KERN_INFO PREFIX "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
+ p->bus, p->bus_irq, p->global_irq,
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger]);
+ if(p->flags.reserved)
+ printk(KERN_INFO PREFIX "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
+ p->flags.reserved);
+
+ }
+ break;
+
+ case ACPI_MADT_NMI_SRC:
+ {
+ struct acpi_table_nmi_src *p =
+ (struct acpi_table_nmi_src*) header;
+ printk(KERN_INFO PREFIX "NMI_SRC (%s %s global_irq %d)\n",
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger], p->global_irq);
+ }
+ break;
+
+ case ACPI_MADT_LAPIC_NMI:
+ {
+ struct acpi_table_lapic_nmi *p =
+ (struct acpi_table_lapic_nmi*) header;
+ printk(KERN_INFO PREFIX "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
+ p->acpi_id,
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger], p->lint);
+ }
+ break;
+
+ case ACPI_MADT_LAPIC_ADDR_OVR:
+ {
+ struct acpi_table_lapic_addr_ovr *p =
+ (struct acpi_table_lapic_addr_ovr*) header;
+ printk(KERN_INFO PREFIX "LAPIC_ADDR_OVR (address[%p])\n",
+ (void *) (unsigned long) p->address);
+ }
+ break;
+
+ case ACPI_MADT_IOSAPIC:
+ {
+ struct acpi_table_iosapic *p =
+ (struct acpi_table_iosapic*) header;
+ printk(KERN_INFO PREFIX "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
+ p->id, (void *) (unsigned long) p->address, p->global_irq_base);
+ }
+ break;
+
+ case ACPI_MADT_LSAPIC:
+ {
+ struct acpi_table_lsapic *p =
+ (struct acpi_table_lsapic*) header;
+ printk(KERN_INFO PREFIX "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
+ p->acpi_id, p->id, p->eid, p->flags.enabled?"enabled":"disabled");
+ }
+ break;
+
+ case ACPI_MADT_PLAT_INT_SRC:
+ {
+ struct acpi_table_plat_int_src *p =
+ (struct acpi_table_plat_int_src*) header;
+ printk(KERN_INFO PREFIX "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
+ mps_inti_flags_polarity[p->flags.polarity],
+ mps_inti_flags_trigger[p->flags.trigger],
+ p->type, p->id, p->eid, p->iosapic_vector, p->global_irq);
+ }
+ break;
+
+ default:
+ printk(KERN_WARNING PREFIX "Found unsupported MADT entry (type = 0x%x)\n",
+ header->type);
+ break;
+ }
+}
+
+
+static int
+acpi_table_compute_checksum (
+ void *table_pointer,
+ unsigned long length)
+{
+ u8 *p = (u8 *) table_pointer;
+ unsigned long remains = length;
+ unsigned long sum = 0;
+
+ if (!p || !length)
+ return -EINVAL;
+
+ while (remains--)
+ sum += *p++;
+
+ return (sum & 0xFF);
+}
+
+/*
+ * acpi_get_table_header_early()
+ * for acpi_blacklisted(), acpi_table_get_sdt()
+ */
+int __init
+acpi_get_table_header_early (
+ enum acpi_table_id id,
+ struct acpi_table_header **header)
+{
+ unsigned int i;
+ enum acpi_table_id temp_id;
+
+ /* DSDT is different from the rest */
+ if (id == ACPI_DSDT)
+ temp_id = ACPI_FADT;
+ else
+ temp_id = id;
+
+ /* Locate the table. */
+
+ for (i = 0; i < sdt_count; i++) {
+ if (sdt_entry[i].id != temp_id)
+ continue;
+ *header = (void *)
+ __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
+ if (!*header) {
+ printk(KERN_WARNING PREFIX "Unable to map %s\n",
+ acpi_table_signatures[temp_id]);
+ return -ENODEV;
+ }
+ break;
+ }
+
+ if (!*header) {
+ printk(KERN_WARNING PREFIX "%s not present\n",
+ acpi_table_signatures[id]);
+ return -ENODEV;
+ }
+
+ /* Map the DSDT header via the pointer in the FADT */
+ if (id == ACPI_DSDT) {
+ struct fadt_descriptor_rev2 *fadt = (struct fadt_descriptor_rev2 *) *header;
+
+ if (fadt->revision == 3 && fadt->Xdsdt) {
+ *header = (void *) __acpi_map_table(fadt->Xdsdt,
+ sizeof(struct acpi_table_header));
+ } else if (fadt->V1_dsdt) {
+ *header = (void *) __acpi_map_table(fadt->V1_dsdt,
+ sizeof(struct acpi_table_header));
+ } else
+ *header = NULL;
+
+ if (!*header) {
+ printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
+ return -ENODEV;
+ }
+ }
+
+ return 0;
+}
+
+
+int __init
+acpi_table_parse_madt_family (
+ enum acpi_table_id id,
+ unsigned long madt_size,
+ int entry_id,
+ acpi_madt_entry_handler handler,
+ unsigned int max_entries)
+{
+ void *madt = NULL;
+ acpi_table_entry_header *entry;
+ unsigned int count = 0;
+ unsigned long madt_end;
+ unsigned int i;
+
+ if (!handler)
+ return -EINVAL;
+
+ /* Locate the MADT (if exists). There should only be one. */
+
+ for (i = 0; i < sdt_count; i++) {
+ if (sdt_entry[i].id != id)
+ continue;
+ madt = (void *)
+ __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
+ if (!madt) {
+ printk(KERN_WARNING PREFIX "Unable to map %s\n",
+ acpi_table_signatures[id]);
+ return -ENODEV;
+ }
+ break;
+ }
+
+ if (!madt) {
+ printk(KERN_WARNING PREFIX "%s not present\n",
+ acpi_table_signatures[id]);
+ return -ENODEV;
+ }
+
+ madt_end = (unsigned long) madt + sdt_entry[i].size;
+
+ /* Parse all entries looking for a match. */
+
+ entry = (acpi_table_entry_header *)
+ ((unsigned long) madt + madt_size);
+
+ while (((unsigned long) entry) + sizeof(acpi_table_entry_header) < madt_end) {
+ if (entry->type == entry_id &&
+ (!max_entries || count++ < max_entries))
+ if (handler(entry, madt_end))
+ return -EINVAL;
+
+ entry = (acpi_table_entry_header *)
+ ((unsigned long) entry + entry->length);
+ }
+ if (max_entries && count > max_entries) {
+ printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of "
+ "%i found\n", acpi_table_signatures[id], entry_id,
+ count - max_entries, count);
+ }
+
+ return count;
+}
+
+
+int __init
+acpi_table_parse_madt (
+ enum acpi_madt_entry_id id,
+ acpi_madt_entry_handler handler,
+ unsigned int max_entries)
+{
+ return acpi_table_parse_madt_family(ACPI_APIC, sizeof(struct acpi_table_madt),
+ id, handler, max_entries);
+}
+
+
+int __init
+acpi_table_parse (
+ enum acpi_table_id id,
+ acpi_table_handler handler)
+{
+ int count = 0;
+ unsigned int i = 0;
+
+ if (!handler)
+ return -EINVAL;
+
+ for (i = 0; i < sdt_count; i++) {
+ if (sdt_entry[i].id != id)
+ continue;
+ count++;
+ if (count == 1)
+ handler(sdt_entry[i].pa, sdt_entry[i].size);
+
+ else
+ printk(KERN_WARNING PREFIX "%d duplicate %s table ignored.\n",
+ count, acpi_table_signatures[id]);
+ }
+
+ return count;
+}
+
+
+static int __init
+acpi_table_get_sdt (
+ struct acpi_table_rsdp *rsdp)
+{
+ struct acpi_table_header *header = NULL;
+ unsigned int i, id = 0;
+
+ if (!rsdp)
+ return -EINVAL;
+
+ /* First check XSDT (but only on ACPI 2.0-compatible systems) */
+
+ if ((rsdp->revision >= 2) &&
+ (((struct acpi20_table_rsdp*)rsdp)->xsdt_address)) {
+
+ struct acpi_table_xsdt *mapped_xsdt = NULL;
+
+ sdt_pa = ((struct acpi20_table_rsdp*)rsdp)->xsdt_address;
+
+ /* map in just the header */
+ header = (struct acpi_table_header *)
+ __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
+
+ if (!header) {
+ printk(KERN_WARNING PREFIX "Unable to map XSDT header\n");
+ return -ENODEV;
+ }
+
+ /* remap in the entire table before processing */
+ mapped_xsdt = (struct acpi_table_xsdt *)
+ __acpi_map_table(sdt_pa, header->length);
+ if (!mapped_xsdt) {
+ printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
+ return -ENODEV;
+ }
+ header = &mapped_xsdt->header;
+
+ if (strncmp(header->signature, "XSDT", 4)) {
+ printk(KERN_WARNING PREFIX "XSDT signature incorrect\n");
+ return -ENODEV;
+ }
+
+ if (acpi_table_compute_checksum(header, header->length)) {
+ printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n");
+ return -ENODEV;
+ }
+
+ sdt_count = (header->length - sizeof(struct acpi_table_header)) >> 3;
+ if (sdt_count > ACPI_MAX_TABLES) {
+ printk(KERN_WARNING PREFIX "Truncated %lu XSDT entries\n",
+ (sdt_count - ACPI_MAX_TABLES));
+ sdt_count = ACPI_MAX_TABLES;
+ }
+
+ for (i = 0; i < sdt_count; i++)
+ sdt_entry[i].pa = (unsigned long) mapped_xsdt->entry[i];
+ }
+
+ /* Then check RSDT */
+
+ else if (rsdp->rsdt_address) {
+
+ struct acpi_table_rsdt *mapped_rsdt = NULL;
+
+ sdt_pa = rsdp->rsdt_address;
+
+ /* map in just the header */
+ header = (struct acpi_table_header *)
+ __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
+ if (!header) {
+ printk(KERN_WARNING PREFIX "Unable to map RSDT header\n");
+ return -ENODEV;
+ }
+
+ /* remap in the entire table before processing */
+ mapped_rsdt = (struct acpi_table_rsdt *)
+ __acpi_map_table(sdt_pa, header->length);
+ if (!mapped_rsdt) {
+ printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
+ return -ENODEV;
+ }
+ header = &mapped_rsdt->header;
+
+ if (strncmp(header->signature, "RSDT", 4)) {
+ printk(KERN_WARNING PREFIX "RSDT signature incorrect\n");
+ return -ENODEV;
+ }
+
+ if (acpi_table_compute_checksum(header, header->length)) {
+ printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n");
+ return -ENODEV;
+ }
+
+ sdt_count = (header->length - sizeof(struct acpi_table_header)) >> 2;
+ if (sdt_count > ACPI_MAX_TABLES) {
+ printk(KERN_WARNING PREFIX "Truncated %lu RSDT entries\n",
+ (sdt_count - ACPI_MAX_TABLES));
+ sdt_count = ACPI_MAX_TABLES;
+ }
+
+ for (i = 0; i < sdt_count; i++)
+ sdt_entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
+ }
+
+ else {
+ printk(KERN_WARNING PREFIX "No System Description Table (RSDT/XSDT) specified in RSDP\n");
+ return -ENODEV;
+ }
+
+ acpi_table_print(header, sdt_pa);
+
+ for (i = 0; i < sdt_count; i++) {
+
+ /* map in just the header */
+ header = (struct acpi_table_header *)
+ __acpi_map_table(sdt_entry[i].pa,
+ sizeof(struct acpi_table_header));
+ if (!header)
+ continue;
+
+ /* remap in the entire table before processing */
+ header = (struct acpi_table_header *)
+ __acpi_map_table(sdt_entry[i].pa,
+ header->length);
+ if (!header)
+ continue;
+
+ acpi_table_print(header, sdt_entry[i].pa);
+
+ if (acpi_table_compute_checksum(header, header->length)) {
+ printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
+ continue;
+ }
+
+ sdt_entry[i].size = header->length;
+
+ for (id = 0; id < ACPI_TABLE_COUNT; id++) {
+ if (!strncmp((char *) &header->signature,
+ acpi_table_signatures[id],
+ sizeof(header->signature))) {
+ sdt_entry[i].id = id;
+ }
+ }
+ }
+
+ /*
+ * The DSDT is *not* in the RSDT (why not? no idea.) but we want
+ * to print its info, because this is what people usually blacklist
+ * against. Unfortunately, we don't know the phys_addr, so just
+ * print 0. Maybe no one will notice.
+ */
+ if(!acpi_get_table_header_early(ACPI_DSDT, &header))
+ acpi_table_print(header, 0);
+
+ return 0;
+}
+
+/*
+ * acpi_table_init()
+ *
+ * find RSDP, find and checksum SDT/XSDT.
+ * checksum all tables, print SDT/XSDT
+ *
+ * result: sdt_entry[] is initialized
+ */
+
+int __init
+acpi_table_init (void)
+{
+ struct acpi_table_rsdp *rsdp = NULL;
+ unsigned long rsdp_phys = 0;
+ int result = 0;
+
+ /* Locate and map the Root System Description Table (RSDP) */
+
+ rsdp_phys = acpi_find_rsdp();
+ if (!rsdp_phys) {
+ printk(KERN_ERR PREFIX "Unable to locate RSDP\n");
+ return -ENODEV;
+ }
+
+ rsdp = (struct acpi_table_rsdp *) __va(rsdp_phys);
+ if (!rsdp) {
+ printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
+ return -ENODEV;
+ }
+
+ printk(KERN_DEBUG PREFIX "RSDP (v%3.3d %6.6s ) @ 0x%p\n",
+ rsdp->revision, rsdp->oem_id, (void *) rsdp_phys);
+
+ if (rsdp->revision < 2)
+ result = acpi_table_compute_checksum(rsdp, sizeof(struct acpi_table_rsdp));
+ else
+ result = acpi_table_compute_checksum(rsdp, ((struct acpi20_table_rsdp *)rsdp)->length);
+
+ if (result) {
+ printk(KERN_WARNING " >>> ERROR: Invalid checksum\n");
+ return -ENODEV;
+ }
+
+ /* Locate and map the System Description table (RSDT/XSDT) */
+
+ if (acpi_table_get_sdt(rsdp))
+ return -ENODEV;
+
+ return 0;
+}
diff --git a/drivers/acpi/tables/Makefile b/drivers/acpi/tables/Makefile
new file mode 100644
index 000000000000..aa4c69594d97
--- /dev/null
+++ b/drivers/acpi/tables/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := tbconvrt.o tbget.o tbrsdt.o tbxface.o \
+ tbgetall.o tbinstal.o tbutils.o tbxfroot.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
new file mode 100644
index 000000000000..334327c1f66f
--- /dev/null
+++ b/drivers/acpi/tables/tbconvrt.c
@@ -0,0 +1,564 @@
+/******************************************************************************
+ *
+ * Module Name: tbconvrt - ACPI Table conversion utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbconvrt")
+
+
+u8 acpi_fadt_is_v1;
+EXPORT_SYMBOL(acpi_fadt_is_v1);
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_table_count
+ *
+ * PARAMETERS: RSDP - Pointer to the RSDP
+ * RSDT - Pointer to the RSDT/XSDT
+ *
+ * RETURN: The number of tables pointed to by the RSDT or XSDT.
+ *
+ * DESCRIPTION: Calculate the number of tables. Automatically handles either
+ * an RSDT or XSDT.
+ *
+ ******************************************************************************/
+
+u32
+acpi_tb_get_table_count (
+ struct rsdp_descriptor *RSDP,
+ struct acpi_table_header *RSDT)
+{
+ u32 pointer_size;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (RSDP->revision < 2) {
+ pointer_size = sizeof (u32);
+ }
+ else {
+ pointer_size = sizeof (u64);
+ }
+
+ /*
+ * Determine the number of tables pointed to by the RSDT/XSDT.
+ * This is defined by the ACPI Specification to be the number of
+ * pointers contained within the RSDT/XSDT. The size of the pointers
+ * is architecture-dependent.
+ */
+ return ((RSDT->length - sizeof (struct acpi_table_header)) / pointer_size);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_to_xsdt
+ *
+ * PARAMETERS: table_info - Info about the RSDT
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert an RSDT to an XSDT (internal common format)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_convert_to_xsdt (
+ struct acpi_table_desc *table_info)
+{
+ acpi_size table_size;
+ u32 i;
+ XSDT_DESCRIPTOR *new_table;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Compute size of the converted XSDT */
+
+ table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof (u64)) +
+ sizeof (struct acpi_table_header);
+
+ /* Allocate an XSDT */
+
+ new_table = ACPI_MEM_CALLOCATE (table_size);
+ if (!new_table) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Copy the header and set the length */
+
+ ACPI_MEMCPY (new_table, table_info->pointer, sizeof (struct acpi_table_header));
+ new_table->length = (u32) table_size;
+
+ /* Copy the table pointers */
+
+ for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
+ if (acpi_gbl_RSDP->revision < 2) {
+ ACPI_STORE_ADDRESS (new_table->table_offset_entry[i],
+ (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, table_info->pointer))->table_offset_entry[i]);
+ }
+ else {
+ new_table->table_offset_entry[i] =
+ (ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info->pointer))->table_offset_entry[i];
+ }
+ }
+
+ /* Delete the original table (either mapped or in a buffer) */
+
+ acpi_tb_delete_single_table (table_info);
+
+ /* Point the table descriptor to the new table */
+
+ table_info->pointer = ACPI_CAST_PTR (struct acpi_table_header, new_table);
+ table_info->length = table_size;
+ table_info->allocation = ACPI_MEM_ALLOCATED;
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_tb_init_generic_address
+ *
+ * PARAMETERS: new_gas_struct - GAS struct to be initialized
+ * register_bit_width - Width of this register
+ * Address - Address of the register
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Initialize a GAS structure.
+ *
+ ******************************************************************************/
+
+static void
+acpi_tb_init_generic_address (
+ struct acpi_generic_address *new_gas_struct,
+ u8 register_bit_width,
+ acpi_physical_address address)
+{
+
+ ACPI_STORE_ADDRESS (new_gas_struct->address, address);
+
+ new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+ new_gas_struct->register_bit_width = register_bit_width;
+ new_gas_struct->register_bit_offset = 0;
+ new_gas_struct->access_width = 0;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_fadt1
+ *
+ * PARAMETERS: local_fadt - Pointer to new FADT
+ * original_fadt - Pointer to old FADT
+ *
+ * RETURN: Populates local_fadt
+ *
+ * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format
+ *
+ ******************************************************************************/
+
+static void
+acpi_tb_convert_fadt1 (
+ struct fadt_descriptor_rev2 *local_fadt,
+ struct fadt_descriptor_rev1 *original_fadt)
+{
+
+
+ /* ACPI 1.0 FACS */
+ /* The BIOS stored FADT should agree with Revision 1.0 */
+ acpi_fadt_is_v1 = 1;
+
+ /*
+ * Copy the table header and the common part of the tables.
+ *
+ * The 2.0 table is an extension of the 1.0 table, so the entire 1.0
+ * table can be copied first, then expand some fields to 64 bits.
+ */
+ ACPI_MEMCPY (local_fadt, original_fadt, sizeof (struct fadt_descriptor_rev1));
+
+ /* Convert table pointers to 64-bit fields */
+
+ ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl);
+ ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt);
+
+ /*
+ * System Interrupt Model isn't used in ACPI 2.0 (local_fadt->Reserved1 = 0;)
+ */
+
+ /*
+ * This field is set by the OEM to convey the preferred power management
+ * profile to OSPM. It doesn't have any 1.0 equivalence. Since we don't
+ * know what kind of 32-bit system this is, we will use "unspecified".
+ */
+ local_fadt->prefer_PM_profile = PM_UNSPECIFIED;
+
+ /*
+ * Processor Performance State Control. This is the value OSPM writes to
+ * the SMI_CMD register to assume processor performance state control
+ * responsibility. There isn't any equivalence in 1.0, but as many 1.x
+ * ACPI tables contain _PCT and _PSS we also keep this value, unless
+ * acpi_strict is set.
+ */
+ if (acpi_strict)
+ local_fadt->pstate_cnt = 0;
+
+ /*
+ * Support for the _CST object and C States change notification.
+ * This data item hasn't any 1.0 equivalence so leave it zero.
+ */
+ local_fadt->cst_cnt = 0;
+
+ /*
+ * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0.
+ * It primarily adds the FADT reset mechanism.
+ */
+ if ((original_fadt->revision == 2) &&
+ (original_fadt->length == sizeof (struct fadt_descriptor_rev2_minus))) {
+ /*
+ * Grab the entire generic address struct, plus the 1-byte reset value
+ * that immediately follows.
+ */
+ ACPI_MEMCPY (&local_fadt->reset_register,
+ &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, original_fadt))->reset_register,
+ sizeof (struct acpi_generic_address) + 1);
+ }
+ else {
+ /*
+ * Since there isn't any equivalence in 1.0 and since it is highly
+ * likely that a 1.0 system has legacy support.
+ */
+ local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES;
+ }
+
+ /*
+ * Convert the V1.0 block addresses to V2.0 GAS structures
+ */
+ acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk, local_fadt->pm1_evt_len,
+ (acpi_physical_address) local_fadt->V1_pm1a_evt_blk);
+ acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk, local_fadt->pm1_evt_len,
+ (acpi_physical_address) local_fadt->V1_pm1b_evt_blk);
+ acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk, local_fadt->pm1_cnt_len,
+ (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk);
+ acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk, local_fadt->pm1_cnt_len,
+ (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk);
+ acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk, local_fadt->pm2_cnt_len,
+ (acpi_physical_address) local_fadt->V1_pm2_cnt_blk);
+ acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk, local_fadt->pm_tm_len,
+ (acpi_physical_address) local_fadt->V1_pm_tmr_blk);
+ acpi_tb_init_generic_address (&local_fadt->xgpe0_blk, 0,
+ (acpi_physical_address) local_fadt->V1_gpe0_blk);
+ acpi_tb_init_generic_address (&local_fadt->xgpe1_blk, 0,
+ (acpi_physical_address) local_fadt->V1_gpe1_blk);
+
+ /* Create separate GAS structs for the PM1 Enable registers */
+
+ acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable,
+ (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
+ (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address +
+ ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
+
+ /* PM1B is optional; leave null if not present */
+
+ if (local_fadt->xpm1b_evt_blk.address) {
+ acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable,
+ (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
+ (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address +
+ ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_fadt2
+ *
+ * PARAMETERS: local_fadt - Pointer to new FADT
+ * original_fadt - Pointer to old FADT
+ *
+ * RETURN: Populates local_fadt
+ *
+ * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format.
+ * Handles optional "X" fields.
+ *
+ ******************************************************************************/
+
+static void
+acpi_tb_convert_fadt2 (
+ struct fadt_descriptor_rev2 *local_fadt,
+ struct fadt_descriptor_rev2 *original_fadt)
+{
+
+ /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */
+
+ ACPI_MEMCPY (local_fadt, original_fadt, sizeof (struct fadt_descriptor_rev2));
+
+ /*
+ * "X" fields are optional extensions to the original V1.0 fields, so
+ * we must selectively expand V1.0 fields if the corresponding X field
+ * is zero.
+ */
+ if (!(local_fadt->xfirmware_ctrl)) {
+ ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl);
+ }
+
+ if (!(local_fadt->Xdsdt)) {
+ ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt);
+ }
+
+ if (!(local_fadt->xpm1a_evt_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk,
+ local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1a_evt_blk);
+ }
+
+ if (!(local_fadt->xpm1b_evt_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk,
+ local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1b_evt_blk);
+ }
+
+ if (!(local_fadt->xpm1a_cnt_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk,
+ local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk);
+ }
+
+ if (!(local_fadt->xpm1b_cnt_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk,
+ local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk);
+ }
+
+ if (!(local_fadt->xpm2_cnt_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk,
+ local_fadt->pm2_cnt_len, (acpi_physical_address) local_fadt->V1_pm2_cnt_blk);
+ }
+
+ if (!(local_fadt->xpm_tmr_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk,
+ local_fadt->pm_tm_len, (acpi_physical_address) local_fadt->V1_pm_tmr_blk);
+ }
+
+ if (!(local_fadt->xgpe0_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xgpe0_blk,
+ 0, (acpi_physical_address) local_fadt->V1_gpe0_blk);
+ }
+
+ if (!(local_fadt->xgpe1_blk.address)) {
+ acpi_tb_init_generic_address (&local_fadt->xgpe1_blk,
+ 0, (acpi_physical_address) local_fadt->V1_gpe1_blk);
+ }
+
+ /* Create separate GAS structs for the PM1 Enable registers */
+
+ acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable,
+ (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
+ (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address +
+ ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
+ acpi_gbl_xpm1a_enable.address_space_id = local_fadt->xpm1a_evt_blk.address_space_id;
+
+ /* PM1B is optional; leave null if not present */
+
+ if (local_fadt->xpm1b_evt_blk.address) {
+ acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable,
+ (u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
+ (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address +
+ ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
+ acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_table_fadt
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local
+ * ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply
+ * copied to the local FADT. The ACPI CA software uses this
+ * local FADT. Thus a significant amount of special #ifdef
+ * type codeing is saved.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_convert_table_fadt (void)
+{
+ struct fadt_descriptor_rev2 *local_fadt;
+ struct acpi_table_desc *table_desc;
+
+
+ ACPI_FUNCTION_TRACE ("tb_convert_table_fadt");
+
+
+ /*
+ * acpi_gbl_FADT is valid. Validate the FADT length. The table must be
+ * at least as long as the version 1.0 FADT
+ */
+ if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev1)) {
+ ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", acpi_gbl_FADT->length));
+ return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
+ }
+
+ /* Allocate buffer for the ACPI 2.0(+) FADT */
+
+ local_fadt = ACPI_MEM_CALLOCATE (sizeof (struct fadt_descriptor_rev2));
+ if (!local_fadt) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
+ if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev2)) {
+ /* Length is too short to be a V2.0 table */
+
+ ACPI_REPORT_WARNING (("Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n",
+ acpi_gbl_FADT->length, acpi_gbl_FADT->revision));
+
+ acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT);
+ }
+ else {
+ /* Valid V2.0 table */
+
+ acpi_tb_convert_fadt2 (local_fadt, acpi_gbl_FADT);
+ }
+ }
+ else {
+ /* Valid V1.0 table */
+
+ acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT);
+ }
+
+ /*
+ * Global FADT pointer will point to the new common V2.0 FADT
+ */
+ acpi_gbl_FADT = local_fadt;
+ acpi_gbl_FADT->length = sizeof (FADT_DESCRIPTOR);
+
+ /* Free the original table */
+
+ table_desc = acpi_gbl_table_lists[ACPI_TABLE_FADT].next;
+ acpi_tb_delete_single_table (table_desc);
+
+ /* Install the new table */
+
+ table_desc->pointer = ACPI_CAST_PTR (struct acpi_table_header, acpi_gbl_FADT);
+ table_desc->allocation = ACPI_MEM_ALLOCATED;
+ table_desc->length = sizeof (struct fadt_descriptor_rev2);
+
+ /* Dump the entire FADT */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES,
+ "Hex dump of common internal FADT, size %d (%X)\n",
+ acpi_gbl_FADT->length, acpi_gbl_FADT->length));
+ ACPI_DUMP_BUFFER ((u8 *) (acpi_gbl_FADT), acpi_gbl_FADT->length);
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_convert_table_facs
+ *
+ * PARAMETERS: table_info - Info for currently installed FACS
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal
+ * table format.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_build_common_facs (
+ struct acpi_table_desc *table_info)
+{
+
+ ACPI_FUNCTION_TRACE ("tb_build_common_facs");
+
+
+ /* Absolute minimum length is 24, but the ACPI spec says 64 */
+
+ if (acpi_gbl_FACS->length < 24) {
+ ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", acpi_gbl_FACS->length));
+ return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
+ }
+
+ if (acpi_gbl_FACS->length < 64) {
+ ACPI_REPORT_WARNING (("FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n",
+ acpi_gbl_FACS->length));
+ }
+
+ /* Copy fields to the new FACS */
+
+ acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock);
+
+ if ((acpi_gbl_RSDP->revision < 2) ||
+ (acpi_gbl_FACS->length < 32) ||
+ (!(acpi_gbl_FACS->xfirmware_waking_vector))) {
+ /* ACPI 1.0 FACS or short table or optional X_ field is zero */
+
+ acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, &(acpi_gbl_FACS->firmware_waking_vector));
+ acpi_gbl_common_fACS.vector_width = 32;
+ }
+ else {
+ /* ACPI 2.0 FACS with valid X_ field */
+
+ acpi_gbl_common_fACS.firmware_waking_vector = &acpi_gbl_FACS->xfirmware_waking_vector;
+ acpi_gbl_common_fACS.vector_width = 64;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
new file mode 100644
index 000000000000..896f3ddda62e
--- /dev/null
+++ b/drivers/acpi/tables/tbget.c
@@ -0,0 +1,493 @@
+/******************************************************************************
+ *
+ * Module Name: tbget - ACPI Table get* routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbget")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_table
+ *
+ * PARAMETERS: Address - Address of table to retrieve. Can be
+ * Logical or Physical
+ * table_info - Where table info is returned
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Get entire table of unknown size.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table (
+ struct acpi_pointer *address,
+ struct acpi_table_desc *table_info)
+{
+ acpi_status status;
+ struct acpi_table_header header;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_table");
+
+
+ /*
+ * Get the header in order to get signature and table size
+ */
+ status = acpi_tb_get_table_header (address, &header);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the entire table */
+
+ status = acpi_tb_get_table_body (address, &header, table_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not get ACPI table (size %X), %s\n",
+ header.length, acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_table_header
+ *
+ * PARAMETERS: Address - Address of table to retrieve. Can be
+ * Logical or Physical
+ * return_header - Where the table header is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get an ACPI table header. Works in both physical or virtual
+ * addressing mode. Works with both physical or logical pointers.
+ * Table is either copied or mapped, depending on the pointer
+ * type and mode of the processor.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table_header (
+ struct acpi_pointer *address,
+ struct acpi_table_header *return_header)
+{
+ acpi_status status = AE_OK;
+ struct acpi_table_header *header = NULL;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_table_header");
+
+
+ /*
+ * Flags contains the current processor mode (Virtual or Physical addressing)
+ * The pointer_type is either Logical or Physical
+ */
+ switch (address->pointer_type) {
+ case ACPI_PHYSMODE_PHYSPTR:
+ case ACPI_LOGMODE_LOGPTR:
+
+ /* Pointer matches processor mode, copy the header */
+
+ ACPI_MEMCPY (return_header, address->pointer.logical, sizeof (struct acpi_table_header));
+ break;
+
+
+ case ACPI_LOGMODE_PHYSPTR:
+
+ /* Create a logical address for the physical pointer*/
+
+ status = acpi_os_map_memory (address->pointer.physical, sizeof (struct acpi_table_header),
+ (void *) &header);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n",
+ ACPI_FORMAT_UINT64 (address->pointer.physical),
+ sizeof (struct acpi_table_header)));
+ return_ACPI_STATUS (status);
+ }
+
+ /* Copy header and delete mapping */
+
+ ACPI_MEMCPY (return_header, header, sizeof (struct acpi_table_header));
+ acpi_os_unmap_memory (header, sizeof (struct acpi_table_header));
+ break;
+
+
+ default:
+
+ ACPI_REPORT_ERROR (("Invalid address flags %X\n",
+ address->pointer_type));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n",
+ return_header->signature));
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_table_body
+ *
+ * PARAMETERS: Address - Address of table to retrieve. Can be
+ * Logical or Physical
+ * Header - Header of the table to retrieve
+ * table_info - Where the table info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to
+ * replace the table with a newer version (table override.)
+ * Works in both physical or virtual
+ * addressing mode. Works with both physical or logical pointers.
+ * Table is either copied or mapped, depending on the pointer
+ * type and mode of the processor.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table_body (
+ struct acpi_pointer *address,
+ struct acpi_table_header *header,
+ struct acpi_table_desc *table_info)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_table_body");
+
+
+ if (!table_info || !address) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Attempt table override.
+ */
+ status = acpi_tb_table_override (header, table_info);
+ if (ACPI_SUCCESS (status)) {
+ /* Table was overridden by the host OS */
+
+ return_ACPI_STATUS (status);
+ }
+
+ /* No override, get the original table */
+
+ status = acpi_tb_get_this_table (address, header, table_info);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_table_override
+ *
+ * PARAMETERS: Header - Pointer to table header
+ * table_info - Return info if table is overridden
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Attempts override of current table with a new one if provided
+ * by the host OS.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_table_override (
+ struct acpi_table_header *header,
+ struct acpi_table_desc *table_info)
+{
+ struct acpi_table_header *new_table;
+ acpi_status status;
+ struct acpi_pointer address;
+
+
+ ACPI_FUNCTION_TRACE ("tb_table_override");
+
+
+ /*
+ * The OSL will examine the header and decide whether to override this
+ * table. If it decides to override, a table will be returned in new_table,
+ * which we will then copy.
+ */
+ status = acpi_os_table_override (header, &new_table);
+ if (ACPI_FAILURE (status)) {
+ /* Some severe error from the OSL, but we basically ignore it */
+
+ ACPI_REPORT_ERROR (("Could not override ACPI table, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ if (!new_table) {
+ /* No table override */
+
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ /*
+ * We have a new table to override the old one. Get a copy of
+ * the new one. We know that the new table has a logical pointer.
+ */
+ address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
+ address.pointer.logical = new_table;
+
+ status = acpi_tb_get_this_table (&address, new_table, table_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not copy override ACPI table, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ /* Copy the table info */
+
+ ACPI_REPORT_INFO (("Table [%4.4s] replaced by host OS\n",
+ table_info->pointer->signature));
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_this_table
+ *
+ * PARAMETERS: Address - Address of table to retrieve. Can be
+ * Logical or Physical
+ * Header - Header of the table to retrieve
+ * table_info - Where the table info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get an entire ACPI table. Works in both physical or virtual
+ * addressing mode. Works with both physical or logical pointers.
+ * Table is either copied or mapped, depending on the pointer
+ * type and mode of the processor.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_this_table (
+ struct acpi_pointer *address,
+ struct acpi_table_header *header,
+ struct acpi_table_desc *table_info)
+{
+ struct acpi_table_header *full_table = NULL;
+ u8 allocation;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_this_table");
+
+
+ /*
+ * Flags contains the current processor mode (Virtual or Physical addressing)
+ * The pointer_type is either Logical or Physical
+ */
+ switch (address->pointer_type) {
+ case ACPI_PHYSMODE_PHYSPTR:
+ case ACPI_LOGMODE_LOGPTR:
+
+ /* Pointer matches processor mode, copy the table to a new buffer */
+
+ full_table = ACPI_MEM_ALLOCATE (header->length);
+ if (!full_table) {
+ ACPI_REPORT_ERROR (("Could not allocate table memory for [%4.4s] length %X\n",
+ header->signature, header->length));
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Copy the entire table (including header) to the local buffer */
+
+ ACPI_MEMCPY (full_table, address->pointer.logical, header->length);
+
+ /* Save allocation type */
+
+ allocation = ACPI_MEM_ALLOCATED;
+ break;
+
+
+ case ACPI_LOGMODE_PHYSPTR:
+
+ /*
+ * Just map the table's physical memory
+ * into our address space.
+ */
+ status = acpi_os_map_memory (address->pointer.physical, (acpi_size) header->length,
+ (void *) &full_table);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n",
+ header->signature,
+ ACPI_FORMAT_UINT64 (address->pointer.physical), header->length));
+ return (status);
+ }
+
+ /* Save allocation type */
+
+ allocation = ACPI_MEM_MAPPED;
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid address flags %X\n",
+ address->pointer_type));
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Validate checksum for _most_ tables,
+ * even the ones whose signature we don't recognize
+ */
+ if (table_info->type != ACPI_TABLE_FACS) {
+ status = acpi_tb_verify_table_checksum (full_table);
+
+#if (!ACPI_CHECKSUM_ABORT)
+ if (ACPI_FAILURE (status)) {
+ /* Ignore the error if configuration says so */
+
+ status = AE_OK;
+ }
+#endif
+ }
+
+ /* Return values */
+
+ table_info->pointer = full_table;
+ table_info->length = (acpi_size) header->length;
+ table_info->allocation = allocation;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
+ full_table->signature,
+ ACPI_FORMAT_UINT64 (address->pointer.physical), full_table));
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_table_ptr
+ *
+ * PARAMETERS: table_type - one of the defined table types
+ * Instance - Which table of this type
+ * table_ptr_loc - pointer to location to place the pointer for
+ * return
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get the pointer to an ACPI table.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table_ptr (
+ acpi_table_type table_type,
+ u32 instance,
+ struct acpi_table_header **table_ptr_loc)
+{
+ struct acpi_table_desc *table_desc;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_table_ptr");
+
+
+ if (!acpi_gbl_DSDT) {
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ if (table_type > ACPI_TABLE_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * For all table types (Single/Multiple), the first
+ * instance is always in the list head.
+ */
+ if (instance == 1) {
+ /* Get the first */
+
+ *table_ptr_loc = NULL;
+ if (acpi_gbl_table_lists[table_type].next) {
+ *table_ptr_loc = acpi_gbl_table_lists[table_type].next->pointer;
+ }
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Check for instance out of range
+ */
+ if (instance > acpi_gbl_table_lists[table_type].count) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /* Walk the list to get the desired table
+ * Since the if (Instance == 1) check above checked for the
+ * first table, setting table_desc equal to the .Next member
+ * is actually pointing to the second table. Therefore, we
+ * need to walk from the 2nd table until we reach the Instance
+ * that the user is looking for and return its table pointer.
+ */
+ table_desc = acpi_gbl_table_lists[table_type].next;
+ for (i = 2; i < instance; i++) {
+ table_desc = table_desc->next;
+ }
+
+ /* We are now pointing to the requested table's descriptor */
+
+ *table_ptr_loc = table_desc->pointer;
+
+ return_ACPI_STATUS (AE_OK);
+}
+
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
new file mode 100644
index 000000000000..adc4270988bc
--- /dev/null
+++ b/drivers/acpi/tables/tbgetall.c
@@ -0,0 +1,313 @@
+/******************************************************************************
+ *
+ * Module Name: tbgetall - Get all required ACPI tables
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbgetall")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_primary_table
+ *
+ * PARAMETERS: Address - Physical address of table to retrieve
+ * *table_info - Where the table info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Maps the physical address of table into a logical address
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_primary_table (
+ struct acpi_pointer *address,
+ struct acpi_table_desc *table_info)
+{
+ acpi_status status;
+ struct acpi_table_header header;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_primary_table");
+
+
+ /* Ignore a NULL address in the RSDT */
+
+ if (!address->pointer.value) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Get the header in order to get signature and table size
+ */
+ status = acpi_tb_get_table_header (address, &header);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Clear the table_info */
+
+ ACPI_MEMSET (table_info, 0, sizeof (struct acpi_table_desc));
+
+ /*
+ * Check the table signature and make sure it is recognized.
+ * Also checks the header checksum
+ */
+ table_info->pointer = &header;
+ status = acpi_tb_recognize_table (table_info, ACPI_TABLE_PRIMARY);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the entire table */
+
+ status = acpi_tb_get_table_body (address, &header, table_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Install the table */
+
+ status = acpi_tb_install_table (table_info);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_secondary_table
+ *
+ * PARAMETERS: Address - Physical address of table to retrieve
+ * *table_info - Where the table info is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Maps the physical address of table into a logical address
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_secondary_table (
+ struct acpi_pointer *address,
+ acpi_string signature,
+ struct acpi_table_desc *table_info)
+{
+ acpi_status status;
+ struct acpi_table_header header;
+
+
+ ACPI_FUNCTION_TRACE_STR ("tb_get_secondary_table", signature);
+
+
+ /* Get the header in order to match the signature */
+
+ status = acpi_tb_get_table_header (address, &header);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Signature must match request */
+
+ if (ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) {
+ ACPI_REPORT_ERROR (("Incorrect table signature - wanted [%s] found [%4.4s]\n",
+ signature, header.signature));
+ return_ACPI_STATUS (AE_BAD_SIGNATURE);
+ }
+
+ /*
+ * Check the table signature and make sure it is recognized.
+ * Also checks the header checksum
+ */
+ table_info->pointer = &header;
+ status = acpi_tb_recognize_table (table_info, ACPI_TABLE_SECONDARY);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the entire table */
+
+ status = acpi_tb_get_table_body (address, &header, table_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Install the table */
+
+ status = acpi_tb_install_table (table_info);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_required_tables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load and validate tables other than the RSDT. The RSDT must
+ * already be loaded and validated.
+ *
+ * Get the minimum set of ACPI tables, namely:
+ *
+ * 1) FADT (via RSDT in loop below)
+ * 2) FACS (via FADT)
+ * 3) DSDT (via FADT)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_required_tables (
+ void)
+{
+ acpi_status status = AE_OK;
+ u32 i;
+ struct acpi_table_desc table_info;
+ struct acpi_pointer address;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_required_tables");
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
+ acpi_gbl_rsdt_table_count));
+
+
+ address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
+
+ /*
+ * Loop through all table pointers found in RSDT.
+ * This will NOT include the FACS and DSDT - we must get
+ * them after the loop.
+ *
+ * The only tables we are interested in getting here is the FADT and
+ * any SSDTs.
+ */
+ for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
+ /* Get the table address from the common internal XSDT */
+
+ address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
+
+ /*
+ * Get the tables needed by this subsystem (FADT and any SSDTs).
+ * NOTE: All other tables are completely ignored at this time.
+ */
+ status = acpi_tb_get_primary_table (&address, &table_info);
+ if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) {
+ ACPI_REPORT_WARNING (("%s, while getting table at %8.8X%8.8X\n",
+ acpi_format_exception (status),
+ ACPI_FORMAT_UINT64 (address.pointer.value)));
+ }
+ }
+
+ /* We must have a FADT to continue */
+
+ if (!acpi_gbl_FADT) {
+ ACPI_REPORT_ERROR (("No FADT present in RSDT/XSDT\n"));
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ /*
+ * Convert the FADT to a common format. This allows earlier revisions of the
+ * table to coexist with newer versions, using common access code.
+ */
+ status = acpi_tb_convert_table_fadt ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n"));
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Get the FACS (Pointed to by the FADT)
+ */
+ address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl;
+
+ status = acpi_tb_get_secondary_table (&address, FACS_SIG, &table_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not get/install the FACS, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Create the common FACS pointer table
+ * (Contains pointers to the original table)
+ */
+ status = acpi_tb_build_common_facs (&table_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Get/install the DSDT (Pointed to by the FADT)
+ */
+ address.pointer.value = acpi_gbl_FADT->Xdsdt;
+
+ status = acpi_tb_get_secondary_table (&address, DSDT_SIG, &table_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not get/install the DSDT\n"));
+ return_ACPI_STATUS (status);
+ }
+
+ /* Set Integer Width (32/64) based upon DSDT revision */
+
+ acpi_ut_set_integer_width (acpi_gbl_DSDT->revision);
+
+ /* Dump the entire DSDT */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES,
+ "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
+ acpi_gbl_DSDT->length, acpi_gbl_DSDT->length, acpi_gbl_integer_bit_width));
+ ACPI_DUMP_BUFFER ((u8 *) acpi_gbl_DSDT, acpi_gbl_DSDT->length);
+
+ /* Always delete the RSDP mapping, we are done with it */
+
+ acpi_tb_delete_tables_by_type (ACPI_TABLE_RSDP);
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
new file mode 100644
index 000000000000..85d5bb01022c
--- /dev/null
+++ b/drivers/acpi/tables/tbinstal.c
@@ -0,0 +1,553 @@
+/******************************************************************************
+ *
+ * Module Name: tbinstal - ACPI table installation and removal
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbinstal")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_match_signature
+ *
+ * PARAMETERS: Signature - Table signature to match
+ * table_info - Return data
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned"
+ * tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_match_signature (
+ char *signature,
+ struct acpi_table_desc *table_info,
+ u8 search_type)
+{
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_TRACE ("tb_match_signature");
+
+
+ /*
+ * Search for a signature match among the known table types
+ */
+ for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) {
+ if (!(acpi_gbl_table_data[i].flags & search_type)) {
+ continue;
+ }
+
+ if (!ACPI_STRNCMP (signature, acpi_gbl_table_data[i].signature,
+ acpi_gbl_table_data[i].sig_length)) {
+ /* Found a signature match, return index if requested */
+
+ if (table_info) {
+ table_info->type = (u8) i;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Table [%4.4s] is an ACPI table consumed by the core subsystem\n",
+ (char *) acpi_gbl_table_data[i].signature));
+
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n",
+ (char *) signature));
+
+ return_ACPI_STATUS (AE_TABLE_NOT_SUPPORTED);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_install_table
+ *
+ * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load and validate all tables other than the RSDT. The RSDT must
+ * already be loaded and validated.
+ * Install the table into the global data structs.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_install_table (
+ struct acpi_table_desc *table_info)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE ("tb_install_table");
+
+
+ /* Lock tables while installing */
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_TABLES);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not acquire table mutex for [%4.4s], %s\n",
+ table_info->pointer->signature, acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ /* Install the table into the global data structure */
+
+ status = acpi_tb_init_table_descriptor (table_info->type, table_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Could not install ACPI table [%4.4s], %s\n",
+ table_info->pointer->signature, acpi_format_exception (status)));
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "%s located at %p\n",
+ acpi_gbl_table_data[table_info->type].name, table_info->pointer));
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_TABLES);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_recognize_table
+ *
+ * PARAMETERS: table_info - Return value from acpi_tb_get_table_body
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check a table signature for a match against known table types
+ *
+ * NOTE: All table pointers are validated as follows:
+ * 1) Table pointer must point to valid physical memory
+ * 2) Signature must be 4 ASCII chars, even if we don't recognize the
+ * name
+ * 3) Table must be readable for length specified in the header
+ * 4) Table checksum must be valid (with the exception of the FACS
+ * which has no checksum for some odd reason)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_recognize_table (
+ struct acpi_table_desc *table_info,
+ u8 search_type)
+{
+ struct acpi_table_header *table_header;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("tb_recognize_table");
+
+
+ /* Ensure that we have a valid table pointer */
+
+ table_header = (struct acpi_table_header *) table_info->pointer;
+ if (!table_header) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * We only "recognize" a limited number of ACPI tables -- namely, the
+ * ones that are used by the subsystem (DSDT, FADT, etc.)
+ *
+ * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized.
+ * This can be any one of many valid ACPI tables, it just isn't one of
+ * the tables that is consumed by the core subsystem
+ */
+ status = acpi_tb_match_signature (table_header->signature, table_info, search_type);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ status = acpi_tb_validate_table_header (table_header);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Return the table type and length via the info struct */
+
+ table_info->length = (acpi_size) table_header->length;
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_init_table_descriptor
+ *
+ * PARAMETERS: table_type - The type of the table
+ * table_info - A table info struct
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Install a table into the global data structs.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_init_table_descriptor (
+ acpi_table_type table_type,
+ struct acpi_table_desc *table_info)
+{
+ struct acpi_table_list *list_head;
+ struct acpi_table_desc *table_desc;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("tb_init_table_descriptor", table_type);
+
+
+ /* Allocate a descriptor for this table */
+
+ table_desc = ACPI_MEM_CALLOCATE (sizeof (struct acpi_table_desc));
+ if (!table_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Install the table into the global data structure
+ */
+ list_head = &acpi_gbl_table_lists[table_type];
+
+ /*
+ * Two major types of tables: 1) Only one instance is allowed. This
+ * includes most ACPI tables such as the DSDT. 2) Multiple instances of
+ * the table are allowed. This includes SSDT and PSDTs.
+ */
+ if (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags)) {
+ /*
+ * Only one table allowed, and a table has alread been installed
+ * at this location, so return an error.
+ */
+ if (list_head->next) {
+ ACPI_MEM_FREE (table_desc);
+ return_ACPI_STATUS (AE_ALREADY_EXISTS);
+ }
+
+ table_desc->next = list_head->next;
+ list_head->next = table_desc;
+
+ if (table_desc->next) {
+ table_desc->next->prev = table_desc;
+ }
+
+ list_head->count++;
+ }
+ else {
+ /*
+ * Link the new table in to the list of tables of this type.
+ * Insert at the end of the list, order IS IMPORTANT.
+ *
+ * table_desc->Prev & Next are already NULL from calloc()
+ */
+ list_head->count++;
+
+ if (!list_head->next) {
+ list_head->next = table_desc;
+ }
+ else {
+ table_desc->next = list_head->next;
+
+ while (table_desc->next->next) {
+ table_desc->next = table_desc->next->next;
+ }
+
+ table_desc->next->next = table_desc;
+ table_desc->prev = table_desc->next;
+ table_desc->next = NULL;
+ }
+ }
+
+ /* Finish initialization of the table descriptor */
+
+ table_desc->type = (u8) table_type;
+ table_desc->pointer = table_info->pointer;
+ table_desc->length = table_info->length;
+ table_desc->allocation = table_info->allocation;
+ table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
+ table_desc->aml_length = (u32) (table_desc->length -
+ (u32) sizeof (struct acpi_table_header));
+ table_desc->table_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_TABLE);
+ table_desc->loaded_into_namespace = FALSE;
+
+ /*
+ * Set the appropriate global pointer (if there is one) to point to the
+ * newly installed table
+ */
+ if (acpi_gbl_table_data[table_type].global_ptr) {
+ *(acpi_gbl_table_data[table_type].global_ptr) = table_info->pointer;
+ }
+
+ /* Return Data */
+
+ table_info->table_id = table_desc->table_id;
+ table_info->installed_desc = table_desc;
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_delete_all_tables
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_delete_all_tables (void)
+{
+ acpi_table_type type;
+
+
+ /*
+ * Free memory allocated for ACPI tables
+ * Memory can either be mapped or allocated
+ */
+ for (type = 0; type < NUM_ACPI_TABLE_TYPES; type++) {
+ acpi_tb_delete_tables_by_type (type);
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_delete_tables_by_type
+ *
+ * PARAMETERS: Type - The table type to be deleted
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete an internal ACPI table
+ * Locks the ACPI table mutex
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_delete_tables_by_type (
+ acpi_table_type type)
+{
+ struct acpi_table_desc *table_desc;
+ u32 count;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("tb_delete_tables_by_type", type);
+
+
+ if (type > ACPI_TABLE_MAX) {
+ return_VOID;
+ }
+
+ if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_TABLES))) {
+ return;
+ }
+
+ /* Clear the appropriate "typed" global table pointer */
+
+ switch (type) {
+ case ACPI_TABLE_RSDP:
+ acpi_gbl_RSDP = NULL;
+ break;
+
+ case ACPI_TABLE_DSDT:
+ acpi_gbl_DSDT = NULL;
+ break;
+
+ case ACPI_TABLE_FADT:
+ acpi_gbl_FADT = NULL;
+ break;
+
+ case ACPI_TABLE_FACS:
+ acpi_gbl_FACS = NULL;
+ break;
+
+ case ACPI_TABLE_XSDT:
+ acpi_gbl_XSDT = NULL;
+ break;
+
+ case ACPI_TABLE_SSDT:
+ case ACPI_TABLE_PSDT:
+ default:
+ break;
+ }
+
+ /*
+ * Free the table
+ * 1) Get the head of the list
+ */
+ table_desc = acpi_gbl_table_lists[type].next;
+ count = acpi_gbl_table_lists[type].count;
+
+ /*
+ * 2) Walk the entire list, deleting both the allocated tables
+ * and the table descriptors
+ */
+ for (i = 0; i < count; i++) {
+ table_desc = acpi_tb_uninstall_table (table_desc);
+ }
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_TABLES);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_delete_single_table
+ *
+ * PARAMETERS: table_info - A table info struct
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Low-level free for a single ACPI table. Handles cases where
+ * the table was allocated a buffer or was mapped.
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_delete_single_table (
+ struct acpi_table_desc *table_desc)
+{
+
+ /* Must have a valid table descriptor and pointer */
+
+ if ((!table_desc) ||
+ (!table_desc->pointer)) {
+ return;
+ }
+
+ /* Valid table, determine type of memory allocation */
+
+ switch (table_desc->allocation) {
+ case ACPI_MEM_NOT_ALLOCATED:
+ break;
+
+ case ACPI_MEM_ALLOCATED:
+
+ ACPI_MEM_FREE (table_desc->pointer);
+ break;
+
+ case ACPI_MEM_MAPPED:
+
+ acpi_os_unmap_memory (table_desc->pointer, table_desc->length);
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_uninstall_table
+ *
+ * PARAMETERS: table_info - A table info struct
+ *
+ * RETURN: Pointer to the next table in the list (of same type)
+ *
+ * DESCRIPTION: Free the memory associated with an internal ACPI table that
+ * is either installed or has never been installed.
+ * Table mutex should be locked.
+ *
+ ******************************************************************************/
+
+struct acpi_table_desc *
+acpi_tb_uninstall_table (
+ struct acpi_table_desc *table_desc)
+{
+ struct acpi_table_desc *next_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("tb_uninstall_table", table_desc);
+
+
+ if (!table_desc) {
+ return_PTR (NULL);
+ }
+
+ /* Unlink the descriptor from the doubly linked list */
+
+ if (table_desc->prev) {
+ table_desc->prev->next = table_desc->next;
+ }
+ else {
+ /* Is first on list, update list head */
+
+ acpi_gbl_table_lists[table_desc->type].next = table_desc->next;
+ }
+
+ if (table_desc->next) {
+ table_desc->next->prev = table_desc->prev;
+ }
+
+ /* Free the memory allocated for the table itself */
+
+ acpi_tb_delete_single_table (table_desc);
+
+ /* Free the table descriptor */
+
+ next_desc = table_desc->next;
+ ACPI_MEM_FREE (table_desc);
+
+ /* Return pointer to the next descriptor */
+
+ return_PTR (next_desc);
+}
+
+
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
new file mode 100644
index 000000000000..9c6913238d52
--- /dev/null
+++ b/drivers/acpi/tables/tbrsdt.c
@@ -0,0 +1,324 @@
+/******************************************************************************
+ *
+ * Module Name: tbrsdt - ACPI RSDT table utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbrsdt")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_verify_rsdp
+ *
+ * PARAMETERS: Address - RSDP (Pointer to RSDT)
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_verify_rsdp (
+ struct acpi_pointer *address)
+{
+ struct acpi_table_desc table_info;
+ acpi_status status;
+ struct rsdp_descriptor *rsdp;
+
+
+ ACPI_FUNCTION_TRACE ("tb_verify_rsdp");
+
+
+ switch (address->pointer_type) {
+ case ACPI_LOGICAL_POINTER:
+
+ rsdp = address->pointer.logical;
+ break;
+
+ case ACPI_PHYSICAL_POINTER:
+ /*
+ * Obtain access to the RSDP structure
+ */
+ status = acpi_os_map_memory (address->pointer.physical, sizeof (struct rsdp_descriptor),
+ (void *) &rsdp);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ break;
+
+ default:
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * The signature and checksum must both be correct
+ */
+ if (ACPI_STRNCMP ((char *) rsdp, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
+ /* Nope, BAD Signature */
+
+ status = AE_BAD_SIGNATURE;
+ goto cleanup;
+ }
+
+ /* Check the standard checksum */
+
+ if (acpi_tb_checksum (rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+ status = AE_BAD_CHECKSUM;
+ goto cleanup;
+ }
+
+ /* Check extended checksum if table version >= 2 */
+
+ if (rsdp->revision >= 2) {
+ if (acpi_tb_checksum (rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0) {
+ status = AE_BAD_CHECKSUM;
+ goto cleanup;
+ }
+ }
+
+ /* The RSDP supplied is OK */
+
+ table_info.pointer = ACPI_CAST_PTR (struct acpi_table_header, rsdp);
+ table_info.length = sizeof (struct rsdp_descriptor);
+ table_info.allocation = ACPI_MEM_MAPPED;
+
+ /* Save the table pointers and allocation info */
+
+ status = acpi_tb_init_table_descriptor (ACPI_TABLE_RSDP, &table_info);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Save the RSDP in a global for easy access */
+
+ acpi_gbl_RSDP = ACPI_CAST_PTR (struct rsdp_descriptor, table_info.pointer);
+ return_ACPI_STATUS (status);
+
+
+ /* Error exit */
+cleanup:
+
+ if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
+ acpi_os_unmap_memory (rsdp, sizeof (struct rsdp_descriptor));
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_rsdt_address
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: RSDT physical address
+ *
+ * DESCRIPTION: Extract the address of the RSDT or XSDT, depending on the
+ * version of the RSDP
+ *
+ ******************************************************************************/
+
+void
+acpi_tb_get_rsdt_address (
+ struct acpi_pointer *out_address)
+{
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ out_address->pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
+
+ /*
+ * For RSDP revision 0 or 1, we use the RSDT.
+ * For RSDP revision 2 (and above), we use the XSDT
+ */
+ if (acpi_gbl_RSDP->revision < 2) {
+ out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address;
+ }
+ else {
+ out_address->pointer.value = acpi_gbl_RSDP->xsdt_physical_address;
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_rsdt
+ *
+ * PARAMETERS: table_ptr - Addressable pointer to the RSDT.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Validate signature for the RSDT or XSDT
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_validate_rsdt (
+ struct acpi_table_header *table_ptr)
+{
+ int no_match;
+
+
+ ACPI_FUNCTION_NAME ("tb_validate_rsdt");
+
+
+ /*
+ * For RSDP revision 0 or 1, we use the RSDT.
+ * For RSDP revision 2 and above, we use the XSDT
+ */
+ if (acpi_gbl_RSDP->revision < 2) {
+ no_match = ACPI_STRNCMP ((char *) table_ptr, RSDT_SIG,
+ sizeof (RSDT_SIG) -1);
+ }
+ else {
+ no_match = ACPI_STRNCMP ((char *) table_ptr, XSDT_SIG,
+ sizeof (XSDT_SIG) -1);
+ }
+
+ if (no_match) {
+ /* Invalid RSDT or XSDT signature */
+
+ ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n"));
+
+ ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20);
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_ERROR,
+ "RSDT/XSDT signature at %X (%p) is invalid\n",
+ acpi_gbl_RSDP->rsdt_physical_address,
+ (void *) (acpi_native_uint) acpi_gbl_RSDP->rsdt_physical_address));
+
+ if (acpi_gbl_RSDP->revision < 2) {
+ ACPI_REPORT_ERROR (("Looking for RSDT (RSDP->Rev < 2)\n"))
+ }
+ else {
+ ACPI_REPORT_ERROR (("Looking for XSDT (RSDP->Rev >= 2)\n"))
+ }
+
+ ACPI_DUMP_BUFFER ((char *) table_ptr, 48);
+
+ return (AE_BAD_SIGNATURE);
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_get_table_rsdt
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_get_table_rsdt (
+ void)
+{
+ struct acpi_table_desc table_info;
+ acpi_status status;
+ struct acpi_pointer address;
+
+
+ ACPI_FUNCTION_TRACE ("tb_get_table_rsdt");
+
+
+ /* Get the RSDT/XSDT via the RSDP */
+
+ acpi_tb_get_rsdt_address (&address);
+
+ table_info.type = ACPI_TABLE_XSDT;
+ status = acpi_tb_get_table (&address, &table_info);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "RSDP located at %p, points to RSDT physical=%8.8X%8.8X \n",
+ acpi_gbl_RSDP,
+ ACPI_FORMAT_UINT64 (address.pointer.value)));
+
+ /* Check the RSDT or XSDT signature */
+
+ status = acpi_tb_validate_rsdt (table_info.pointer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the number of tables defined in the RSDT or XSDT */
+
+ acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer);
+
+ /* Convert and/or copy to an XSDT structure */
+
+ status = acpi_tb_convert_to_xsdt (&table_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Save the table pointers and allocation info */
+
+ status = acpi_tb_init_table_descriptor (ACPI_TABLE_XSDT, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ acpi_gbl_XSDT = ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info.pointer);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
new file mode 100644
index 000000000000..fede5804c783
--- /dev/null
+++ b/drivers/acpi/tables/tbutils.c
@@ -0,0 +1,240 @@
+/******************************************************************************
+ *
+ * Module Name: tbutils - Table manipulation utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbutils")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_handle_to_object
+ *
+ * PARAMETERS: table_id - Id for which the function is searching
+ * table_desc - Pointer to return the matching table
+ * descriptor.
+ *
+ * RETURN: Search the tables to find one with a matching table_id and
+ * return a pointer to that table descriptor.
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_tb_handle_to_object (
+ u16 table_id,
+ struct acpi_table_desc **return_table_desc)
+{
+ u32 i;
+ struct acpi_table_desc *table_desc;
+
+
+ ACPI_FUNCTION_NAME ("tb_handle_to_object");
+
+
+ for (i = 0; i < ACPI_TABLE_MAX; i++) {
+ table_desc = acpi_gbl_table_lists[i].next;
+ while (table_desc) {
+ if (table_desc->table_id == table_id) {
+ *return_table_desc = table_desc;
+ return (AE_OK);
+ }
+
+ table_desc = table_desc->next;
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id));
+ return (AE_BAD_PARAMETER);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_validate_table_header
+ *
+ * PARAMETERS: table_header - Logical pointer to the table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Check an ACPI table header for validity
+ *
+ * NOTE: Table pointers are validated as follows:
+ * 1) Table pointer must point to valid physical memory
+ * 2) Signature must be 4 ASCII chars, even if we don't recognize the
+ * name
+ * 3) Table must be readable for length specified in the header
+ * 4) Table checksum must be valid (with the exception of the FACS
+ * which has no checksum because it contains variable fields)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_validate_table_header (
+ struct acpi_table_header *table_header)
+{
+ acpi_name signature;
+
+
+ ACPI_FUNCTION_NAME ("tb_validate_table_header");
+
+
+ /* Verify that this is a valid address */
+
+ if (!acpi_os_readable (table_header, sizeof (struct acpi_table_header))) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Cannot read table header at %p\n", table_header));
+ return (AE_BAD_ADDRESS);
+ }
+
+ /* Ensure that the signature is 4 ASCII characters */
+
+ ACPI_MOVE_32_TO_32 (&signature, table_header->signature);
+ if (!acpi_ut_valid_acpi_name (signature)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Table signature at %p [%p] has invalid characters\n",
+ table_header, &signature));
+
+ ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n",
+ (char *) &signature));
+ ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header));
+ return (AE_BAD_SIGNATURE);
+ }
+
+ /* Validate the table length */
+
+ if (table_header->length < sizeof (struct acpi_table_header)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid length in table header %p name %4.4s\n",
+ table_header, (char *) &signature));
+
+ ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n",
+ (u32) table_header->length));
+ ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header));
+ return (AE_BAD_HEADER);
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_verify_table_checksum
+ *
+ * PARAMETERS: *table_header - ACPI table to verify
+ *
+ * RETURN: 8 bit checksum of table
+ *
+ * DESCRIPTION: Does an 8 bit checksum of table and returns status. A correct
+ * table should have a checksum of 0.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_verify_table_checksum (
+ struct acpi_table_header *table_header)
+{
+ u8 checksum;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("tb_verify_table_checksum");
+
+
+ /* Compute the checksum on the table */
+
+ checksum = acpi_tb_checksum (table_header, table_header->length);
+
+ /* Return the appropriate exception */
+
+ if (checksum) {
+ ACPI_REPORT_WARNING (("Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n",
+ table_header->signature, (u32) table_header->checksum, (u32) checksum));
+
+ status = AE_BAD_CHECKSUM;
+ }
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_checksum
+ *
+ * PARAMETERS: Buffer - Buffer to checksum
+ * Length - Size of the buffer
+ *
+ * RETURNS 8 bit checksum of buffer
+ *
+ * DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it.
+ *
+ ******************************************************************************/
+
+u8
+acpi_tb_checksum (
+ void *buffer,
+ u32 length)
+{
+ const u8 *limit;
+ const u8 *rover;
+ u8 sum = 0;
+
+
+ if (buffer && length) {
+ /* Buffer and Length are valid */
+
+ limit = (u8 *) buffer + length;
+
+ for (rover = buffer; rover < limit; rover++) {
+ sum = (u8) (sum + *rover);
+ }
+ }
+ return (sum);
+}
+
+
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
new file mode 100644
index 000000000000..7715043461c4
--- /dev/null
+++ b/drivers/acpi/tables/tbxface.c
@@ -0,0 +1,448 @@
+/******************************************************************************
+ *
+ * Module Name: tbxface - Public interfaces to the ACPI subsystem
+ * ACPI table oriented interfaces
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+#include <acpi/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbxface")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_load_tables
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to load the ACPI tables from the
+ * provided RSDT
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_load_tables (void)
+{
+ struct acpi_pointer rsdp_address;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_load_tables");
+
+
+ /* Get the RSDP */
+
+ status = acpi_os_get_root_pointer (ACPI_LOGICAL_ADDRESSING,
+ &rsdp_address);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("acpi_load_tables: Could not get RSDP, %s\n",
+ acpi_format_exception (status)));
+ goto error_exit;
+ }
+
+ /* Map and validate the RSDP */
+
+ acpi_gbl_table_flags = rsdp_address.pointer_type;
+
+ status = acpi_tb_verify_rsdp (&rsdp_address);
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("acpi_load_tables: RSDP Failed validation: %s\n",
+ acpi_format_exception (status)));
+ goto error_exit;
+ }
+
+ /* Get the RSDT via the RSDP */
+
+ status = acpi_tb_get_table_rsdt ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("acpi_load_tables: Could not load RSDT: %s\n",
+ acpi_format_exception (status)));
+ goto error_exit;
+ }
+
+ /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */
+
+ status = acpi_tb_get_required_tables ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n",
+ acpi_format_exception (status)));
+ goto error_exit;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
+
+
+ /* Load the namespace from the tables */
+
+ status = acpi_ns_load_namespace ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("acpi_load_tables: Could not load namespace: %s\n",
+ acpi_format_exception (status)));
+ goto error_exit;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+
+
+error_exit:
+ ACPI_REPORT_ERROR (("acpi_load_tables: Could not load tables: %s\n",
+ acpi_format_exception (status)));
+
+ return_ACPI_STATUS (status);
+}
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_load_table
+ *
+ * PARAMETERS: table_ptr - pointer to a buffer containing the entire
+ * table to be loaded
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to load a table from the caller's
+ * buffer. The buffer must contain an entire ACPI Table including
+ * a valid header. The header fields will be verified, and if it
+ * is determined that the table is invalid, the call will fail.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_load_table (
+ struct acpi_table_header *table_ptr)
+{
+ acpi_status status;
+ struct acpi_table_desc table_info;
+ struct acpi_pointer address;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_load_table");
+
+
+ if (!table_ptr) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Copy the table to a local buffer */
+
+ address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
+ address.pointer.logical = table_ptr;
+
+ status = acpi_tb_get_table_body (&address, table_ptr, &table_info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Install the new table into the local data structures */
+
+ status = acpi_tb_install_table (&table_info);
+ if (ACPI_FAILURE (status)) {
+ /* Free table allocated by acpi_tb_get_table_body */
+
+ acpi_tb_delete_single_table (&table_info);
+ return_ACPI_STATUS (status);
+ }
+
+ /* Convert the table to common format if necessary */
+
+ switch (table_info.type) {
+ case ACPI_TABLE_FADT:
+
+ status = acpi_tb_convert_table_fadt ();
+ break;
+
+ case ACPI_TABLE_FACS:
+
+ status = acpi_tb_build_common_facs (&table_info);
+ break;
+
+ default:
+ /* Load table into namespace if it contains executable AML */
+
+ status = acpi_ns_load_table (table_info.installed_desc, acpi_gbl_root_node);
+ break;
+ }
+
+ if (ACPI_FAILURE (status)) {
+ /* Uninstall table and free the buffer */
+
+ (void) acpi_tb_uninstall_table (table_info.installed_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_unload_table
+ *
+ * PARAMETERS: table_type - Type of table to be unloaded
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This routine is used to force the unload of a table
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_unload_table (
+ acpi_table_type table_type)
+{
+ struct acpi_table_desc *table_desc;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_unload_table");
+
+
+ /* Parameter validation */
+
+ if (table_type > ACPI_TABLE_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+
+ /* Find all tables of the requested type */
+
+ table_desc = acpi_gbl_table_lists[table_type].next;
+ while (table_desc) {
+ /*
+ * Delete all namespace entries owned by this table. Note that these
+ * entries can appear anywhere in the namespace by virtue of the AML
+ * "Scope" operator. Thus, we need to track ownership by an ID, not
+ * simply a position within the hierarchy
+ */
+ acpi_ns_delete_namespace_by_owner (table_desc->table_id);
+
+ table_desc = table_desc->next;
+ }
+
+ /* Delete (or unmap) all tables of this type */
+
+ acpi_tb_delete_tables_by_type (table_type);
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_table_header
+ *
+ * PARAMETERS: table_type - one of the defined table types
+ * Instance - the non zero instance of the table, allows
+ * support for multiple tables of the same type
+ * see acpi_gbl_acpi_table_flag
+ * out_table_header - pointer to the struct acpi_table_header if successful
+ *
+ * DESCRIPTION: This function is called to get an ACPI table header. The caller
+ * supplies an pointer to a data area sufficient to contain an ACPI
+ * struct acpi_table_header structure.
+ *
+ * The header contains a length field that can be used to determine
+ * the size of the buffer needed to contain the entire table. This
+ * function is not valid for the RSD PTR table since it does not
+ * have a standard header and is fixed length.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_table_header (
+ acpi_table_type table_type,
+ u32 instance,
+ struct acpi_table_header *out_table_header)
+{
+ struct acpi_table_header *tbl_ptr;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_table_header");
+
+
+ if ((instance == 0) ||
+ (table_type == ACPI_TABLE_RSDP) ||
+ (!out_table_header)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Check the table type and instance */
+
+ if ((table_type > ACPI_TABLE_MAX) ||
+ (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags) &&
+ instance > 1)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the entire table */
+
+ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * The function will return a NULL pointer if the table is not loaded
+ */
+ if (tbl_ptr == NULL) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /*
+ * Copy the header to the caller's buffer
+ */
+ ACPI_MEMCPY ((void *) out_table_header, (void *) tbl_ptr,
+ sizeof (struct acpi_table_header));
+
+ return_ACPI_STATUS (status);
+}
+
+
+#endif /* ACPI_FUTURE_USAGE */
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_table
+ *
+ * PARAMETERS: table_type - one of the defined table types
+ * Instance - the non zero instance of the table, allows
+ * support for multiple tables of the same type
+ * see acpi_gbl_acpi_table_flag
+ * ret_buffer - pointer to a structure containing a buffer to
+ * receive the table
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get an ACPI table. The caller
+ * supplies an out_buffer large enough to contain the entire ACPI
+ * table. The caller should call the acpi_get_table_header function
+ * first to determine the buffer size needed. Upon completion
+ * the out_buffer->Length field will indicate the number of bytes
+ * copied into the out_buffer->buf_ptr buffer. This table will be
+ * a complete table including the header.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_table (
+ acpi_table_type table_type,
+ u32 instance,
+ struct acpi_buffer *ret_buffer)
+{
+ struct acpi_table_header *tbl_ptr;
+ acpi_status status;
+ acpi_size table_length;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_table");
+
+
+ /* Parameter validation */
+
+ if (instance == 0) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_ut_validate_buffer (ret_buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Check the table type and instance */
+
+ if ((table_type > ACPI_TABLE_MAX) ||
+ (ACPI_IS_SINGLE_TABLE (acpi_gbl_table_data[table_type].flags) &&
+ instance > 1)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+
+ /* Get a pointer to the entire table */
+
+ status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * acpi_tb_get_table_ptr will return a NULL pointer if the
+ * table is not loaded.
+ */
+ if (tbl_ptr == NULL) {
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ /* Get the table length */
+
+ if (table_type == ACPI_TABLE_RSDP) {
+ /*
+ * RSD PTR is the only "table" without a header
+ */
+ table_length = sizeof (struct rsdp_descriptor);
+ }
+ else {
+ table_length = (acpi_size) tbl_ptr->length;
+ }
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (ret_buffer, table_length);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Copy the table to the buffer */
+
+ ACPI_MEMCPY ((void *) ret_buffer->pointer, (void *) tbl_ptr, table_length);
+ return_ACPI_STATUS (AE_OK);
+}
+EXPORT_SYMBOL(acpi_get_table);
+
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
new file mode 100644
index 000000000000..6e8072ebbac6
--- /dev/null
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -0,0 +1,606 @@
+/******************************************************************************
+ *
+ * Module Name: tbxfroot - Find the root ACPI table (RSDT)
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+
+#define _COMPONENT ACPI_TABLES
+ ACPI_MODULE_NAME ("tbxfroot")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_find_table
+ *
+ * PARAMETERS: Signature - String with ACPI table signature
+ * oem_id - String with the table OEM ID
+ * oem_table_id - String with the OEM Table ID.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
+ * Signature, OEM ID and OEM Table ID.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_find_table (
+ char *signature,
+ char *oem_id,
+ char *oem_table_id,
+ struct acpi_table_header **table_ptr)
+{
+ acpi_status status;
+ struct acpi_table_header *table;
+
+
+ ACPI_FUNCTION_TRACE ("tb_find_table");
+
+
+ /* Validate string lengths */
+
+ if ((ACPI_STRLEN (signature) > ACPI_NAME_SIZE) ||
+ (ACPI_STRLEN (oem_id) > sizeof (table->oem_id)) ||
+ (ACPI_STRLEN (oem_table_id) > sizeof (table->oem_table_id))) {
+ return_ACPI_STATUS (AE_AML_STRING_LIMIT);
+ }
+
+ if (!ACPI_STRNCMP (signature, DSDT_SIG, ACPI_NAME_SIZE)) {
+ /*
+ * The DSDT pointer is contained in the FADT, not the RSDT.
+ * This code should suffice, because the only code that would perform
+ * a "find" on the DSDT is the data_table_region() AML opcode -- in
+ * which case, the DSDT is guaranteed to be already loaded.
+ * If this becomes insufficient, the FADT will have to be found first.
+ */
+ if (!acpi_gbl_DSDT) {
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ table = acpi_gbl_DSDT;
+ }
+ else {
+ /* Find the table */
+
+ status = acpi_get_firmware_table (signature, 1,
+ ACPI_LOGICAL_ADDRESSING, &table);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Check oem_id and oem_table_id */
+
+ if ((oem_id[0] && ACPI_STRNCMP (
+ oem_id, table->oem_id, sizeof (table->oem_id))) ||
+ (oem_table_id[0] && ACPI_STRNCMP (
+ oem_table_id, table->oem_table_id, sizeof (table->oem_table_id)))) {
+ return_ACPI_STATUS (AE_AML_NAME_NOT_FOUND);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", table->signature));
+ *table_ptr = table;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_get_firmware_table
+ *
+ * PARAMETERS: Signature - Any ACPI table signature
+ * Instance - the non zero instance of the table, allows
+ * support for multiple tables of the same type
+ * Flags - Physical/Virtual support
+ * table_pointer - Where a buffer containing the table is
+ * returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to get an ACPI table. A buffer is
+ * allocated for the table and returned in table_pointer.
+ * This table will be a complete table including the header.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_firmware_table (
+ acpi_string signature,
+ u32 instance,
+ u32 flags,
+ struct acpi_table_header **table_pointer)
+{
+ acpi_status status;
+ struct acpi_pointer address;
+ struct acpi_table_header *header = NULL;
+ struct acpi_table_desc *table_info = NULL;
+ struct acpi_table_desc *rsdt_info;
+ u32 table_count;
+ u32 i;
+ u32 j;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_firmware_table");
+
+
+ /*
+ * Ensure that at least the table manager is initialized. We don't
+ * require that the entire ACPI subsystem is up for this interface.
+ * If we have a buffer, we must have a length too
+ */
+ if ((instance == 0) ||
+ (!signature) ||
+ (!table_pointer)) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Ensure that we have a RSDP */
+
+ if (!acpi_gbl_RSDP) {
+ /* Get the RSDP */
+
+ status = acpi_os_get_root_pointer (flags, &address);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "RSDP not found\n"));
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ /* Map and validate the RSDP */
+
+ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
+ status = acpi_os_map_memory (address.pointer.physical, sizeof (struct rsdp_descriptor),
+ (void *) &acpi_gbl_RSDP);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+ else {
+ acpi_gbl_RSDP = address.pointer.logical;
+ }
+
+ /* The signature and checksum must both be correct */
+
+ if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
+ /* Nope, BAD Signature */
+
+ return_ACPI_STATUS (AE_BAD_SIGNATURE);
+ }
+
+ if (acpi_tb_checksum (acpi_gbl_RSDP, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+ /* Nope, BAD Checksum */
+
+ return_ACPI_STATUS (AE_BAD_CHECKSUM);
+ }
+ }
+
+ /* Get the RSDT address via the RSDP */
+
+ acpi_tb_get_rsdt_address (&address);
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "RSDP located at %p, RSDT physical=%8.8X%8.8X \n",
+ acpi_gbl_RSDP,
+ ACPI_FORMAT_UINT64 (address.pointer.value)));
+
+ /* Insert processor_mode flags */
+
+ address.pointer_type |= flags;
+
+ /* Get and validate the RSDT */
+
+ rsdt_info = ACPI_MEM_CALLOCATE (sizeof (struct acpi_table_desc));
+ if (!rsdt_info) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ status = acpi_tb_get_table (&address, rsdt_info);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ status = acpi_tb_validate_rsdt (rsdt_info->pointer);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Allocate a scratch table header and table descriptor */
+
+ header = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_header));
+ if (!header) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ table_info = ACPI_MEM_ALLOCATE (sizeof (struct acpi_table_desc));
+ if (!table_info) {
+ status = AE_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Get the number of table pointers within the RSDT */
+
+ table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, rsdt_info->pointer);
+ address.pointer_type = acpi_gbl_table_flags | flags;
+
+ /*
+ * Search the RSDT/XSDT for the correct instance of the
+ * requested table
+ */
+ for (i = 0, j = 0; i < table_count; i++) {
+ /* Get the next table pointer, handle RSDT vs. XSDT */
+
+ if (acpi_gbl_RSDP->revision < 2) {
+ address.pointer.value = (ACPI_CAST_PTR (
+ RSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i];
+ }
+ else {
+ address.pointer.value = (ACPI_CAST_PTR (
+ XSDT_DESCRIPTOR, rsdt_info->pointer))->table_offset_entry[i];
+ }
+
+ /* Get the table header */
+
+ status = acpi_tb_get_table_header (&address, header);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ /* Compare table signatures and table instance */
+
+ if (!ACPI_STRNCMP (header->signature, signature, ACPI_NAME_SIZE)) {
+ /* An instance of the table was found */
+
+ j++;
+ if (j >= instance) {
+ /* Found the correct instance, get the entire table */
+
+ status = acpi_tb_get_table_body (&address, header, table_info);
+ if (ACPI_FAILURE (status)) {
+ goto cleanup;
+ }
+
+ *table_pointer = table_info->pointer;
+ goto cleanup;
+ }
+ }
+ }
+
+ /* Did not find the table */
+
+ status = AE_NOT_EXIST;
+
+
+cleanup:
+ acpi_os_unmap_memory (rsdt_info->pointer, (acpi_size) rsdt_info->pointer->length);
+ ACPI_MEM_FREE (rsdt_info);
+
+ if (header) {
+ ACPI_MEM_FREE (header);
+ }
+ if (table_info) {
+ ACPI_MEM_FREE (table_info);
+ }
+ return_ACPI_STATUS (status);
+}
+EXPORT_SYMBOL(acpi_get_firmware_table);
+
+
+/* TBD: Move to a new file */
+
+#if ACPI_MACHINE_WIDTH != 16
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_find_root_pointer
+ *
+ * PARAMETERS: **rsdp_address - Where to place the RSDP address
+ * Flags - Logical/Physical addressing
+ *
+ * RETURN: Status, Physical address of the RSDP
+ *
+ * DESCRIPTION: Find the RSDP
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_find_root_pointer (
+ u32 flags,
+ struct acpi_pointer *rsdp_address)
+{
+ struct acpi_table_desc table_info;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_find_root_pointer");
+
+
+ /* Get the RSDP */
+
+ status = acpi_tb_find_rsdp (&table_info, flags);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "RSDP structure not found, %s Flags=%X\n",
+ acpi_format_exception (status), flags));
+ return_ACPI_STATUS (AE_NO_ACPI_TABLES);
+ }
+
+ rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER;
+ rsdp_address->pointer.physical = table_info.physical_address;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_scan_memory_for_rsdp
+ *
+ * PARAMETERS: start_address - Starting pointer for search
+ * Length - Maximum length to search
+ *
+ * RETURN: Pointer to the RSDP if found, otherwise NULL.
+ *
+ * DESCRIPTION: Search a block of memory for the RSDP signature
+ *
+ ******************************************************************************/
+
+u8 *
+acpi_tb_scan_memory_for_rsdp (
+ u8 *start_address,
+ u32 length)
+{
+ u8 *mem_rover;
+ u8 *end_address;
+ u8 checksum;
+
+
+ ACPI_FUNCTION_TRACE ("tb_scan_memory_for_rsdp");
+
+
+ end_address = start_address + length;
+
+ /* Search from given start address for the requested length */
+
+ for (mem_rover = start_address; mem_rover < end_address;
+ mem_rover += ACPI_RSDP_SCAN_STEP) {
+ /* The signature and checksum must both be correct */
+
+ if (ACPI_STRNCMP ((char *) mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
+ /* No signature match, keep looking */
+
+ continue;
+ }
+
+ /* Signature matches, check the appropriate checksum */
+
+ if ((ACPI_CAST_PTR (struct rsdp_descriptor, mem_rover))->revision < 2) {
+ /* ACPI version 1.0 */
+
+ checksum = acpi_tb_checksum (mem_rover, ACPI_RSDP_CHECKSUM_LENGTH);
+ }
+ else {
+ /* Post ACPI 1.0, use extended_checksum */
+
+ checksum = acpi_tb_checksum (mem_rover, ACPI_RSDP_XCHECKSUM_LENGTH);
+ }
+
+ if (checksum == 0) {
+ /* Checksum valid, we have found a valid RSDP */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "RSDP located at physical address %p\n", mem_rover));
+ return_PTR (mem_rover);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Found an RSDP at physical address %p, but it has a bad checksum\n",
+ mem_rover));
+ }
+
+ /* Searched entire block, no RSDP was found */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Searched entire block, no valid RSDP was found.\n"));
+ return_PTR (NULL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_find_rsdp
+ *
+ * PARAMETERS: *table_info - Where the table info is returned
+ * Flags - Current memory mode (logical vs.
+ * physical addressing)
+ *
+ * RETURN: Status, RSDP physical address
+ *
+ * DESCRIPTION: search lower 1_mbyte of memory for the root system descriptor
+ * pointer structure. If it is found, set *RSDP to point to it.
+ *
+ * NOTE1: The RSDp must be either in the first 1_k of the Extended
+ * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
+ * Only a 32-bit physical address is necessary.
+ *
+ * NOTE2: This function is always available, regardless of the
+ * initialization state of the rest of ACPI.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_find_rsdp (
+ struct acpi_table_desc *table_info,
+ u32 flags)
+{
+ u8 *table_ptr;
+ u8 *mem_rover;
+ u32 physical_address;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("tb_find_rsdp");
+
+
+ /*
+ * Scan supports either 1) Logical addressing or 2) Physical addressing
+ */
+ if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
+ /*
+ * 1a) Get the location of the EBDA
+ */
+ status = acpi_os_map_memory ((acpi_physical_address) ACPI_EBDA_PTR_LOCATION,
+ ACPI_EBDA_PTR_LENGTH,
+ (void *) &table_ptr);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not map memory at %8.8X for length %X\n",
+ ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
+ return_ACPI_STATUS (status);
+ }
+
+ ACPI_MOVE_16_TO_32 (&physical_address, table_ptr);
+ physical_address <<= 4; /* Convert segment to physical address */
+ acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH);
+
+ /* EBDA present? */
+
+ if (physical_address > 0x400) {
+ /*
+ * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length)
+ */
+ status = acpi_os_map_memory ((acpi_physical_address) physical_address,
+ ACPI_EBDA_WINDOW_SIZE,
+ (void *) &table_ptr);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not map memory at %8.8X for length %X\n",
+ physical_address, ACPI_EBDA_WINDOW_SIZE));
+ return_ACPI_STATUS (status);
+ }
+
+ mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE);
+ acpi_os_unmap_memory (table_ptr, ACPI_EBDA_WINDOW_SIZE);
+
+ if (mem_rover) {
+ /* Found it, return the physical address */
+
+ physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr);
+
+ table_info->physical_address = (acpi_physical_address) physical_address;
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ /*
+ * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
+ */
+ status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE,
+ ACPI_HI_RSDP_WINDOW_SIZE,
+ (void *) &table_ptr);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not map memory at %8.8X for length %X\n",
+ ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE));
+ return_ACPI_STATUS (status);
+ }
+
+ mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+ acpi_os_unmap_memory (table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+
+ if (mem_rover) {
+ /* Found it, return the physical address */
+
+ physical_address = ACPI_HI_RSDP_WINDOW_BASE + ACPI_PTR_DIFF (mem_rover, table_ptr);
+
+ table_info->physical_address = (acpi_physical_address) physical_address;
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ /*
+ * Physical addressing
+ */
+ else {
+ /*
+ * 1a) Get the location of the EBDA
+ */
+ ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION);
+ physical_address <<= 4; /* Convert segment to physical address */
+
+ /* EBDA present? */
+
+ if (physical_address > 0x400) {
+ /*
+ * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length)
+ */
+ mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (physical_address),
+ ACPI_EBDA_WINDOW_SIZE);
+ if (mem_rover) {
+ /* Found it, return the physical address */
+
+ table_info->physical_address = ACPI_TO_INTEGER (mem_rover);
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ /*
+ * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
+ */
+ mem_rover = acpi_tb_scan_memory_for_rsdp (ACPI_PHYSADDR_TO_PTR (ACPI_HI_RSDP_WINDOW_BASE),
+ ACPI_HI_RSDP_WINDOW_SIZE);
+ if (mem_rover) {
+ /* Found it, return the physical address */
+
+ table_info->physical_address = ACPI_TO_INTEGER (mem_rover);
+ return_ACPI_STATUS (AE_OK);
+ }
+ }
+
+ /* RSDP signature was not found */
+
+ return_ACPI_STATUS (AE_NOT_FOUND);
+}
+
+#endif
+
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
new file mode 100644
index 000000000000..79c3a686bc44
--- /dev/null
+++ b/drivers/acpi/thermal.c
@@ -0,0 +1,1445 @@
+/*
+ * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This driver fully implements the ACPI thermal policy as described in the
+ * ACPI 2.0 Specification.
+ *
+ * TBD: 1. Implement passive cooling hysteresis.
+ * 2. Enhance passive cooling (CPU) states/limit interface to support
+ * concepts of 'multiple limiters', upper/lower limits, etc.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_THERMAL_COMPONENT 0x04000000
+#define ACPI_THERMAL_CLASS "thermal_zone"
+#define ACPI_THERMAL_DRIVER_NAME "ACPI Thermal Zone Driver"
+#define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
+#define ACPI_THERMAL_FILE_STATE "state"
+#define ACPI_THERMAL_FILE_TEMPERATURE "temperature"
+#define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points"
+#define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode"
+#define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency"
+#define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
+#define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
+#define ACPI_THERMAL_NOTIFY_DEVICES 0x82
+#define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
+#define ACPI_THERMAL_NOTIFY_HOT 0xF1
+#define ACPI_THERMAL_MODE_ACTIVE 0x00
+#define ACPI_THERMAL_MODE_PASSIVE 0x01
+#define ACPI_THERMAL_MODE_CRITICAL 0xff
+#define ACPI_THERMAL_PATH_POWEROFF "/sbin/poweroff"
+
+#define ACPI_THERMAL_MAX_ACTIVE 10
+#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
+
+#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
+#define CELSIUS_TO_KELVIN(t) ((t+273)*10)
+
+#define _COMPONENT ACPI_THERMAL_COMPONENT
+ACPI_MODULE_NAME ("acpi_thermal")
+
+MODULE_AUTHOR("Paul Diefenbaugh");
+MODULE_DESCRIPTION(ACPI_THERMAL_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int tzp;
+module_param(tzp, int, 0);
+MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
+
+
+static int acpi_thermal_add (struct acpi_device *device);
+static int acpi_thermal_remove (struct acpi_device *device, int type);
+static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
+static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
+static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
+static ssize_t acpi_thermal_write_trip_points (struct file*,const char __user *,size_t,loff_t *);
+static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file);
+static ssize_t acpi_thermal_write_cooling_mode (struct file*,const char __user *,size_t,loff_t *);
+static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file);
+static ssize_t acpi_thermal_write_polling(struct file*,const char __user *,size_t,loff_t *);
+
+static struct acpi_driver acpi_thermal_driver = {
+ .name = ACPI_THERMAL_DRIVER_NAME,
+ .class = ACPI_THERMAL_CLASS,
+ .ids = ACPI_THERMAL_HID,
+ .ops = {
+ .add = acpi_thermal_add,
+ .remove = acpi_thermal_remove,
+ },
+};
+
+struct acpi_thermal_state {
+ u8 critical:1;
+ u8 hot:1;
+ u8 passive:1;
+ u8 active:1;
+ u8 reserved:4;
+ int active_index;
+};
+
+struct acpi_thermal_state_flags {
+ u8 valid:1;
+ u8 enabled:1;
+ u8 reserved:6;
+};
+
+struct acpi_thermal_critical {
+ struct acpi_thermal_state_flags flags;
+ unsigned long temperature;
+};
+
+struct acpi_thermal_hot {
+ struct acpi_thermal_state_flags flags;
+ unsigned long temperature;
+};
+
+struct acpi_thermal_passive {
+ struct acpi_thermal_state_flags flags;
+ unsigned long temperature;
+ unsigned long tc1;
+ unsigned long tc2;
+ unsigned long tsp;
+ struct acpi_handle_list devices;
+};
+
+struct acpi_thermal_active {
+ struct acpi_thermal_state_flags flags;
+ unsigned long temperature;
+ struct acpi_handle_list devices;
+};
+
+struct acpi_thermal_trips {
+ struct acpi_thermal_critical critical;
+ struct acpi_thermal_hot hot;
+ struct acpi_thermal_passive passive;
+ struct acpi_thermal_active active[ACPI_THERMAL_MAX_ACTIVE];
+};
+
+struct acpi_thermal_flags {
+ u8 cooling_mode:1; /* _SCP */
+ u8 devices:1; /* _TZD */
+ u8 reserved:6;
+};
+
+struct acpi_thermal {
+ acpi_handle handle;
+ acpi_bus_id name;
+ unsigned long temperature;
+ unsigned long last_temperature;
+ unsigned long polling_frequency;
+ u8 cooling_mode;
+ volatile u8 zombie;
+ struct acpi_thermal_flags flags;
+ struct acpi_thermal_state state;
+ struct acpi_thermal_trips trips;
+ struct acpi_handle_list devices;
+ struct timer_list timer;
+};
+
+static struct file_operations acpi_thermal_state_fops = {
+ .open = acpi_thermal_state_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct file_operations acpi_thermal_temp_fops = {
+ .open = acpi_thermal_temp_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct file_operations acpi_thermal_trip_fops = {
+ .open = acpi_thermal_trip_open_fs,
+ .read = seq_read,
+ .write = acpi_thermal_write_trip_points,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct file_operations acpi_thermal_cooling_fops = {
+ .open = acpi_thermal_cooling_open_fs,
+ .read = seq_read,
+ .write = acpi_thermal_write_cooling_mode,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct file_operations acpi_thermal_polling_fops = {
+ .open = acpi_thermal_polling_open_fs,
+ .read = seq_read,
+ .write = acpi_thermal_write_polling,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* --------------------------------------------------------------------------
+ Thermal Zone Management
+ -------------------------------------------------------------------------- */
+
+static int
+acpi_thermal_get_temperature (
+ struct acpi_thermal *tz)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_get_temperature");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ tz->last_temperature = tz->temperature;
+
+ status = acpi_evaluate_integer(tz->handle, "_TMP", NULL, &tz->temperature);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Temperature is %lu dK\n", tz->temperature));
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_get_polling_frequency (
+ struct acpi_thermal *tz)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_get_polling_frequency");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ status = acpi_evaluate_integer(tz->handle, "_TZP", NULL, &tz->polling_frequency);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency is %lu dS\n", tz->polling_frequency));
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_set_polling (
+ struct acpi_thermal *tz,
+ int seconds)
+{
+ ACPI_FUNCTION_TRACE("acpi_thermal_set_polling");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ tz->polling_frequency = seconds * 10; /* Convert value to deci-seconds */
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Polling frequency set to %lu seconds\n", tz->polling_frequency));
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_set_cooling_mode (
+ struct acpi_thermal *tz,
+ int mode)
+{
+ acpi_status status = AE_OK;
+ union acpi_object arg0 = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list arg_list = {1, &arg0};
+ acpi_handle handle = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_set_cooling_mode");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ status = acpi_get_handle(tz->handle, "_SCP", &handle);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "_SCP not present\n"));
+ return_VALUE(-ENODEV);
+ }
+
+ arg0.integer.value = mode;
+
+ status = acpi_evaluate_object(handle, NULL, &arg_list, NULL);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ tz->cooling_mode = mode;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling mode [%s]\n",
+ mode?"passive":"active"));
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_get_trip_points (
+ struct acpi_thermal *tz)
+{
+ acpi_status status = AE_OK;
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_get_trip_points");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ /* Critical Shutdown (required) */
+
+ status = acpi_evaluate_integer(tz->handle, "_CRT", NULL,
+ &tz->trips.critical.temperature);
+ if (ACPI_FAILURE(status)) {
+ tz->trips.critical.flags.valid = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "No critical threshold\n"));
+ return_VALUE(-ENODEV);
+ }
+ else {
+ tz->trips.critical.flags.valid = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found critical threshold [%lu]\n", tz->trips.critical.temperature));
+ }
+
+ /* Critical Sleep (optional) */
+
+ status = acpi_evaluate_integer(tz->handle, "_HOT", NULL, &tz->trips.hot.temperature);
+ if (ACPI_FAILURE(status)) {
+ tz->trips.hot.flags.valid = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
+ }
+ else {
+ tz->trips.hot.flags.valid = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n", tz->trips.hot.temperature));
+ }
+
+ /* Passive: Processors (optional) */
+
+ status = acpi_evaluate_integer(tz->handle, "_PSV", NULL, &tz->trips.passive.temperature);
+ if (ACPI_FAILURE(status)) {
+ tz->trips.passive.flags.valid = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
+ }
+ else {
+ tz->trips.passive.flags.valid = 1;
+
+ status = acpi_evaluate_integer(tz->handle, "_TC1", NULL, &tz->trips.passive.tc1);
+ if (ACPI_FAILURE(status))
+ tz->trips.passive.flags.valid = 0;
+
+ status = acpi_evaluate_integer(tz->handle, "_TC2", NULL, &tz->trips.passive.tc2);
+ if (ACPI_FAILURE(status))
+ tz->trips.passive.flags.valid = 0;
+
+ status = acpi_evaluate_integer(tz->handle, "_TSP", NULL, &tz->trips.passive.tsp);
+ if (ACPI_FAILURE(status))
+ tz->trips.passive.flags.valid = 0;
+
+ status = acpi_evaluate_reference(tz->handle, "_PSL", NULL, &tz->trips.passive.devices);
+ if (ACPI_FAILURE(status))
+ tz->trips.passive.flags.valid = 0;
+
+ if (!tz->trips.passive.flags.valid)
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid passive threshold\n"));
+ else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found passive threshold [%lu]\n", tz->trips.passive.temperature));
+ }
+
+ /* Active: Fans, etc. (optional) */
+
+ for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
+
+ char name[5] = {'_','A','C',('0'+i),'\0'};
+
+ status = acpi_evaluate_integer(tz->handle, name, NULL, &tz->trips.active[i].temperature);
+ if (ACPI_FAILURE(status))
+ break;
+
+ name[2] = 'L';
+ status = acpi_evaluate_reference(tz->handle, name, NULL, &tz->trips.active[i].devices);
+ if (ACPI_SUCCESS(status)) {
+ tz->trips.active[i].flags.valid = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found active threshold [%d]:[%lu]\n", i, tz->trips.active[i].temperature));
+ }
+ else
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid active threshold [%d]\n", i));
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_get_devices (
+ struct acpi_thermal *tz)
+{
+ acpi_status status = AE_OK;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_get_devices");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ status = acpi_evaluate_reference(tz->handle, "_TZD", NULL, &tz->devices);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_call_usermode (
+ char *path)
+{
+ char *argv[2] = {NULL, NULL};
+ char *envp[3] = {NULL, NULL, NULL};
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_call_usermode");
+
+ if (!path)
+ return_VALUE(-EINVAL);
+
+ argv[0] = path;
+
+ /* minimal command environment */
+ envp[0] = "HOME=/";
+ envp[1] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+
+ call_usermodehelper(argv[0], argv, envp, 0);
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_critical (
+ struct acpi_thermal *tz)
+{
+ int result = 0;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_critical");
+
+ if (!tz || !tz->trips.critical.flags.valid)
+ return_VALUE(-EINVAL);
+
+ if (tz->temperature >= tz->trips.critical.temperature) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Critical trip point\n"));
+ tz->trips.critical.flags.enabled = 1;
+ }
+ else if (tz->trips.critical.flags.enabled)
+ tz->trips.critical.flags.enabled = 0;
+
+ result = acpi_bus_get_device(tz->handle, &device);
+ if (result)
+ return_VALUE(result);
+
+ printk(KERN_EMERG "Critical temperature reached (%ld C), shutting down.\n", KELVIN_TO_CELSIUS(tz->temperature));
+ acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_CRITICAL, tz->trips.critical.flags.enabled);
+
+ acpi_thermal_call_usermode(ACPI_THERMAL_PATH_POWEROFF);
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_hot (
+ struct acpi_thermal *tz)
+{
+ int result = 0;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_hot");
+
+ if (!tz || !tz->trips.hot.flags.valid)
+ return_VALUE(-EINVAL);
+
+ if (tz->temperature >= tz->trips.hot.temperature) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Hot trip point\n"));
+ tz->trips.hot.flags.enabled = 1;
+ }
+ else if (tz->trips.hot.flags.enabled)
+ tz->trips.hot.flags.enabled = 0;
+
+ result = acpi_bus_get_device(tz->handle, &device);
+ if (result)
+ return_VALUE(result);
+
+ acpi_bus_generate_event(device, ACPI_THERMAL_NOTIFY_HOT, tz->trips.hot.flags.enabled);
+
+ /* TBD: Call user-mode "sleep(S4)" function */
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_passive (
+ struct acpi_thermal *tz)
+{
+ int result = 0;
+ struct acpi_thermal_passive *passive = NULL;
+ int trend = 0;
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_passive");
+
+ if (!tz || !tz->trips.passive.flags.valid)
+ return_VALUE(-EINVAL);
+
+ passive = &(tz->trips.passive);
+
+ /*
+ * Above Trip?
+ * -----------
+ * Calculate the thermal trend (using the passive cooling equation)
+ * and modify the performance limit for all passive cooling devices
+ * accordingly. Note that we assume symmetry.
+ */
+ if (tz->temperature >= passive->temperature) {
+ trend = (passive->tc1 * (tz->temperature - tz->last_temperature)) + (passive->tc2 * (tz->temperature - passive->temperature));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n",
+ trend, passive->tc1, tz->temperature,
+ tz->last_temperature, passive->tc2,
+ tz->temperature, passive->temperature));
+ tz->trips.passive.flags.enabled = 1;
+ /* Heating up? */
+ if (trend > 0)
+ for (i=0; i<passive->devices.count; i++)
+ acpi_processor_set_thermal_limit(
+ passive->devices.handles[i],
+ ACPI_PROCESSOR_LIMIT_INCREMENT);
+ /* Cooling off? */
+ else if (trend < 0)
+ for (i=0; i<passive->devices.count; i++)
+ acpi_processor_set_thermal_limit(
+ passive->devices.handles[i],
+ ACPI_PROCESSOR_LIMIT_DECREMENT);
+ }
+
+ /*
+ * Below Trip?
+ * -----------
+ * Implement passive cooling hysteresis to slowly increase performance
+ * and avoid thrashing around the passive trip point. Note that we
+ * assume symmetry.
+ */
+ else if (tz->trips.passive.flags.enabled) {
+ for (i=0; i<passive->devices.count; i++)
+ result = acpi_processor_set_thermal_limit(
+ passive->devices.handles[i],
+ ACPI_PROCESSOR_LIMIT_DECREMENT);
+ if (result == 1) {
+ tz->trips.passive.flags.enabled = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Disabling passive cooling (zone is cool)\n"));
+ }
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_active (
+ struct acpi_thermal *tz)
+{
+ int result = 0;
+ struct acpi_thermal_active *active = NULL;
+ int i = 0;
+ int j = 0;
+ unsigned long maxtemp = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_active");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++) {
+
+ active = &(tz->trips.active[i]);
+ if (!active || !active->flags.valid)
+ break;
+
+ /*
+ * Above Threshold?
+ * ----------------
+ * If not already enabled, turn ON all cooling devices
+ * associated with this active threshold.
+ */
+ if (tz->temperature >= active->temperature) {
+ if (active->temperature > maxtemp)
+ tz->state.active_index = i, maxtemp = active->temperature;
+ if (!active->flags.enabled) {
+ for (j = 0; j < active->devices.count; j++) {
+ result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D0);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'on'\n", active->devices.handles[j]));
+ continue;
+ }
+ active->flags.enabled = 1;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'on'\n", active->devices.handles[j]));
+ }
+ }
+ }
+ /*
+ * Below Threshold?
+ * ----------------
+ * Turn OFF all cooling devices associated with this
+ * threshold.
+ */
+ else if (active->flags.enabled) {
+ for (j = 0; j < active->devices.count; j++) {
+ result = acpi_bus_set_power(active->devices.handles[j], ACPI_STATE_D3);
+ if (result) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Unable to turn cooling device [%p] 'off'\n", active->devices.handles[j]));
+ continue;
+ }
+ active->flags.enabled = 0;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Cooling device [%p] now 'off'\n", active->devices.handles[j]));
+ }
+ }
+ }
+
+ return_VALUE(0);
+}
+
+
+static void acpi_thermal_check (void *context);
+
+static void
+acpi_thermal_run (
+ unsigned long data)
+{
+ struct acpi_thermal *tz = (struct acpi_thermal *)data;
+ if (!tz->zombie)
+ acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+ acpi_thermal_check, (void *) data);
+}
+
+
+static void
+acpi_thermal_check (
+ void *data)
+{
+ int result = 0;
+ struct acpi_thermal *tz = (struct acpi_thermal *) data;
+ unsigned long sleep_time = 0;
+ int i = 0;
+ struct acpi_thermal_state state;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_check");
+
+ if (!tz) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
+ return_VOID;
+ }
+
+ state = tz->state;
+
+ result = acpi_thermal_get_temperature(tz);
+ if (result)
+ return_VOID;
+
+ memset(&tz->state, 0, sizeof(tz->state));
+
+ /*
+ * Check Trip Points
+ * -----------------
+ * Compare the current temperature to the trip point values to see
+ * if we've entered one of the thermal policy states. Note that
+ * this function determines when a state is entered, but the
+ * individual policy decides when it is exited (e.g. hysteresis).
+ */
+ if (tz->trips.critical.flags.valid)
+ state.critical |= (tz->temperature >= tz->trips.critical.temperature);
+ if (tz->trips.hot.flags.valid)
+ state.hot |= (tz->temperature >= tz->trips.hot.temperature);
+ if (tz->trips.passive.flags.valid)
+ state.passive |= (tz->temperature >= tz->trips.passive.temperature);
+ for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++)
+ if (tz->trips.active[i].flags.valid)
+ state.active |= (tz->temperature >= tz->trips.active[i].temperature);
+
+ /*
+ * Invoke Policy
+ * -------------
+ * Separated from the above check to allow individual policy to
+ * determine when to exit a given state.
+ */
+ if (state.critical)
+ acpi_thermal_critical(tz);
+ if (state.hot)
+ acpi_thermal_hot(tz);
+ if (state.passive)
+ acpi_thermal_passive(tz);
+ if (state.active)
+ acpi_thermal_active(tz);
+
+ /*
+ * Calculate State
+ * ---------------
+ * Again, separated from the above two to allow independent policy
+ * decisions.
+ */
+ if (tz->trips.critical.flags.enabled)
+ tz->state.critical = 1;
+ if (tz->trips.hot.flags.enabled)
+ tz->state.hot = 1;
+ if (tz->trips.passive.flags.enabled)
+ tz->state.passive = 1;
+ for (i=0; i<ACPI_THERMAL_MAX_ACTIVE; i++)
+ if (tz->trips.active[i].flags.enabled)
+ tz->state.active = 1;
+
+ /*
+ * Calculate Sleep Time
+ * --------------------
+ * If we're in the passive state, use _TSP's value. Otherwise
+ * use the default polling frequency (e.g. _TZP). If no polling
+ * frequency is specified then we'll wait forever (at least until
+ * a thermal event occurs). Note that _TSP and _TZD values are
+ * given in 1/10th seconds (we must covert to milliseconds).
+ */
+ if (tz->state.passive)
+ sleep_time = tz->trips.passive.tsp * 100;
+ else if (tz->polling_frequency > 0)
+ sleep_time = tz->polling_frequency * 100;
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s: temperature[%lu] sleep[%lu]\n",
+ tz->name, tz->temperature, sleep_time));
+
+ /*
+ * Schedule Next Poll
+ * ------------------
+ */
+ if (!sleep_time) {
+ if (timer_pending(&(tz->timer)))
+ del_timer(&(tz->timer));
+ }
+ else {
+ if (timer_pending(&(tz->timer)))
+ mod_timer(&(tz->timer), (HZ * sleep_time) / 1000);
+ else {
+ tz->timer.data = (unsigned long) tz;
+ tz->timer.function = acpi_thermal_run;
+ tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
+ add_timer(&(tz->timer));
+ }
+ }
+
+ return_VOID;
+}
+
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_thermal_dir;
+
+static int acpi_thermal_state_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_state_seq_show");
+
+ if (!tz)
+ goto end;
+
+ seq_puts(seq, "state: ");
+
+ if (!tz->state.critical && !tz->state.hot && !tz->state.passive && !tz->state.active)
+ seq_puts(seq, "ok\n");
+ else {
+ if (tz->state.critical)
+ seq_puts(seq, "critical ");
+ if (tz->state.hot)
+ seq_puts(seq, "hot ");
+ if (tz->state.passive)
+ seq_puts(seq, "passive ");
+ if (tz->state.active)
+ seq_printf(seq, "active[%d]", tz->state.active_index);
+ seq_puts(seq, "\n");
+ }
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_thermal_state_seq_show, PDE(inode)->data);
+}
+
+
+static int acpi_thermal_temp_seq_show(struct seq_file *seq, void *offset)
+{
+ int result = 0;
+ struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_temp_seq_show");
+
+ if (!tz)
+ goto end;
+
+ result = acpi_thermal_get_temperature(tz);
+ if (result)
+ goto end;
+
+ seq_printf(seq, "temperature: %ld C\n",
+ KELVIN_TO_CELSIUS(tz->temperature));
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_thermal_temp_seq_show, PDE(inode)->data);
+}
+
+
+static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+ int i = 0;
+ int j = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_trip_seq_show");
+
+ if (!tz)
+ goto end;
+
+ if (tz->trips.critical.flags.valid)
+ seq_printf(seq, "critical (S5): %ld C\n",
+ KELVIN_TO_CELSIUS(tz->trips.critical.temperature));
+
+ if (tz->trips.hot.flags.valid)
+ seq_printf(seq, "hot (S4): %ld C\n",
+ KELVIN_TO_CELSIUS(tz->trips.hot.temperature));
+
+ if (tz->trips.passive.flags.valid) {
+ seq_printf(seq, "passive: %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
+ KELVIN_TO_CELSIUS(tz->trips.passive.temperature),
+ tz->trips.passive.tc1,
+ tz->trips.passive.tc2,
+ tz->trips.passive.tsp);
+ for (j=0; j<tz->trips.passive.devices.count; j++) {
+
+ seq_printf(seq, "0x%p ", tz->trips.passive.devices.handles[j]);
+ }
+ seq_puts(seq, "\n");
+ }
+
+ for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
+ if (!(tz->trips.active[i].flags.valid))
+ break;
+ seq_printf(seq, "active[%d]: %ld C: devices=",
+ i, KELVIN_TO_CELSIUS(tz->trips.active[i].temperature));
+ for (j = 0; j < tz->trips.active[i].devices.count; j++)
+ seq_printf(seq, "0x%p ",
+ tz->trips.active[i].devices.handles[j]);
+ seq_puts(seq, "\n");
+ }
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_thermal_trip_seq_show, PDE(inode)->data);
+}
+
+static ssize_t
+acpi_thermal_write_trip_points (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+
+ char *limit_string;
+ int num, critical, hot, passive;
+ int *active;
+ int i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_write_trip_points");
+
+ limit_string = kmalloc(ACPI_THERMAL_MAX_LIMIT_STR_LEN, GFP_KERNEL);
+ if(!limit_string)
+ return_VALUE(-ENOMEM);
+
+ memset(limit_string, 0, ACPI_THERMAL_MAX_LIMIT_STR_LEN);
+
+ active = kmalloc(ACPI_THERMAL_MAX_ACTIVE *sizeof(int), GFP_KERNEL);
+ if(!active)
+ return_VALUE(-ENOMEM);
+
+ if (!tz || (count > ACPI_THERMAL_MAX_LIMIT_STR_LEN - 1)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
+ count = -EINVAL;
+ goto end;
+ }
+
+ if (copy_from_user(limit_string, buffer, count)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
+ count = -EFAULT;
+ goto end;
+ }
+
+ limit_string[count] = '\0';
+
+ num = sscanf(limit_string, "%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d:%d",
+ &critical, &hot, &passive,
+ &active[0], &active[1], &active[2], &active[3], &active[4],
+ &active[5], &active[6], &active[7], &active[8], &active[9]);
+ if(!(num >=5 && num < (ACPI_THERMAL_MAX_ACTIVE + 3))) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
+ count = -EINVAL;
+ goto end;
+ }
+
+ tz->trips.critical.temperature = CELSIUS_TO_KELVIN(critical);
+ tz->trips.hot.temperature = CELSIUS_TO_KELVIN(hot);
+ tz->trips.passive.temperature = CELSIUS_TO_KELVIN(passive);
+ for (i = 0; i < num - 3; i++) {
+ if (!(tz->trips.active[i].flags.valid))
+ break;
+ tz->trips.active[i].temperature = CELSIUS_TO_KELVIN(active[i]);
+ }
+
+end:
+ kfree(active);
+ kfree(limit_string);
+ return_VALUE(count);
+}
+
+
+static int acpi_thermal_cooling_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_cooling_seq_show");
+
+ if (!tz)
+ goto end;
+
+ if (!tz->flags.cooling_mode) {
+ seq_puts(seq, "<setting not supported>\n");
+ }
+
+ if ( tz->cooling_mode == ACPI_THERMAL_MODE_CRITICAL )
+ seq_printf(seq, "cooling mode: critical\n");
+ else
+ seq_printf(seq, "cooling mode: %s\n",
+ tz->cooling_mode?"passive":"active");
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_thermal_cooling_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_thermal_cooling_seq_show,
+ PDE(inode)->data);
+}
+
+static ssize_t
+acpi_thermal_write_cooling_mode (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+ int result = 0;
+ char mode_string[12] = {'\0'};
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_write_cooling_mode");
+
+ if (!tz || (count > sizeof(mode_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (!tz->flags.cooling_mode)
+ return_VALUE(-ENODEV);
+
+ if (copy_from_user(mode_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ mode_string[count] = '\0';
+
+ result = acpi_thermal_set_cooling_mode(tz,
+ simple_strtoul(mode_string, NULL, 0));
+ if (result)
+ return_VALUE(result);
+
+ acpi_thermal_check(tz);
+
+ return_VALUE(count);
+}
+
+
+static int acpi_thermal_polling_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_thermal *tz = (struct acpi_thermal *)seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_polling_seq_show");
+
+ if (!tz)
+ goto end;
+
+ if (!tz->polling_frequency) {
+ seq_puts(seq, "<polling disabled>\n");
+ goto end;
+ }
+
+ seq_printf(seq, "polling frequency: %lu seconds\n",
+ (tz->polling_frequency / 10));
+
+end:
+ return_VALUE(0);
+}
+
+static int acpi_thermal_polling_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, acpi_thermal_polling_seq_show,
+ PDE(inode)->data);
+}
+
+static ssize_t
+acpi_thermal_write_polling (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *ppos)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_thermal *tz = (struct acpi_thermal *)m->private;
+ int result = 0;
+ char polling_string[12] = {'\0'};
+ int seconds = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_write_polling");
+
+ if (!tz || (count > sizeof(polling_string) - 1))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(polling_string, buffer, count))
+ return_VALUE(-EFAULT);
+
+ polling_string[count] = '\0';
+
+ seconds = simple_strtoul(polling_string, NULL, 0);
+
+ result = acpi_thermal_set_polling(tz, seconds);
+ if (result)
+ return_VALUE(result);
+
+ acpi_thermal_check(tz);
+
+ return_VALUE(count);
+}
+
+
+static int
+acpi_thermal_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_add_fs");
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_thermal_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ acpi_device_dir(device)->owner = THIS_MODULE;
+ }
+
+ /* 'state' [R] */
+ entry = create_proc_entry(ACPI_THERMAL_FILE_STATE,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_THERMAL_FILE_STATE));
+ else {
+ entry->proc_fops = &acpi_thermal_state_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'temperature' [R] */
+ entry = create_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
+ S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_THERMAL_FILE_TEMPERATURE));
+ else {
+ entry->proc_fops = &acpi_thermal_temp_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'trip_points' [R/W] */
+ entry = create_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_THERMAL_FILE_TRIP_POINTS));
+ else {
+ entry->proc_fops = &acpi_thermal_trip_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'cooling_mode' [R/W] */
+ entry = create_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_THERMAL_FILE_COOLING_MODE));
+ else {
+ entry->proc_fops = &acpi_thermal_cooling_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'polling_frequency' [R/W] */
+ entry = create_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
+ S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create '%s' fs entry\n",
+ ACPI_THERMAL_FILE_POLLING_FREQ));
+ else {
+ entry->proc_fops = &acpi_thermal_polling_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_remove_fs (
+ struct acpi_device *device)
+{
+ ACPI_FUNCTION_TRACE("acpi_thermal_remove_fs");
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE,
+ acpi_device_dir(device));
+ remove_proc_entry(ACPI_THERMAL_FILE_STATE,
+ acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device), acpi_thermal_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+static void
+acpi_thermal_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_thermal *tz = (struct acpi_thermal *) data;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_notify");
+
+ if (!tz)
+ return_VOID;
+
+ if (acpi_bus_get_device(tz->handle, &device))
+ return_VOID;
+
+ switch (event) {
+ case ACPI_THERMAL_NOTIFY_TEMPERATURE:
+ acpi_thermal_check(tz);
+ break;
+ case ACPI_THERMAL_NOTIFY_THRESHOLDS:
+ acpi_thermal_get_trip_points(tz);
+ acpi_thermal_check(tz);
+ acpi_bus_generate_event(device, event, 0);
+ break;
+ case ACPI_THERMAL_NOTIFY_DEVICES:
+ if (tz->flags.devices)
+ acpi_thermal_get_devices(tz);
+ acpi_bus_generate_event(device, event, 0);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+
+static int
+acpi_thermal_get_info (
+ struct acpi_thermal *tz)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_get_info");
+
+ if (!tz)
+ return_VALUE(-EINVAL);
+
+ /* Get temperature [_TMP] (required) */
+ result = acpi_thermal_get_temperature(tz);
+ if (result)
+ return_VALUE(result);
+
+ /* Get trip points [_CRT, _PSV, etc.] (required) */
+ result = acpi_thermal_get_trip_points(tz);
+ if (result)
+ return_VALUE(result);
+
+ /* Set the cooling mode [_SCP] to active cooling (default) */
+ result = acpi_thermal_set_cooling_mode(tz, ACPI_THERMAL_MODE_ACTIVE);
+ if (!result)
+ tz->flags.cooling_mode = 1;
+ else {
+ /* Oh,we have not _SCP method.
+ Generally show cooling_mode by _ACx, _PSV,spec 12.2*/
+ tz->flags.cooling_mode = 0;
+ if ( tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) {
+ if ( tz->trips.passive.temperature > tz->trips.active[0].temperature )
+ tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
+ else
+ tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
+ } else if ( !tz->trips.active[0].flags.valid && tz->trips.passive.flags.valid ) {
+ tz->cooling_mode = ACPI_THERMAL_MODE_PASSIVE;
+ } else if ( tz->trips.active[0].flags.valid && !tz->trips.passive.flags.valid ) {
+ tz->cooling_mode = ACPI_THERMAL_MODE_ACTIVE;
+ } else {
+ /* _ACx and _PSV are optional, but _CRT is required */
+ tz->cooling_mode = ACPI_THERMAL_MODE_CRITICAL;
+ }
+ }
+
+ /* Get default polling frequency [_TZP] (optional) */
+ if (tzp)
+ tz->polling_frequency = tzp;
+ else
+ acpi_thermal_get_polling_frequency(tz);
+
+ /* Get devices in this thermal zone [_TZD] (optional) */
+ result = acpi_thermal_get_devices(tz);
+ if (!result)
+ tz->flags.devices = 1;
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_thermal_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = AE_OK;
+ struct acpi_thermal *tz = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ tz = kmalloc(sizeof(struct acpi_thermal), GFP_KERNEL);
+ if (!tz)
+ return_VALUE(-ENOMEM);
+ memset(tz, 0, sizeof(struct acpi_thermal));
+
+ tz->handle = device->handle;
+ strcpy(tz->name, device->pnp.bus_id);
+ strcpy(acpi_device_name(device), ACPI_THERMAL_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
+ acpi_driver_data(device) = tz;
+
+ result = acpi_thermal_get_info(tz);
+ if (result)
+ goto end;
+
+ result = acpi_thermal_add_fs(device);
+ if (result)
+ return_VALUE(result);
+
+ init_timer(&tz->timer);
+
+ acpi_thermal_check(tz);
+
+ status = acpi_install_notify_handler(tz->handle,
+ ACPI_DEVICE_NOTIFY, acpi_thermal_notify, tz);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
+ acpi_device_name(device), acpi_device_bid(device),
+ KELVIN_TO_CELSIUS(tz->temperature));
+
+end:
+ if (result) {
+ acpi_thermal_remove_fs(device);
+ kfree(tz);
+ }
+
+ return_VALUE(result);
+}
+
+
+static int
+acpi_thermal_remove (
+ struct acpi_device *device,
+ int type)
+{
+ acpi_status status = AE_OK;
+ struct acpi_thermal *tz = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ tz = (struct acpi_thermal *) acpi_driver_data(device);
+
+ /* avoid timer adding new defer task */
+ tz->zombie = 1;
+ /* wait for running timer (on other CPUs) finish */
+ del_timer_sync(&(tz->timer));
+ /* synchronize deferred task */
+ acpi_os_wait_events_complete(NULL);
+ /* deferred task may reinsert timer */
+ del_timer_sync(&(tz->timer));
+
+ status = acpi_remove_notify_handler(tz->handle,
+ ACPI_DEVICE_NOTIFY, acpi_thermal_notify);
+ if (ACPI_FAILURE(status))
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+
+ /* Terminate policy */
+ if (tz->trips.passive.flags.valid
+ && tz->trips.passive.flags.enabled) {
+ tz->trips.passive.flags.enabled = 0;
+ acpi_thermal_passive(tz);
+ }
+ if (tz->trips.active[0].flags.valid
+ && tz->trips.active[0].flags.enabled) {
+ tz->trips.active[0].flags.enabled = 0;
+ acpi_thermal_active(tz);
+ }
+
+ acpi_thermal_remove_fs(device);
+
+ kfree(tz);
+ return_VALUE(0);
+}
+
+
+static int __init
+acpi_thermal_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_thermal_init");
+
+ acpi_thermal_dir = proc_mkdir(ACPI_THERMAL_CLASS, acpi_root_dir);
+ if (!acpi_thermal_dir)
+ return_VALUE(-ENODEV);
+ acpi_thermal_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&acpi_thermal_driver);
+ if (result < 0) {
+ remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+
+static void __exit
+acpi_thermal_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_thermal_exit");
+
+ acpi_bus_unregister_driver(&acpi_thermal_driver);
+
+ remove_proc_entry(ACPI_THERMAL_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+
+
+module_init(acpi_thermal_init);
+module_exit(acpi_thermal_exit);
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
new file mode 100644
index 000000000000..c84997c9f964
--- /dev/null
+++ b/drivers/acpi/toshiba_acpi.c
@@ -0,0 +1,575 @@
+/*
+ * toshiba_acpi.c - Toshiba Laptop ACPI Extras
+ *
+ *
+ * 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 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
+ *
+ *
+ * The devolpment page for this driver is located at
+ * http://memebeam.org/toys/ToshibaAcpiDriver.
+ *
+ * Credits:
+ * Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
+ * engineering the Windows drivers
+ * Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
+ * Rob Miller - TV out and hotkeys help
+ *
+ *
+ * TODO
+ *
+ */
+
+#define TOSHIBA_ACPI_VERSION "0.18"
+#define PROC_INTERFACE_VERSION 1
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("John Belmonte");
+MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
+MODULE_LICENSE("GPL");
+
+#define MY_LOGPREFIX "toshiba_acpi: "
+#define MY_ERR KERN_ERR MY_LOGPREFIX
+#define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
+#define MY_INFO KERN_INFO MY_LOGPREFIX
+
+/* Toshiba ACPI method paths */
+#define METHOD_LCD_BRIGHTNESS "\\_SB_.PCI0.VGA_.LCD_._BCM"
+#define METHOD_HCI_1 "\\_SB_.VALD.GHCI"
+#define METHOD_HCI_2 "\\_SB_.VALZ.GHCI"
+#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
+
+/* Toshiba HCI interface definitions
+ *
+ * HCI is Toshiba's "Hardware Control Interface" which is supposed to
+ * be uniform across all their models. Ideally we would just call
+ * dedicated ACPI methods instead of using this primitive interface.
+ * However the ACPI methods seem to be incomplete in some areas (for
+ * example they allow setting, but not reading, the LCD brightness value),
+ * so this is still useful.
+ */
+
+#define HCI_WORDS 6
+
+/* operations */
+#define HCI_SET 0xff00
+#define HCI_GET 0xfe00
+
+/* return codes */
+#define HCI_SUCCESS 0x0000
+#define HCI_FAILURE 0x1000
+#define HCI_NOT_SUPPORTED 0x8000
+#define HCI_EMPTY 0x8c00
+
+/* registers */
+#define HCI_FAN 0x0004
+#define HCI_SYSTEM_EVENT 0x0016
+#define HCI_VIDEO_OUT 0x001c
+#define HCI_HOTKEY_EVENT 0x001e
+#define HCI_LCD_BRIGHTNESS 0x002a
+
+/* field definitions */
+#define HCI_LCD_BRIGHTNESS_BITS 3
+#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
+#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
+#define HCI_VIDEO_OUT_LCD 0x1
+#define HCI_VIDEO_OUT_CRT 0x2
+#define HCI_VIDEO_OUT_TV 0x4
+
+/* utility
+ */
+
+static __inline__ void
+_set_bit(u32* word, u32 mask, int value)
+{
+ *word = (*word & ~mask) | (mask * value);
+}
+
+/* acpi interface wrappers
+ */
+
+static int
+is_valid_acpi_path(const char* methodName)
+{
+ acpi_handle handle;
+ acpi_status status;
+
+ status = acpi_get_handle(NULL, (char*)methodName, &handle);
+ return !ACPI_FAILURE(status);
+}
+
+static int
+write_acpi_int(const char* methodName, int val)
+{
+ struct acpi_object_list params;
+ union acpi_object in_objs[1];
+ acpi_status status;
+
+ params.count = sizeof(in_objs)/sizeof(in_objs[0]);
+ params.pointer = in_objs;
+ in_objs[0].type = ACPI_TYPE_INTEGER;
+ in_objs[0].integer.value = val;
+
+ status = acpi_evaluate_object(NULL, (char*)methodName, &params, NULL);
+ return (status == AE_OK);
+}
+
+#if 0
+static int
+read_acpi_int(const char* methodName, int* pVal)
+{
+ struct acpi_buffer results;
+ union acpi_object out_objs[1];
+ acpi_status status;
+
+ results.length = sizeof(out_objs);
+ results.pointer = out_objs;
+
+ status = acpi_evaluate_object(0, (char*)methodName, 0, &results);
+ *pVal = out_objs[0].integer.value;
+
+ return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER);
+}
+#endif
+
+static const char* method_hci /*= 0*/;
+
+/* Perform a raw HCI call. Here we don't care about input or output buffer
+ * format.
+ */
+static acpi_status
+hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
+{
+ struct acpi_object_list params;
+ union acpi_object in_objs[HCI_WORDS];
+ struct acpi_buffer results;
+ union acpi_object out_objs[HCI_WORDS+1];
+ acpi_status status;
+ int i;
+
+ params.count = HCI_WORDS;
+ params.pointer = in_objs;
+ for (i = 0; i < HCI_WORDS; ++i) {
+ in_objs[i].type = ACPI_TYPE_INTEGER;
+ in_objs[i].integer.value = in[i];
+ }
+
+ results.length = sizeof(out_objs);
+ results.pointer = out_objs;
+
+ status = acpi_evaluate_object(NULL, (char*)method_hci, &params,
+ &results);
+ if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
+ for (i = 0; i < out_objs->package.count; ++i) {
+ out[i] = out_objs->package.elements[i].integer.value;
+ }
+ }
+
+ return status;
+}
+
+/* common hci tasks (get or set one value)
+ *
+ * In addition to the ACPI status, the HCI system returns a result which
+ * may be useful (such as "not supported").
+ */
+
+static acpi_status
+hci_write1(u32 reg, u32 in1, u32* result)
+{
+ u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status = hci_raw(in, out);
+ *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+ return status;
+}
+
+static acpi_status
+hci_read1(u32 reg, u32* out1, u32* result)
+{
+ u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
+ u32 out[HCI_WORDS];
+ acpi_status status = hci_raw(in, out);
+ *out1 = out[2];
+ *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+ return status;
+}
+
+static struct proc_dir_entry* toshiba_proc_dir /*= 0*/;
+static int force_fan;
+static int last_key_event;
+static int key_event_valid;
+
+typedef struct _ProcItem
+{
+ const char* name;
+ char* (*read_func)(char*);
+ unsigned long (*write_func)(const char*, unsigned long);
+} ProcItem;
+
+/* proc file handlers
+ */
+
+static int
+dispatch_read(char* page, char** start, off_t off, int count, int* eof,
+ ProcItem* item)
+{
+ char* p = page;
+ int len;
+
+ if (off == 0)
+ p = item->read_func(p);
+
+ /* ISSUE: I don't understand this code */
+ len = (p - page);
+ if (len <= off+count) *eof = 1;
+ *start = page + off;
+ len -= off;
+ if (len>count) len = count;
+ if (len<0) len = 0;
+ return len;
+}
+
+static int
+dispatch_write(struct file* file, const char __user * buffer,
+ unsigned long count, ProcItem* item)
+{
+ int result;
+ char* tmp_buffer;
+
+ /* Arg buffer points to userspace memory, which can't be accessed
+ * directly. Since we're making a copy, zero-terminate the
+ * destination so that sscanf can be used on it safely.
+ */
+ tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
+ if (copy_from_user(tmp_buffer, buffer, count)) {
+ result = -EFAULT;
+ }
+ else {
+ tmp_buffer[count] = 0;
+ result = item->write_func(tmp_buffer, count);
+ }
+ kfree(tmp_buffer);
+ return result;
+}
+
+static char*
+read_lcd(char* p)
+{
+ u32 hci_result;
+ u32 value;
+
+ hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
+ if (hci_result == HCI_SUCCESS) {
+ value = value >> HCI_LCD_BRIGHTNESS_SHIFT;
+ p += sprintf(p, "brightness: %d\n", value);
+ p += sprintf(p, "brightness_levels: %d\n",
+ HCI_LCD_BRIGHTNESS_LEVELS);
+ } else {
+ printk(MY_ERR "Error reading LCD brightness\n");
+ }
+
+ return p;
+}
+
+static unsigned long
+write_lcd(const char* buffer, unsigned long count)
+{
+ int value;
+ u32 hci_result;
+
+ if (sscanf(buffer, " brightness : %i", &value) == 1 &&
+ value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
+ value = value << HCI_LCD_BRIGHTNESS_SHIFT;
+ hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
+ if (hci_result != HCI_SUCCESS)
+ return -EFAULT;
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static char*
+read_video(char* p)
+{
+ u32 hci_result;
+ u32 value;
+
+ hci_read1(HCI_VIDEO_OUT, &value, &hci_result);
+ if (hci_result == HCI_SUCCESS) {
+ int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
+ int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
+ int is_tv = (value & HCI_VIDEO_OUT_TV ) ? 1 : 0;
+ p += sprintf(p, "lcd_out: %d\n", is_lcd);
+ p += sprintf(p, "crt_out: %d\n", is_crt);
+ p += sprintf(p, "tv_out: %d\n", is_tv);
+ } else {
+ printk(MY_ERR "Error reading video out status\n");
+ }
+
+ return p;
+}
+
+static unsigned long
+write_video(const char* buffer, unsigned long count)
+{
+ int value;
+ int remain = count;
+ int lcd_out = -1;
+ int crt_out = -1;
+ int tv_out = -1;
+ u32 hci_result;
+ int video_out;
+
+ /* scan expression. Multiple expressions may be delimited with ;
+ *
+ * NOTE: to keep scanning simple, invalid fields are ignored
+ */
+ while (remain) {
+ if (sscanf(buffer, " lcd_out : %i", &value) == 1)
+ lcd_out = value & 1;
+ else if (sscanf(buffer, " crt_out : %i", &value) == 1)
+ crt_out = value & 1;
+ else if (sscanf(buffer, " tv_out : %i", &value) == 1)
+ tv_out = value & 1;
+ /* advance to one character past the next ; */
+ do {
+ ++buffer;
+ --remain;
+ }
+ while (remain && *(buffer-1) != ';');
+ }
+
+ hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
+ if (hci_result == HCI_SUCCESS) {
+ int new_video_out = video_out;
+ if (lcd_out != -1)
+ _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
+ if (crt_out != -1)
+ _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
+ if (tv_out != -1)
+ _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
+ /* To avoid unnecessary video disruption, only write the new
+ * video setting if something changed. */
+ if (new_video_out != video_out)
+ write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
+ } else {
+ return -EFAULT;
+ }
+
+ return count;
+}
+
+static char*
+read_fan(char* p)
+{
+ u32 hci_result;
+ u32 value;
+
+ hci_read1(HCI_FAN, &value, &hci_result);
+ if (hci_result == HCI_SUCCESS) {
+ p += sprintf(p, "running: %d\n", (value > 0));
+ p += sprintf(p, "force_on: %d\n", force_fan);
+ } else {
+ printk(MY_ERR "Error reading fan status\n");
+ }
+
+ return p;
+}
+
+static unsigned long
+write_fan(const char* buffer, unsigned long count)
+{
+ int value;
+ u32 hci_result;
+
+ if (sscanf(buffer, " force_on : %i", &value) == 1 &&
+ value >= 0 && value <= 1) {
+ hci_write1(HCI_FAN, value, &hci_result);
+ if (hci_result != HCI_SUCCESS)
+ return -EFAULT;
+ else
+ force_fan = value;
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static char*
+read_keys(char* p)
+{
+ u32 hci_result;
+ u32 value;
+
+ if (!key_event_valid) {
+ hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
+ if (hci_result == HCI_SUCCESS) {
+ key_event_valid = 1;
+ last_key_event = value;
+ } else if (hci_result == HCI_EMPTY) {
+ /* better luck next time */
+ } else if (hci_result == HCI_NOT_SUPPORTED) {
+ /* This is a workaround for an unresolved issue on
+ * some machines where system events sporadically
+ * become disabled. */
+ hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
+ printk(MY_NOTICE "Re-enabled hotkeys\n");
+ } else {
+ printk(MY_ERR "Error reading hotkey status\n");
+ goto end;
+ }
+ }
+
+ p += sprintf(p, "hotkey_ready: %d\n", key_event_valid);
+ p += sprintf(p, "hotkey: 0x%04x\n", last_key_event);
+
+end:
+ return p;
+}
+
+static unsigned long
+write_keys(const char* buffer, unsigned long count)
+{
+ int value;
+
+ if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 &&
+ value == 0) {
+ key_event_valid = 0;
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+static char*
+read_version(char* p)
+{
+ p += sprintf(p, "driver: %s\n", TOSHIBA_ACPI_VERSION);
+ p += sprintf(p, "proc_interface: %d\n",
+ PROC_INTERFACE_VERSION);
+ return p;
+}
+
+/* proc and module init
+ */
+
+#define PROC_TOSHIBA "toshiba"
+
+static ProcItem proc_items[] =
+{
+ { "lcd" , read_lcd , write_lcd },
+ { "video" , read_video , write_video },
+ { "fan" , read_fan , write_fan },
+ { "keys" , read_keys , write_keys },
+ { "version" , read_version , NULL },
+ { NULL }
+};
+
+static acpi_status __init
+add_device(void)
+{
+ struct proc_dir_entry* proc;
+ ProcItem* item;
+
+ for (item = proc_items; item->name; ++item)
+ {
+ proc = create_proc_read_entry(item->name,
+ S_IFREG | S_IRUGO | S_IWUSR,
+ toshiba_proc_dir, (read_proc_t*)dispatch_read, item);
+ if (proc)
+ proc->owner = THIS_MODULE;
+ if (proc && item->write_func)
+ proc->write_proc = (write_proc_t*)dispatch_write;
+ }
+
+ return AE_OK;
+}
+
+static acpi_status __exit
+remove_device(void)
+{
+ ProcItem* item;
+
+ for (item = proc_items; item->name; ++item)
+ remove_proc_entry(item->name, toshiba_proc_dir);
+ return AE_OK;
+}
+
+static int __init
+toshiba_acpi_init(void)
+{
+ acpi_status status = AE_OK;
+ u32 hci_result;
+
+ if (acpi_disabled)
+ return -ENODEV;
+ /* simple device detection: look for HCI method */
+ if (is_valid_acpi_path(METHOD_HCI_1))
+ method_hci = METHOD_HCI_1;
+ else if (is_valid_acpi_path(METHOD_HCI_2))
+ method_hci = METHOD_HCI_2;
+ else
+ return -ENODEV;
+
+ printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
+ TOSHIBA_ACPI_VERSION);
+ printk(MY_INFO " HCI method: %s\n", method_hci);
+
+ force_fan = 0;
+ key_event_valid = 0;
+
+ /* enable event fifo */
+ hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
+
+ toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
+ if (!toshiba_proc_dir) {
+ status = AE_ERROR;
+ } else {
+ toshiba_proc_dir->owner = THIS_MODULE;
+ status = add_device();
+ if (ACPI_FAILURE(status))
+ remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+ }
+
+ return (ACPI_SUCCESS(status)) ? 0 : -ENODEV;
+}
+
+static void __exit
+toshiba_acpi_exit(void)
+{
+ remove_device();
+
+ if (toshiba_proc_dir)
+ remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+
+ return;
+}
+
+module_init(toshiba_acpi_init);
+module_exit(toshiba_acpi_exit);
diff --git a/drivers/acpi/utilities/Makefile b/drivers/acpi/utilities/Makefile
new file mode 100644
index 000000000000..939c447dd52a
--- /dev/null
+++ b/drivers/acpi/utilities/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for all Linux ACPI interpreter subdirectories
+#
+
+obj-y := utalloc.o utdebug.o uteval.o utinit.o utmisc.o utxface.o \
+ utcopy.o utdelete.o utglobal.o utmath.o utobject.o
+
+EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
new file mode 100644
index 000000000000..3313439c4bc7
--- /dev/null
+++ b/drivers/acpi/utilities/utalloc.c
@@ -0,0 +1,988 @@
+/******************************************************************************
+ *
+ * Module Name: utalloc - local cache and memory allocation routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utalloc")
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ut_release_to_cache
+ *
+ * PARAMETERS: list_id - Memory list/cache ID
+ * Object - The object to be released
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Release an object to the specified cache. If cache is full,
+ * the object is deleted.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_release_to_cache (
+ u32 list_id,
+ void *object)
+{
+ struct acpi_memory_list *cache_info;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ cache_info = &acpi_gbl_memory_lists[list_id];
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+
+ /* If walk cache is full, just free this wallkstate object */
+
+ if (cache_info->cache_depth >= cache_info->max_cache_depth) {
+ ACPI_MEM_FREE (object);
+ ACPI_MEM_TRACKING (cache_info->total_freed++);
+ }
+
+ /* Otherwise put this object back into the cache */
+
+ else {
+ if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) {
+ return;
+ }
+
+ /* Mark the object as cached */
+
+ ACPI_MEMSET (object, 0xCA, cache_info->object_size);
+ ACPI_SET_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_CACHED);
+
+ /* Put the object at the head of the cache list */
+
+ * (ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head;
+ cache_info->list_head = object;
+ cache_info->cache_depth++;
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_CACHES);
+ }
+
+#else
+
+ /* Object cache is disabled; just free the object */
+
+ ACPI_MEM_FREE (object);
+ ACPI_MEM_TRACKING (cache_info->total_freed++);
+#endif
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ut_acquire_from_cache
+ *
+ * PARAMETERS: list_id - Memory list ID
+ *
+ * RETURN: A requested object. NULL if the object could not be
+ * allocated.
+ *
+ * DESCRIPTION: Get an object from the specified cache. If cache is empty,
+ * the object is allocated.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ut_acquire_from_cache (
+ u32 list_id)
+{
+ struct acpi_memory_list *cache_info;
+ void *object;
+
+
+ ACPI_FUNCTION_NAME ("ut_acquire_from_cache");
+
+
+ cache_info = &acpi_gbl_memory_lists[list_id];
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+
+ if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES))) {
+ return (NULL);
+ }
+
+ ACPI_MEM_TRACKING (cache_info->cache_requests++);
+
+ /* Check the cache first */
+
+ if (cache_info->list_head) {
+ /* There is an object available, use it */
+
+ object = cache_info->list_head;
+ cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset])));
+
+ ACPI_MEM_TRACKING (cache_info->cache_hits++);
+ cache_info->cache_depth--;
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p from %s\n",
+ object, acpi_gbl_memory_lists[list_id].list_name));
+#endif
+
+ if (ACPI_FAILURE (acpi_ut_release_mutex (ACPI_MTX_CACHES))) {
+ return (NULL);
+ }
+
+ /* Clear (zero) the previously used Object */
+
+ ACPI_MEMSET (object, 0, cache_info->object_size);
+ }
+
+ else {
+ /* The cache is empty, create a new object */
+
+ /* Avoid deadlock with ACPI_MEM_CALLOCATE */
+
+ if (ACPI_FAILURE (acpi_ut_release_mutex (ACPI_MTX_CACHES))) {
+ return (NULL);
+ }
+
+ object = ACPI_MEM_CALLOCATE (cache_info->object_size);
+ ACPI_MEM_TRACKING (cache_info->total_allocated++);
+ }
+
+#else
+
+ /* Object cache is disabled; just allocate the object */
+
+ object = ACPI_MEM_CALLOCATE (cache_info->object_size);
+ ACPI_MEM_TRACKING (cache_info->total_allocated++);
+#endif
+
+ return (object);
+}
+
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_generic_cache
+ *
+ * PARAMETERS: list_id - Memory list ID
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Free all objects within the requested cache.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_delete_generic_cache (
+ u32 list_id)
+{
+ struct acpi_memory_list *cache_info;
+ char *next;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ cache_info = &acpi_gbl_memory_lists[list_id];
+ while (cache_info->list_head) {
+ /* Delete one cached state object */
+
+ next = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) cache_info->list_head)[cache_info->link_offset])));
+ ACPI_MEM_FREE (cache_info->list_head);
+
+ cache_info->list_head = next;
+ cache_info->cache_depth--;
+ }
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_validate_buffer
+ *
+ * PARAMETERS: Buffer - Buffer descriptor to be validated
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Perform parameter validation checks on an struct acpi_buffer
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_validate_buffer (
+ struct acpi_buffer *buffer)
+{
+
+ /* Obviously, the structure pointer must be valid */
+
+ if (!buffer) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /* Special semantics for the length */
+
+ if ((buffer->length == ACPI_NO_BUFFER) ||
+ (buffer->length == ACPI_ALLOCATE_BUFFER) ||
+ (buffer->length == ACPI_ALLOCATE_LOCAL_BUFFER)) {
+ return (AE_OK);
+ }
+
+ /* Length is valid, the buffer pointer must be also */
+
+ if (!buffer->pointer) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_initialize_buffer
+ *
+ * PARAMETERS: Buffer - Buffer to be validated
+ * required_length - Length needed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Validate that the buffer is of the required length or
+ * allocate a new buffer. Returned buffer is always zeroed.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_initialize_buffer (
+ struct acpi_buffer *buffer,
+ acpi_size required_length)
+{
+ acpi_status status = AE_OK;
+
+
+ switch (buffer->length) {
+ case ACPI_NO_BUFFER:
+
+ /* Set the exception and returned the required length */
+
+ status = AE_BUFFER_OVERFLOW;
+ break;
+
+
+ case ACPI_ALLOCATE_BUFFER:
+
+ /* Allocate a new buffer */
+
+ buffer->pointer = acpi_os_allocate (required_length);
+ if (!buffer->pointer) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Clear the buffer */
+
+ ACPI_MEMSET (buffer->pointer, 0, required_length);
+ break;
+
+
+ case ACPI_ALLOCATE_LOCAL_BUFFER:
+
+ /* Allocate a new buffer with local interface to allow tracking */
+
+ buffer->pointer = ACPI_MEM_CALLOCATE (required_length);
+ if (!buffer->pointer) {
+ return (AE_NO_MEMORY);
+ }
+ break;
+
+
+ default:
+
+ /* Existing buffer: Validate the size of the buffer */
+
+ if (buffer->length < required_length) {
+ status = AE_BUFFER_OVERFLOW;
+ break;
+ }
+
+ /* Clear the buffer */
+
+ ACPI_MEMSET (buffer->pointer, 0, required_length);
+ break;
+ }
+
+ buffer->length = required_length;
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_allocate
+ *
+ * PARAMETERS: Size - Size of the allocation
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: Address of the allocated memory on success, NULL on failure.
+ *
+ * DESCRIPTION: The subsystem's equivalent of malloc.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ut_allocate (
+ acpi_size size,
+ u32 component,
+ char *module,
+ u32 line)
+{
+ void *allocation;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ut_allocate", size);
+
+
+ /* Check for an inadvertent size of zero bytes */
+
+ if (!size) {
+ _ACPI_REPORT_ERROR (module, line, component,
+ ("ut_allocate: Attempt to allocate zero bytes\n"));
+ size = 1;
+ }
+
+ allocation = acpi_os_allocate (size);
+ if (!allocation) {
+ /* Report allocation error */
+
+ _ACPI_REPORT_ERROR (module, line, component,
+ ("ut_allocate: Could not allocate size %X\n", (u32) size));
+
+ return_PTR (NULL);
+ }
+
+ return_PTR (allocation);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_callocate
+ *
+ * PARAMETERS: Size - Size of the allocation
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: Address of the allocated memory on success, NULL on failure.
+ *
+ * DESCRIPTION: Subsystem equivalent of calloc.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ut_callocate (
+ acpi_size size,
+ u32 component,
+ char *module,
+ u32 line)
+{
+ void *allocation;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ut_callocate", size);
+
+
+ /* Check for an inadvertent size of zero bytes */
+
+ if (!size) {
+ _ACPI_REPORT_ERROR (module, line, component,
+ ("ut_callocate: Attempt to allocate zero bytes\n"));
+ return_PTR (NULL);
+ }
+
+ allocation = acpi_os_allocate (size);
+ if (!allocation) {
+ /* Report allocation error */
+
+ _ACPI_REPORT_ERROR (module, line, component,
+ ("ut_callocate: Could not allocate size %X\n", (u32) size));
+ return_PTR (NULL);
+ }
+
+ /* Clear the memory block */
+
+ ACPI_MEMSET (allocation, 0, size);
+ return_PTR (allocation);
+}
+
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+/*
+ * These procedures are used for tracking memory leaks in the subsystem, and
+ * they get compiled out when the ACPI_DBG_TRACK_ALLOCATIONS is not set.
+ *
+ * Each memory allocation is tracked via a doubly linked list. Each
+ * element contains the caller's component, module name, function name, and
+ * line number. acpi_ut_allocate and acpi_ut_callocate call
+ * acpi_ut_track_allocation to add an element to the list; deletion
+ * occurs in the body of acpi_ut_free.
+ */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_allocate_and_track
+ *
+ * PARAMETERS: Size - Size of the allocation
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: Address of the allocated memory on success, NULL on failure.
+ *
+ * DESCRIPTION: The subsystem's equivalent of malloc.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ut_allocate_and_track (
+ acpi_size size,
+ u32 component,
+ char *module,
+ u32 line)
+{
+ struct acpi_debug_mem_block *allocation;
+ acpi_status status;
+
+
+ allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), component,
+ module, line);
+ if (!allocation) {
+ return (NULL);
+ }
+
+ status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, allocation, size,
+ ACPI_MEM_MALLOC, component, module, line);
+ if (ACPI_FAILURE (status)) {
+ acpi_os_free (allocation);
+ return (NULL);
+ }
+
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++;
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += (u32) size;
+
+ return ((void *) &allocation->user_space);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_callocate_and_track
+ *
+ * PARAMETERS: Size - Size of the allocation
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: Address of the allocated memory on success, NULL on failure.
+ *
+ * DESCRIPTION: Subsystem equivalent of calloc.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ut_callocate_and_track (
+ acpi_size size,
+ u32 component,
+ char *module,
+ u32 line)
+{
+ struct acpi_debug_mem_block *allocation;
+ acpi_status status;
+
+
+ allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), component,
+ module, line);
+ if (!allocation) {
+ /* Report allocation error */
+
+ _ACPI_REPORT_ERROR (module, line, component,
+ ("ut_callocate: Could not allocate size %X\n", (u32) size));
+ return (NULL);
+ }
+
+ status = acpi_ut_track_allocation (ACPI_MEM_LIST_GLOBAL, allocation, size,
+ ACPI_MEM_CALLOC, component, module, line);
+ if (ACPI_FAILURE (status)) {
+ acpi_os_free (allocation);
+ return (NULL);
+ }
+
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_allocated++;
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size += (u32) size;
+
+ return ((void *) &allocation->user_space);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_free_and_track
+ *
+ * PARAMETERS: Allocation - Address of the memory to deallocate
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Frees the memory at Allocation
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_free_and_track (
+ void *allocation,
+ u32 component,
+ char *module,
+ u32 line)
+{
+ struct acpi_debug_mem_block *debug_block;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_free", allocation);
+
+
+ if (NULL == allocation) {
+ _ACPI_REPORT_ERROR (module, line, component,
+ ("acpi_ut_free: Attempt to delete a NULL address\n"));
+
+ return_VOID;
+ }
+
+ debug_block = ACPI_CAST_PTR (struct acpi_debug_mem_block,
+ (((char *) allocation) - sizeof (struct acpi_debug_mem_header)));
+
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].total_freed++;
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].current_total_size -= debug_block->size;
+
+ status = acpi_ut_remove_allocation (ACPI_MEM_LIST_GLOBAL, debug_block,
+ component, module, line);
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not free memory, %s\n",
+ acpi_format_exception (status)));
+ }
+
+ acpi_os_free (debug_block);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p freed\n", allocation));
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_find_allocation
+ *
+ * PARAMETERS: list_id - Memory list to search
+ * Allocation - Address of allocated memory
+ *
+ * RETURN: A list element if found; NULL otherwise.
+ *
+ * DESCRIPTION: Searches for an element in the global allocation tracking list.
+ *
+ ******************************************************************************/
+
+struct acpi_debug_mem_block *
+acpi_ut_find_allocation (
+ u32 list_id,
+ void *allocation)
+{
+ struct acpi_debug_mem_block *element;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if (list_id > ACPI_MEM_LIST_MAX) {
+ return (NULL);
+ }
+
+ element = acpi_gbl_memory_lists[list_id].list_head;
+
+ /* Search for the address. */
+
+ while (element) {
+ if (element == allocation) {
+ return (element);
+ }
+
+ element = element->next;
+ }
+
+ return (NULL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_track_allocation
+ *
+ * PARAMETERS: list_id - Memory list to search
+ * Allocation - Address of allocated memory
+ * Size - Size of the allocation
+ * alloc_type - MEM_MALLOC or MEM_CALLOC
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Inserts an element into the global allocation tracking list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_track_allocation (
+ u32 list_id,
+ struct acpi_debug_mem_block *allocation,
+ acpi_size size,
+ u8 alloc_type,
+ u32 component,
+ char *module,
+ u32 line)
+{
+ struct acpi_memory_list *mem_list;
+ struct acpi_debug_mem_block *element;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_track_allocation", allocation);
+
+
+ if (list_id > ACPI_MEM_LIST_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ mem_list = &acpi_gbl_memory_lists[list_id];
+ status = acpi_ut_acquire_mutex (ACPI_MTX_MEMORY);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Search list for this address to make sure it is not already on the list.
+ * This will catch several kinds of problems.
+ */
+
+ element = acpi_ut_find_allocation (list_id, allocation);
+ if (element) {
+ ACPI_REPORT_ERROR (("ut_track_allocation: Allocation already present in list! (%p)\n",
+ allocation));
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", element, allocation));
+
+ goto unlock_and_exit;
+ }
+
+ /* Fill in the instance data. */
+
+ allocation->size = (u32) size;
+ allocation->alloc_type = alloc_type;
+ allocation->component = component;
+ allocation->line = line;
+
+ ACPI_STRNCPY (allocation->module, module, ACPI_MAX_MODULE_NAME);
+ allocation->module[ACPI_MAX_MODULE_NAME-1] = 0;
+
+ /* Insert at list head */
+
+ if (mem_list->list_head) {
+ ((struct acpi_debug_mem_block *)(mem_list->list_head))->previous = allocation;
+ }
+
+ allocation->next = mem_list->list_head;
+ allocation->previous = NULL;
+
+ mem_list->list_head = allocation;
+
+
+unlock_and_exit:
+ status = acpi_ut_release_mutex (ACPI_MTX_MEMORY);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_remove_allocation
+ *
+ * PARAMETERS: list_id - Memory list to search
+ * Allocation - Address of allocated memory
+ * Component - Component type of caller
+ * Module - Source file name of caller
+ * Line - Line number of caller
+ *
+ * RETURN:
+ *
+ * DESCRIPTION: Deletes an element from the global allocation tracking list.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_remove_allocation (
+ u32 list_id,
+ struct acpi_debug_mem_block *allocation,
+ u32 component,
+ char *module,
+ u32 line)
+{
+ struct acpi_memory_list *mem_list;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_remove_allocation");
+
+
+ if (list_id > ACPI_MEM_LIST_MAX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ mem_list = &acpi_gbl_memory_lists[list_id];
+ if (NULL == mem_list->list_head) {
+ /* No allocations! */
+
+ _ACPI_REPORT_ERROR (module, line, component,
+ ("ut_remove_allocation: Empty allocation list, nothing to free!\n"));
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ status = acpi_ut_acquire_mutex (ACPI_MTX_MEMORY);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Unlink */
+
+ if (allocation->previous) {
+ (allocation->previous)->next = allocation->next;
+ }
+ else {
+ mem_list->list_head = allocation->next;
+ }
+
+ if (allocation->next) {
+ (allocation->next)->previous = allocation->previous;
+ }
+
+ /* Mark the segment as deleted */
+
+ ACPI_MEMSET (&allocation->user_space, 0xEA, allocation->size);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", allocation->size));
+
+ status = acpi_ut_release_mutex (ACPI_MTX_MEMORY);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_dump_allocation_info
+ *
+ * PARAMETERS:
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print some info about the outstanding allocations.
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+void
+acpi_ut_dump_allocation_info (
+ void)
+{
+/*
+ struct acpi_memory_list *mem_list;
+*/
+
+ ACPI_FUNCTION_TRACE ("ut_dump_allocation_info");
+
+/*
+ ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
+ ("%30s: %4d (%3d Kb)\n", "Current allocations",
+ mem_list->current_count,
+ ROUND_UP_TO_1K (mem_list->current_size)));
+
+ ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
+ ("%30s: %4d (%3d Kb)\n", "Max concurrent allocations",
+ mem_list->max_concurrent_count,
+ ROUND_UP_TO_1K (mem_list->max_concurrent_size)));
+
+
+ ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
+ ("%30s: %4d (%3d Kb)\n", "Total (all) internal objects",
+ running_object_count,
+ ROUND_UP_TO_1K (running_object_size)));
+
+ ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
+ ("%30s: %4d (%3d Kb)\n", "Total (all) allocations",
+ running_alloc_count,
+ ROUND_UP_TO_1K (running_alloc_size)));
+
+
+ ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
+ ("%30s: %4d (%3d Kb)\n", "Current Nodes",
+ acpi_gbl_current_node_count,
+ ROUND_UP_TO_1K (acpi_gbl_current_node_size)));
+
+ ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
+ ("%30s: %4d (%3d Kb)\n", "Max Nodes",
+ acpi_gbl_max_concurrent_node_count,
+ ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * sizeof (struct acpi_namespace_node)))));
+*/
+ return_VOID;
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_dump_allocations
+ *
+ * PARAMETERS: Component - Component(s) to dump info for.
+ * Module - Module to dump info for. NULL means all.
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print a list of all outstanding allocations.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_dump_allocations (
+ u32 component,
+ char *module)
+{
+ struct acpi_debug_mem_block *element;
+ union acpi_descriptor *descriptor;
+ u32 num_outstanding = 0;
+
+
+ ACPI_FUNCTION_TRACE ("ut_dump_allocations");
+
+
+ /*
+ * Walk the allocation list.
+ */
+ if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_MEMORY))) {
+ return;
+ }
+
+ element = acpi_gbl_memory_lists[0].list_head;
+ while (element) {
+ if ((element->component & component) &&
+ ((module == NULL) || (0 == ACPI_STRCMP (module, element->module)))) {
+ /* Ignore allocated objects that are in a cache */
+
+ descriptor = ACPI_CAST_PTR (union acpi_descriptor, &element->user_space);
+ if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) {
+ acpi_os_printf ("%p Len %04X %9.9s-%d [%s] ",
+ descriptor, element->size, element->module,
+ element->line, acpi_ut_get_descriptor_name (descriptor));
+
+ /* Most of the elements will be Operand objects. */
+
+ switch (ACPI_GET_DESCRIPTOR_TYPE (descriptor)) {
+ case ACPI_DESC_TYPE_OPERAND:
+ acpi_os_printf ("%12.12s R%hd",
+ acpi_ut_get_type_name (descriptor->object.common.type),
+ descriptor->object.common.reference_count);
+ break;
+
+ case ACPI_DESC_TYPE_PARSER:
+ acpi_os_printf ("aml_opcode %04hX",
+ descriptor->op.asl.aml_opcode);
+ break;
+
+ case ACPI_DESC_TYPE_NAMED:
+ acpi_os_printf ("%4.4s",
+ acpi_ut_get_node_name (&descriptor->node));
+ break;
+
+ default:
+ break;
+ }
+
+ acpi_os_printf ( "\n");
+ num_outstanding++;
+ }
+ }
+ element = element->next;
+ }
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_MEMORY);
+
+ /* Print summary */
+
+ if (!num_outstanding) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "No outstanding allocations.\n"));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "%d(%X) Outstanding allocations\n",
+ num_outstanding, num_outstanding));
+ }
+
+ return_VOID;
+}
+
+
+#endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */
+
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
new file mode 100644
index 000000000000..0fcd98bde0d1
--- /dev/null
+++ b/drivers/acpi/utilities/utcopy.c
@@ -0,0 +1,930 @@
+/******************************************************************************
+ *
+ * Module Name: utcopy - Internal to external object translation utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utcopy")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_isimple_to_esimple
+ *
+ * PARAMETERS: *internal_object - Pointer to the object we are examining
+ * *Buffer - Where the object is returned
+ * *space_used - Where the data length is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to place a simple object in a user
+ * buffer.
+ *
+ * The buffer is assumed to have sufficient space for the object.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_copy_isimple_to_esimple (
+ union acpi_operand_object *internal_object,
+ union acpi_object *external_object,
+ u8 *data_space,
+ acpi_size *buffer_space_used)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_isimple_to_esimple");
+
+
+ *buffer_space_used = 0;
+
+ /*
+ * Check for NULL object case (could be an uninitialized
+ * package element)
+ */
+ if (!internal_object) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Always clear the external object */
+
+ ACPI_MEMSET (external_object, 0, sizeof (union acpi_object));
+
+ /*
+ * In general, the external object will be the same type as
+ * the internal object
+ */
+ external_object->type = ACPI_GET_OBJECT_TYPE (internal_object);
+
+ /* However, only a limited number of external types are supported */
+
+ switch (ACPI_GET_OBJECT_TYPE (internal_object)) {
+ case ACPI_TYPE_STRING:
+
+ external_object->string.pointer = (char *) data_space;
+ external_object->string.length = internal_object->string.length;
+ *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ((acpi_size) internal_object->string.length + 1);
+
+ ACPI_MEMCPY ((void *) data_space, (void *) internal_object->string.pointer,
+ (acpi_size) internal_object->string.length + 1);
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ external_object->buffer.pointer = data_space;
+ external_object->buffer.length = internal_object->buffer.length;
+ *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (internal_object->string.length);
+
+ ACPI_MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer,
+ internal_object->buffer.length);
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+
+ external_object->integer.value = internal_object->integer.value;
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ /*
+ * This is an object reference. Attempt to dereference it.
+ */
+ switch (internal_object->reference.opcode) {
+ case AML_INT_NAMEPATH_OP:
+
+ /* For namepath, return the object handle ("reference") */
+
+ default:
+ /*
+ * Use the object type of "Any" to indicate a reference
+ * to object containing a handle to an ACPI named object.
+ */
+ external_object->type = ACPI_TYPE_ANY;
+ external_object->reference.handle = internal_object->reference.node;
+ break;
+ }
+ break;
+
+
+ case ACPI_TYPE_PROCESSOR:
+
+ external_object->processor.proc_id = internal_object->processor.proc_id;
+ external_object->processor.pblk_address = internal_object->processor.address;
+ external_object->processor.pblk_length = internal_object->processor.length;
+ break;
+
+
+ case ACPI_TYPE_POWER:
+
+ external_object->power_resource.system_level =
+ internal_object->power_resource.system_level;
+
+ external_object->power_resource.resource_order =
+ internal_object->power_resource.resource_order;
+ break;
+
+
+ default:
+ /*
+ * There is no corresponding external object type
+ */
+ return_ACPI_STATUS (AE_SUPPORT);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_ielement_to_eelement
+ *
+ * PARAMETERS: acpi_pkg_callback
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Copy one package element to another package element
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_ielement_to_eelement (
+ u8 object_type,
+ union acpi_operand_object *source_object,
+ union acpi_generic_state *state,
+ void *context)
+{
+ acpi_status status = AE_OK;
+ struct acpi_pkg_info *info = (struct acpi_pkg_info *) context;
+ acpi_size object_space;
+ u32 this_index;
+ union acpi_object *target_object;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ this_index = state->pkg.index;
+ target_object = (union acpi_object *)
+ &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index];
+
+ switch (object_type) {
+ case ACPI_COPY_TYPE_SIMPLE:
+
+ /*
+ * This is a simple or null object
+ */
+ status = acpi_ut_copy_isimple_to_esimple (source_object,
+ target_object, info->free_space, &object_space);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+ break;
+
+
+ case ACPI_COPY_TYPE_PACKAGE:
+
+ /*
+ * Build the package object
+ */
+ target_object->type = ACPI_TYPE_PACKAGE;
+ target_object->package.count = source_object->package.count;
+ target_object->package.elements = ACPI_CAST_PTR (union acpi_object, info->free_space);
+
+ /*
+ * Pass the new package object back to the package walk routine
+ */
+ state->pkg.this_target_obj = target_object;
+
+ /*
+ * Save space for the array of objects (Package elements)
+ * update the buffer length counter
+ */
+ object_space = ACPI_ROUND_UP_TO_NATIVE_WORD (
+ (acpi_size) target_object->package.count * sizeof (union acpi_object));
+ break;
+
+
+ default:
+ return (AE_BAD_PARAMETER);
+ }
+
+ info->free_space += object_space;
+ info->length += object_space;
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_ipackage_to_epackage
+ *
+ * PARAMETERS: *internal_object - Pointer to the object we are returning
+ * *Buffer - Where the object is returned
+ * *space_used - Where the object length is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to place a package object in a user
+ * buffer. A package object by definition contains other objects.
+ *
+ * The buffer is assumed to have sufficient space for the object.
+ * The caller must have verified the buffer length needed using the
+ * acpi_ut_get_object_size function before calling this function.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_copy_ipackage_to_epackage (
+ union acpi_operand_object *internal_object,
+ u8 *buffer,
+ acpi_size *space_used)
+{
+ union acpi_object *external_object;
+ acpi_status status;
+ struct acpi_pkg_info info;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_ipackage_to_epackage");
+
+
+ /*
+ * First package at head of the buffer
+ */
+ external_object = ACPI_CAST_PTR (union acpi_object, buffer);
+
+ /*
+ * Free space begins right after the first package
+ */
+ info.length = ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object));
+ info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object));
+ info.object_space = 0;
+ info.num_packages = 1;
+
+ external_object->type = ACPI_GET_OBJECT_TYPE (internal_object);
+ external_object->package.count = internal_object->package.count;
+ external_object->package.elements = ACPI_CAST_PTR (union acpi_object, info.free_space);
+
+ /*
+ * Leave room for an array of ACPI_OBJECTS in the buffer
+ * and move the free space past it
+ */
+ info.length += (acpi_size) external_object->package.count *
+ ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object));
+ info.free_space += external_object->package.count *
+ ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object));
+
+ status = acpi_ut_walk_package_tree (internal_object, external_object,
+ acpi_ut_copy_ielement_to_eelement, &info);
+
+ *space_used = info.length;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_iobject_to_eobject
+ *
+ * PARAMETERS: *internal_object - The internal object to be converted
+ * *buffer_ptr - Where the object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to build an API object to be returned to
+ * the caller.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_iobject_to_eobject (
+ union acpi_operand_object *internal_object,
+ struct acpi_buffer *ret_buffer)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_iobject_to_eobject");
+
+
+ if (ACPI_GET_OBJECT_TYPE (internal_object) == ACPI_TYPE_PACKAGE) {
+ /*
+ * Package object: Copy all subobjects (including
+ * nested packages)
+ */
+ status = acpi_ut_copy_ipackage_to_epackage (internal_object,
+ ret_buffer->pointer, &ret_buffer->length);
+ }
+ else {
+ /*
+ * Build a simple object (no nested objects)
+ */
+ status = acpi_ut_copy_isimple_to_esimple (internal_object,
+ (union acpi_object *) ret_buffer->pointer,
+ ((u8 *) ret_buffer->pointer +
+ ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))),
+ &ret_buffer->length);
+ /*
+ * build simple does not include the object size in the length
+ * so we add it in here
+ */
+ ret_buffer->length += sizeof (union acpi_object);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_esimple_to_isimple
+ *
+ * PARAMETERS: *external_object - The external object to be converted
+ * *internal_object - Where the internal object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function copies an external object to an internal one.
+ * NOTE: Pointers can be copied, we don't need to copy data.
+ * (The pointers have to be valid in our address space no matter
+ * what we do with them!)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_esimple_to_isimple (
+ union acpi_object *external_object,
+ union acpi_operand_object **ret_internal_object)
+{
+ union acpi_operand_object *internal_object;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_esimple_to_isimple");
+
+
+ /*
+ * Simple types supported are: String, Buffer, Integer
+ */
+ switch (external_object->type) {
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ case ACPI_TYPE_INTEGER:
+
+ internal_object = acpi_ut_create_internal_object ((u8) external_object->type);
+ if (!internal_object) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+ break;
+
+ default:
+ /* All other types are not supported */
+
+ return_ACPI_STATUS (AE_SUPPORT);
+ }
+
+
+ /* Must COPY string and buffer contents */
+
+ switch (external_object->type) {
+ case ACPI_TYPE_STRING:
+
+ internal_object->string.pointer =
+ ACPI_MEM_CALLOCATE ((acpi_size) external_object->string.length + 1);
+ if (!internal_object->string.pointer) {
+ goto error_exit;
+ }
+
+ ACPI_MEMCPY (internal_object->string.pointer,
+ external_object->string.pointer,
+ external_object->string.length);
+
+ internal_object->string.length = external_object->string.length;
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ internal_object->buffer.pointer =
+ ACPI_MEM_CALLOCATE (external_object->buffer.length);
+ if (!internal_object->buffer.pointer) {
+ goto error_exit;
+ }
+
+ ACPI_MEMCPY (internal_object->buffer.pointer,
+ external_object->buffer.pointer,
+ external_object->buffer.length);
+
+ internal_object->buffer.length = external_object->buffer.length;
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+
+ internal_object->integer.value = external_object->integer.value;
+ break;
+
+ default:
+ /* Other types can't get here */
+ break;
+ }
+
+ *ret_internal_object = internal_object;
+ return_ACPI_STATUS (AE_OK);
+
+
+error_exit:
+ acpi_ut_remove_reference (internal_object);
+ return_ACPI_STATUS (AE_NO_MEMORY);
+}
+
+
+#ifdef ACPI_FUTURE_IMPLEMENTATION
+
+/* Code to convert packages that are parameters to control methods */
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_epackage_to_ipackage
+ *
+ * PARAMETERS: *internal_object - Pointer to the object we are returning
+ * *Buffer - Where the object is returned
+ * *space_used - Where the length of the object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to place a package object in a user
+ * buffer. A package object by definition contains other objects.
+ *
+ * The buffer is assumed to have sufficient space for the object.
+ * The caller must have verified the buffer length needed using the
+ * acpi_ut_get_object_size function before calling this function.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_copy_epackage_to_ipackage (
+ union acpi_operand_object *internal_object,
+ u8 *buffer,
+ u32 *space_used)
+{
+ u8 *free_space;
+ union acpi_object *external_object;
+ u32 length = 0;
+ u32 this_index;
+ u32 object_space = 0;
+ union acpi_operand_object *this_internal_obj;
+ union acpi_object *this_external_obj;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_epackage_to_ipackage");
+
+
+ /*
+ * First package at head of the buffer
+ */
+ external_object = (union acpi_object *)buffer;
+
+ /*
+ * Free space begins right after the first package
+ */
+ free_space = buffer + sizeof(union acpi_object);
+
+
+ external_object->type = ACPI_GET_OBJECT_TYPE (internal_object);
+ external_object->package.count = internal_object->package.count;
+ external_object->package.elements = (union acpi_object *)free_space;
+
+ /*
+ * Build an array of ACPI_OBJECTS in the buffer
+ * and move the free space past it
+ */
+ free_space += external_object->package.count * sizeof(union acpi_object);
+
+
+ /* Call walk_package */
+
+}
+
+#endif /* Future implementation */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_eobject_to_iobject
+ *
+ * PARAMETERS: *internal_object - The external object to be converted
+ * *buffer_ptr - Where the internal object is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: Converts an external object to an internal object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_eobject_to_iobject (
+ union acpi_object *external_object,
+ union acpi_operand_object **internal_object)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_eobject_to_iobject");
+
+
+ if (external_object->type == ACPI_TYPE_PACKAGE) {
+ /*
+ * Packages as external input to control methods are not supported,
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Packages as parameters not implemented!\n"));
+
+ return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
+ }
+
+ else {
+ /*
+ * Build a simple object (no nested objects)
+ */
+ status = acpi_ut_copy_esimple_to_isimple (external_object, internal_object);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_simple_object
+ *
+ * PARAMETERS: source_desc - The internal object to be copied
+ * dest_desc - New target object
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Simple copy of one internal object to another. Reference count
+ * of the destination object is preserved.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_simple_object (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *dest_desc)
+{
+ u16 reference_count;
+ union acpi_operand_object *next_object;
+
+
+ /* Save fields from destination that we don't want to overwrite */
+
+ reference_count = dest_desc->common.reference_count;
+ next_object = dest_desc->common.next_object;
+
+ /* Copy the entire source object over the destination object*/
+
+ ACPI_MEMCPY ((char *) dest_desc, (char *) source_desc,
+ sizeof (union acpi_operand_object));
+
+ /* Restore the saved fields */
+
+ dest_desc->common.reference_count = reference_count;
+ dest_desc->common.next_object = next_object;
+
+ /* Handle the objects with extra data */
+
+ switch (ACPI_GET_OBJECT_TYPE (dest_desc)) {
+ case ACPI_TYPE_BUFFER:
+
+ dest_desc->buffer.node = NULL;
+ dest_desc->common.flags = source_desc->common.flags;
+
+ /*
+ * Allocate and copy the actual buffer if and only if:
+ * 1) There is a valid buffer pointer
+ * 2) The buffer is not static (not in an ACPI table) (in this case,
+ * the actual pointer was already copied above)
+ */
+ if ((source_desc->buffer.pointer) &&
+ (!(source_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
+ dest_desc->buffer.pointer = NULL;
+
+ /* Create an actual buffer only if length > 0 */
+
+ if (source_desc->buffer.length) {
+ dest_desc->buffer.pointer =
+ ACPI_MEM_ALLOCATE (source_desc->buffer.length);
+ if (!dest_desc->buffer.pointer) {
+ return (AE_NO_MEMORY);
+ }
+
+ /* Copy the actual buffer data */
+
+ ACPI_MEMCPY (dest_desc->buffer.pointer,
+ source_desc->buffer.pointer,
+ source_desc->buffer.length);
+ }
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ /*
+ * Allocate and copy the actual string if and only if:
+ * 1) There is a valid string pointer
+ * 2) The string is not static (not in an ACPI table) (in this case,
+ * the actual pointer was already copied above)
+ */
+ if ((source_desc->string.pointer) &&
+ (!(source_desc->common.flags & AOPOBJ_STATIC_POINTER))) {
+ dest_desc->string.pointer =
+ ACPI_MEM_ALLOCATE ((acpi_size) source_desc->string.length + 1);
+ if (!dest_desc->string.pointer) {
+ return (AE_NO_MEMORY);
+ }
+
+ ACPI_MEMCPY (dest_desc->string.pointer, source_desc->string.pointer,
+ (acpi_size) source_desc->string.length + 1);
+ }
+ break;
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ /*
+ * We copied the reference object, so we now must add a reference
+ * to the object pointed to by the reference
+ */
+ acpi_ut_add_reference (source_desc->reference.object);
+ break;
+
+ default:
+ /* Nothing to do for other simple objects */
+ break;
+ }
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_ielement_to_ielement
+ *
+ * PARAMETERS: acpi_pkg_callback
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Copy one package element to another package element
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_ielement_to_ielement (
+ u8 object_type,
+ union acpi_operand_object *source_object,
+ union acpi_generic_state *state,
+ void *context)
+{
+ acpi_status status = AE_OK;
+ u32 this_index;
+ union acpi_operand_object **this_target_ptr;
+ union acpi_operand_object *target_object;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ this_index = state->pkg.index;
+ this_target_ptr = (union acpi_operand_object **)
+ &state->pkg.dest_object->package.elements[this_index];
+
+ switch (object_type) {
+ case ACPI_COPY_TYPE_SIMPLE:
+
+ /* A null source object indicates a (legal) null package element */
+
+ if (source_object) {
+ /*
+ * This is a simple object, just copy it
+ */
+ target_object = acpi_ut_create_internal_object (
+ ACPI_GET_OBJECT_TYPE (source_object));
+ if (!target_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ status = acpi_ut_copy_simple_object (source_object, target_object);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ *this_target_ptr = target_object;
+ }
+ else {
+ /* Pass through a null element */
+
+ *this_target_ptr = NULL;
+ }
+ break;
+
+
+ case ACPI_COPY_TYPE_PACKAGE:
+
+ /*
+ * This object is a package - go down another nesting level
+ * Create and build the package object
+ */
+ target_object = acpi_ut_create_internal_object (ACPI_TYPE_PACKAGE);
+ if (!target_object) {
+ return (AE_NO_MEMORY);
+ }
+
+ target_object->package.count = source_object->package.count;
+ target_object->common.flags = source_object->common.flags;
+
+ /*
+ * Create the object array
+ */
+ target_object->package.elements =
+ ACPI_MEM_CALLOCATE (((acpi_size) source_object->package.count + 1) *
+ sizeof (void *));
+ if (!target_object->package.elements) {
+ status = AE_NO_MEMORY;
+ goto error_exit;
+ }
+
+ /*
+ * Pass the new package object back to the package walk routine
+ */
+ state->pkg.this_target_obj = target_object;
+
+ /*
+ * Store the object pointer in the parent package object
+ */
+ *this_target_ptr = target_object;
+ break;
+
+
+ default:
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (status);
+
+error_exit:
+ acpi_ut_remove_reference (target_object);
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_ipackage_to_ipackage
+ *
+ * PARAMETERS: *source_obj - Pointer to the source package object
+ * *dest_obj - Where the internal object is returned
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to copy an internal package object
+ * into another internal package object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_ipackage_to_ipackage (
+ union acpi_operand_object *source_obj,
+ union acpi_operand_object *dest_obj,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_ipackage_to_ipackage");
+
+
+ dest_obj->common.type = ACPI_GET_OBJECT_TYPE (source_obj);
+ dest_obj->common.flags = source_obj->common.flags;
+ dest_obj->package.count = source_obj->package.count;
+
+ /*
+ * Create the object array and walk the source package tree
+ */
+ dest_obj->package.elements = ACPI_MEM_CALLOCATE (
+ ((acpi_size) source_obj->package.count + 1) *
+ sizeof (void *));
+ if (!dest_obj->package.elements) {
+ ACPI_REPORT_ERROR (
+ ("aml_build_copy_internal_package_object: Package allocation failure\n"));
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /*
+ * Copy the package element-by-element by walking the package "tree".
+ * This handles nested packages of arbitrary depth.
+ */
+ status = acpi_ut_walk_package_tree (source_obj, dest_obj,
+ acpi_ut_copy_ielement_to_ielement, walk_state);
+ if (ACPI_FAILURE (status)) {
+ /* On failure, delete the destination package object */
+
+ acpi_ut_remove_reference (dest_obj);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_iobject_to_iobject
+ *
+ * PARAMETERS: walk_state - Current walk state
+ * source_desc - The internal object to be copied
+ * dest_desc - Where the copied object is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Copy an internal object to a new internal object
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_copy_iobject_to_iobject (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object **dest_desc,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("ut_copy_iobject_to_iobject");
+
+
+ /* Create the top level object */
+
+ *dest_desc = acpi_ut_create_internal_object (ACPI_GET_OBJECT_TYPE (source_desc));
+ if (!*dest_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Copy the object and possible subobjects */
+
+ if (ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_PACKAGE) {
+ status = acpi_ut_copy_ipackage_to_ipackage (source_desc, *dest_desc,
+ walk_state);
+ }
+ else {
+ status = acpi_ut_copy_simple_object (source_desc, *dest_desc);
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
new file mode 100644
index 000000000000..985c5d045b78
--- /dev/null
+++ b/drivers/acpi/utilities/utdebug.c
@@ -0,0 +1,624 @@
+/******************************************************************************
+ *
+ * Module Name: utdebug - Debug print routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utdebug")
+
+
+#ifdef ACPI_DEBUG_OUTPUT
+
+static u32 acpi_gbl_prev_thread_id = 0xFFFFFFFF;
+static char *acpi_gbl_fn_entry_str = "----Entry";
+static char *acpi_gbl_fn_exit_str = "----Exit-";
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_init_stack_ptr_trace
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Save the current stack pointer
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_init_stack_ptr_trace (
+ void)
+{
+ u32 current_sp;
+
+
+ acpi_gbl_entry_stack_pointer = ACPI_PTR_DIFF (&current_sp, NULL);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_track_stack_ptr
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Save the current stack pointer
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_track_stack_ptr (
+ void)
+{
+ acpi_size current_sp;
+
+
+ current_sp = ACPI_PTR_DIFF (&current_sp, NULL);
+
+ if (current_sp < acpi_gbl_lowest_stack_pointer) {
+ acpi_gbl_lowest_stack_pointer = current_sp;
+ }
+
+ if (acpi_gbl_nesting_level > acpi_gbl_deepest_nesting) {
+ acpi_gbl_deepest_nesting = acpi_gbl_nesting_level;
+ }
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_debug_print
+ *
+ * PARAMETERS: debug_level - Requested debug print level
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * component_id - Caller's component ID (for error output)
+ *
+ * Format - Printf format field
+ * ... - Optional printf arguments
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message with prefix consisting of the module name,
+ * line number, and component ID.
+ *
+ ****************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_debug_print (
+ u32 requested_debug_level,
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ char *format,
+ ...)
+{
+ u32 thread_id;
+ va_list args;
+
+
+ /*
+ * Stay silent if the debug level or component ID is disabled
+ */
+ if (!(requested_debug_level & acpi_dbg_level) ||
+ !(dbg_info->component_id & acpi_dbg_layer)) {
+ return;
+ }
+
+ /*
+ * Thread tracking and context switch notification
+ */
+ thread_id = acpi_os_get_thread_id ();
+
+ if (thread_id != acpi_gbl_prev_thread_id) {
+ if (ACPI_LV_THREADS & acpi_dbg_level) {
+ acpi_os_printf ("\n**** Context Switch from TID %X to TID %X ****\n\n",
+ acpi_gbl_prev_thread_id, thread_id);
+ }
+
+ acpi_gbl_prev_thread_id = thread_id;
+ }
+
+ /*
+ * Display the module name, current line number, thread ID (if requested),
+ * current procedure nesting level, and the current procedure name
+ */
+ acpi_os_printf ("%8s-%04ld ", dbg_info->module_name, line_number);
+
+ if (ACPI_LV_THREADS & acpi_dbg_level) {
+ acpi_os_printf ("[%04lX] ", thread_id);
+ }
+
+ acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name);
+
+ va_start (args, format);
+ acpi_os_vprintf (format, args);
+}
+EXPORT_SYMBOL(acpi_ut_debug_print);
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_debug_print_raw
+ *
+ * PARAMETERS: requested_debug_level - Requested debug print level
+ * line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ * Format - Printf format field
+ * ... - Optional printf arguments
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print message with no headers. Has same interface as
+ * debug_print so that the same macros can be used.
+ *
+ ****************************************************************************/
+
+void ACPI_INTERNAL_VAR_XFACE
+acpi_ut_debug_print_raw (
+ u32 requested_debug_level,
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ char *format,
+ ...)
+{
+ va_list args;
+
+
+ if (!(requested_debug_level & acpi_dbg_level) ||
+ !(dbg_info->component_id & acpi_dbg_layer)) {
+ return;
+ }
+
+ va_start (args, format);
+ acpi_os_vprintf (format, args);
+}
+EXPORT_SYMBOL(acpi_ut_debug_print_raw);
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_trace
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_trace (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info)
+{
+
+ acpi_gbl_nesting_level++;
+ acpi_ut_track_stack_ptr ();
+
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s\n", acpi_gbl_fn_entry_str);
+}
+EXPORT_SYMBOL(acpi_ut_trace);
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_trace_ptr
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ * Pointer - Pointer to display
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_trace_ptr (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ void *pointer)
+{
+ acpi_gbl_nesting_level++;
+ acpi_ut_track_stack_ptr ();
+
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s %p\n", acpi_gbl_fn_entry_str, pointer);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_trace_str
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ * String - Additional string to display
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_trace_str (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ char *string)
+{
+
+ acpi_gbl_nesting_level++;
+ acpi_ut_track_stack_ptr ();
+
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s %s\n", acpi_gbl_fn_entry_str, string);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_trace_u32
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ * Integer - Integer to display
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_trace_u32 (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ u32 integer)
+{
+
+ acpi_gbl_nesting_level++;
+ acpi_ut_track_stack_ptr ();
+
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s %08X\n", acpi_gbl_fn_entry_str, integer);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_exit
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_exit (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info)
+{
+
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s\n", acpi_gbl_fn_exit_str);
+
+ acpi_gbl_nesting_level--;
+}
+EXPORT_SYMBOL(acpi_ut_exit);
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_status_exit
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ * Status - Exit status code
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level. Prints exit status also.
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_status_exit (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ acpi_status status)
+{
+
+ if (ACPI_SUCCESS (status)) {
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s %s\n", acpi_gbl_fn_exit_str,
+ acpi_format_exception (status));
+ }
+ else {
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s ****Exception****: %s\n", acpi_gbl_fn_exit_str,
+ acpi_format_exception (status));
+ }
+
+ acpi_gbl_nesting_level--;
+}
+EXPORT_SYMBOL(acpi_ut_status_exit);
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_value_exit
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ * Value - Value to be printed with exit msg
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level. Prints exit value also.
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_value_exit (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ acpi_integer value)
+{
+
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s %8.8X%8.8X\n", acpi_gbl_fn_exit_str,
+ ACPI_FORMAT_UINT64 (value));
+
+ acpi_gbl_nesting_level--;
+}
+EXPORT_SYMBOL(acpi_ut_value_exit);
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_ptr_exit
+ *
+ * PARAMETERS: line_number - Caller's line number
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
+ * Value - Value to be printed with exit msg
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
+ * set in debug_level. Prints exit value also.
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_ptr_exit (
+ u32 line_number,
+ struct acpi_debug_print_info *dbg_info,
+ u8 *ptr)
+{
+
+ acpi_ut_debug_print (ACPI_LV_FUNCTIONS, line_number, dbg_info,
+ "%s %p\n", acpi_gbl_fn_exit_str, ptr);
+
+ acpi_gbl_nesting_level--;
+}
+
+#endif
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_dump_buffer
+ *
+ * PARAMETERS: Buffer - Buffer to dump
+ * Count - Amount to dump, in bytes
+ * Display - BYTE, WORD, DWORD, or QWORD display
+ * component_iD - Caller's component ID
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Generic dump buffer in both hex and ascii.
+ *
+ ****************************************************************************/
+
+void
+acpi_ut_dump_buffer (
+ u8 *buffer,
+ u32 count,
+ u32 display,
+ u32 component_id)
+{
+ acpi_native_uint i = 0;
+ acpi_native_uint j;
+ u32 temp32;
+ u8 buf_char;
+
+
+ /* Only dump the buffer if tracing is enabled */
+
+ if (!((ACPI_LV_TABLES & acpi_dbg_level) &&
+ (component_id & acpi_dbg_layer))) {
+ return;
+ }
+
+ if ((count < 4) || (count & 0x01)) {
+ display = DB_BYTE_DISPLAY;
+ }
+
+ acpi_os_printf ("\nOffset Value\n");
+
+ /*
+ * Nasty little dump buffer routine!
+ */
+ while (i < count) {
+ /* Print current offset */
+
+ acpi_os_printf ("%05X ", (u32) i);
+
+ /* Print 16 hex chars */
+
+ for (j = 0; j < 16;) {
+ if (i + j >= count) {
+ acpi_os_printf ("\n");
+ return;
+ }
+
+ /* Make sure that the s8 doesn't get sign-extended! */
+
+ switch (display) {
+ /* Default is BYTE display */
+
+ default:
+
+ acpi_os_printf ("%02X ",
+ *((u8 *) &buffer[i + j]));
+ j += 1;
+ break;
+
+
+ case DB_WORD_DISPLAY:
+
+ ACPI_MOVE_16_TO_32 (&temp32, &buffer[i + j]);
+ acpi_os_printf ("%04X ", temp32);
+ j += 2;
+ break;
+
+
+ case DB_DWORD_DISPLAY:
+
+ ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j]);
+ acpi_os_printf ("%08X ", temp32);
+ j += 4;
+ break;
+
+
+ case DB_QWORD_DISPLAY:
+
+ ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j]);
+ acpi_os_printf ("%08X", temp32);
+
+ ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j + 4]);
+ acpi_os_printf ("%08X ", temp32);
+ j += 8;
+ break;
+ }
+ }
+
+ /*
+ * Print the ASCII equivalent characters
+ * But watch out for the bad unprintable ones...
+ */
+ for (j = 0; j < 16; j++) {
+ if (i + j >= count) {
+ acpi_os_printf ("\n");
+ return;
+ }
+
+ buf_char = buffer[i + j];
+ if ((buf_char > 0x1F && buf_char < 0x2E) ||
+ (buf_char > 0x2F && buf_char < 0x61) ||
+ (buf_char > 0x60 && buf_char < 0x7F)) {
+ acpi_os_printf ("%c", buf_char);
+ }
+ else {
+ acpi_os_printf (".");
+ }
+ }
+
+ /* Done with that line. */
+
+ acpi_os_printf ("\n");
+ i += 16;
+ }
+
+ return;
+}
+
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
new file mode 100644
index 000000000000..9a52ad52a23a
--- /dev/null
+++ b/drivers/acpi/utilities/utdelete.c
@@ -0,0 +1,700 @@
+/*******************************************************************************
+ *
+ * Module Name: utdelete - object deletion and reference count utilities
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acevents.h>
+#include <acpi/amlcode.h>
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utdelete")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_internal_obj
+ *
+ * PARAMETERS: *Object - Pointer to the list to be deleted
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Low level object deletion, after reference counts have been
+ * updated (All reference counts, including sub-objects!)
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_delete_internal_obj (
+ union acpi_operand_object *object)
+{
+ void *obj_pointer = NULL;
+ union acpi_operand_object *handler_desc;
+ union acpi_operand_object *second_desc;
+ union acpi_operand_object *next_desc;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_delete_internal_obj", object);
+
+
+ if (!object) {
+ return_VOID;
+ }
+
+ /*
+ * Must delete or free any pointers within the object that are not
+ * actual ACPI objects (for example, a raw buffer pointer).
+ */
+ switch (ACPI_GET_OBJECT_TYPE (object)) {
+ case ACPI_TYPE_STRING:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** String %p, ptr %p\n",
+ object, object->string.pointer));
+
+ /* Free the actual string buffer */
+
+ if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
+ /* But only if it is NOT a pointer into an ACPI table */
+
+ obj_pointer = object->string.pointer;
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "**** Buffer %p, ptr %p\n",
+ object, object->buffer.pointer));
+
+ /* Free the actual buffer */
+
+ if (!(object->common.flags & AOPOBJ_STATIC_POINTER)) {
+ /* But only if it is NOT a pointer into an ACPI table */
+
+ obj_pointer = object->buffer.pointer;
+ }
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, " **** Package of count %X\n",
+ object->package.count));
+
+ /*
+ * Elements of the package are not handled here, they are deleted
+ * separately
+ */
+
+ /* Free the (variable length) element pointer array */
+
+ obj_pointer = object->package.elements;
+ break;
+
+
+ case ACPI_TYPE_DEVICE:
+
+ if (object->device.gpe_block) {
+ (void) acpi_ev_delete_gpe_block (object->device.gpe_block);
+ }
+
+ /* Walk the handler list for this device */
+
+ handler_desc = object->device.handler;
+ while (handler_desc) {
+ next_desc = handler_desc->address_space.next;
+ acpi_ut_remove_reference (handler_desc);
+ handler_desc = next_desc;
+ }
+ break;
+
+
+ case ACPI_TYPE_MUTEX:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Mutex %p, Semaphore %p\n",
+ object, object->mutex.semaphore));
+
+ acpi_ex_unlink_mutex (object);
+ (void) acpi_os_delete_semaphore (object->mutex.semaphore);
+ break;
+
+
+ case ACPI_TYPE_EVENT:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Event %p, Semaphore %p\n",
+ object, object->event.semaphore));
+
+ (void) acpi_os_delete_semaphore (object->event.semaphore);
+ object->event.semaphore = NULL;
+ break;
+
+
+ case ACPI_TYPE_METHOD:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object));
+
+ /* Delete the method semaphore if it exists */
+
+ if (object->method.semaphore) {
+ (void) acpi_os_delete_semaphore (object->method.semaphore);
+ object->method.semaphore = NULL;
+ }
+ break;
+
+
+ case ACPI_TYPE_REGION:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object));
+
+ second_desc = acpi_ns_get_secondary_object (object);
+ if (second_desc) {
+ /*
+ * Free the region_context if and only if the handler is one of the
+ * default handlers -- and therefore, we created the context object
+ * locally, it was not created by an external caller.
+ */
+ handler_desc = object->region.handler;
+ if (handler_desc) {
+ if (handler_desc->address_space.hflags & ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) {
+ obj_pointer = second_desc->extra.region_context;
+ }
+
+ acpi_ut_remove_reference (handler_desc);
+ }
+
+ /* Now we can free the Extra object */
+
+ acpi_ut_delete_object_desc (second_desc);
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object));
+
+ second_desc = acpi_ns_get_secondary_object (object);
+ if (second_desc) {
+ acpi_ut_delete_object_desc (second_desc);
+ }
+ break;
+
+
+ default:
+ break;
+ }
+
+ /* Free any allocated memory (pointer within the object) found above */
+
+ if (obj_pointer) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object Subptr %p\n",
+ obj_pointer));
+ ACPI_MEM_FREE (obj_pointer);
+ }
+
+ /* Now the object can be safely deleted */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Deleting Object %p [%s]\n",
+ object, acpi_ut_get_object_type_name (object)));
+
+ acpi_ut_delete_object_desc (object);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_internal_object_list
+ *
+ * PARAMETERS: *obj_list - Pointer to the list to be deleted
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: This function deletes an internal object list, including both
+ * simple objects and package objects
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_delete_internal_object_list (
+ union acpi_operand_object **obj_list)
+{
+ union acpi_operand_object **internal_obj;
+
+
+ ACPI_FUNCTION_TRACE ("ut_delete_internal_object_list");
+
+
+ /* Walk the null-terminated internal list */
+
+ for (internal_obj = obj_list; *internal_obj; internal_obj++) {
+ acpi_ut_remove_reference (*internal_obj);
+ }
+
+ /* Free the combined parameter pointer list and object array */
+
+ ACPI_MEM_FREE (obj_list);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_update_ref_count
+ *
+ * PARAMETERS: *Object - Object whose ref count is to be updated
+ * Action - What to do
+ *
+ * RETURN: New ref count
+ *
+ * DESCRIPTION: Modify the ref count and return it.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ut_update_ref_count (
+ union acpi_operand_object *object,
+ u32 action)
+{
+ u16 count;
+ u16 new_count;
+
+
+ ACPI_FUNCTION_NAME ("ut_update_ref_count");
+
+
+ if (!object) {
+ return;
+ }
+
+ count = object->common.reference_count;
+ new_count = count;
+
+ /*
+ * Perform the reference count action (increment, decrement, or force delete)
+ */
+ switch (action) {
+
+ case REF_INCREMENT:
+
+ new_count++;
+ object->common.reference_count = new_count;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Incremented]\n",
+ object, new_count));
+ break;
+
+
+ case REF_DECREMENT:
+
+ if (count < 1) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
+ object, new_count));
+
+ new_count = 0;
+ }
+ else {
+ new_count--;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Decremented]\n",
+ object, new_count));
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (object) == ACPI_TYPE_METHOD) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Method Obj %p Refs=%X, [Decremented]\n",
+ object, new_count));
+ }
+
+ object->common.reference_count = new_count;
+ if (new_count == 0) {
+ acpi_ut_delete_internal_obj (object);
+ }
+
+ break;
+
+
+ case REF_FORCE_DELETE:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, Force delete! (Set to 0)\n",
+ object, count));
+
+ new_count = 0;
+ object->common.reference_count = new_count;
+ acpi_ut_delete_internal_obj (object);
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown action (%X)\n", action));
+ break;
+ }
+
+ /*
+ * Sanity check the reference count, for debug purposes only.
+ * (A deleted object will have a huge reference count)
+ */
+ if (count > ACPI_MAX_REFERENCE_COUNT) {
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN,
+ "**** Warning **** Large Reference Count (%X) in object %p\n\n",
+ count, object));
+ }
+
+ return;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_update_object_reference
+ *
+ * PARAMETERS: *Object - Increment ref count for this object
+ * and all sub-objects
+ * Action - Either REF_INCREMENT or REF_DECREMENT or
+ * REF_FORCE_DELETE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Increment the object reference count
+ *
+ * Object references are incremented when:
+ * 1) An object is attached to a Node (namespace object)
+ * 2) An object is copied (all subobjects must be incremented)
+ *
+ * Object references are decremented when:
+ * 1) An object is detached from an Node
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_update_object_reference (
+ union acpi_operand_object *object,
+ u16 action)
+{
+ acpi_status status;
+ u32 i;
+ union acpi_generic_state *state_list = NULL;
+ union acpi_generic_state *state;
+ union acpi_operand_object *tmp;
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_update_object_reference", object);
+
+
+ /* Ignore a null object ptr */
+
+ if (!object) {
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Make sure that this isn't a namespace handle */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p is NS handle\n", object));
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ state = acpi_ut_create_update_state (object, action);
+
+ while (state) {
+ object = state->update.object;
+ action = state->update.value;
+ acpi_ut_delete_generic_state (state);
+
+ /*
+ * All sub-objects must have their reference count incremented also.
+ * Different object types have different subobjects.
+ */
+ switch (ACPI_GET_OBJECT_TYPE (object)) {
+ case ACPI_TYPE_DEVICE:
+
+ tmp = object->device.system_notify;
+ if (tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->device.system_notify = NULL;
+ acpi_ut_update_ref_count (tmp, action);
+
+ tmp = object->device.device_notify;
+ if (tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->device.device_notify = NULL;
+ acpi_ut_update_ref_count (tmp, action);
+
+ break;
+
+
+ case ACPI_TYPE_PACKAGE:
+
+ /*
+ * We must update all the sub-objects of the package
+ * (Each of whom may have their own sub-objects, etc.
+ */
+ for (i = 0; i < object->package.count; i++) {
+ /*
+ * Push each element onto the stack for later processing.
+ * Note: There can be null elements within the package,
+ * these are simply ignored
+ */
+ status = acpi_ut_create_update_state_and_push (
+ object->package.elements[i], action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ tmp = object->package.elements[i];
+ if (tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->package.elements[i] = NULL;
+ }
+ break;
+
+
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ status = acpi_ut_create_update_state_and_push (
+ object->buffer_field.buffer_obj, action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ tmp = object->buffer_field.buffer_obj;
+ if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->buffer_field.buffer_obj = NULL;
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REGION_FIELD:
+
+ status = acpi_ut_create_update_state_and_push (
+ object->field.region_obj, action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ tmp = object->field.region_obj;
+ if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->field.region_obj = NULL;
+ break;
+
+
+ case ACPI_TYPE_LOCAL_BANK_FIELD:
+
+ status = acpi_ut_create_update_state_and_push (
+ object->bank_field.bank_obj, action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ tmp = object->bank_field.bank_obj;
+ if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->bank_field.bank_obj = NULL;
+
+ status = acpi_ut_create_update_state_and_push (
+ object->bank_field.region_obj, action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ tmp = object->bank_field.region_obj;
+ if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->bank_field.region_obj = NULL;
+ break;
+
+
+ case ACPI_TYPE_LOCAL_INDEX_FIELD:
+
+ status = acpi_ut_create_update_state_and_push (
+ object->index_field.index_obj, action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ tmp = object->index_field.index_obj;
+ if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->index_field.index_obj = NULL;
+
+ status = acpi_ut_create_update_state_and_push (
+ object->index_field.data_obj, action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+
+ tmp = object->index_field.data_obj;
+ if ( tmp && (tmp->common.reference_count <= 1) && action == REF_DECREMENT)
+ object->index_field.data_obj = NULL;
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ /*
+ * The target of an Index (a package, string, or buffer) must track
+ * changes to the ref count of the index.
+ */
+ if (object->reference.opcode == AML_INDEX_OP) {
+ status = acpi_ut_create_update_state_and_push (
+ object->reference.object, action, &state_list);
+ if (ACPI_FAILURE (status)) {
+ goto error_exit;
+ }
+ }
+ break;
+
+
+ case ACPI_TYPE_REGION:
+ default:
+
+ /* No subobjects */
+ break;
+ }
+
+ /*
+ * Now we can update the count in the main object. This can only
+ * happen after we update the sub-objects in case this causes the
+ * main object to be deleted.
+ */
+ acpi_ut_update_ref_count (object, action);
+
+ /* Move on to the next object to be updated */
+
+ state = acpi_ut_pop_generic_state (&state_list);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+
+
+error_exit:
+
+ ACPI_REPORT_ERROR (("Could not update object reference count, %s\n",
+ acpi_format_exception (status)));
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_add_reference
+ *
+ * PARAMETERS: *Object - Object whose reference count is to be
+ * incremented
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Add one reference to an ACPI object
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_add_reference (
+ union acpi_operand_object *object)
+{
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_add_reference", object);
+
+
+ /* Ensure that we have a valid object */
+
+ if (!acpi_ut_valid_internal_object (object)) {
+ return_VOID;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Obj %p Current Refs=%X [To Be Incremented]\n",
+ object, object->common.reference_count));
+
+ /* Increment the reference count */
+
+ (void) acpi_ut_update_object_reference (object, REF_INCREMENT);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_remove_reference
+ *
+ * PARAMETERS: *Object - Object whose ref count will be decremented
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Decrement the reference count of an ACPI internal object
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_remove_reference (
+ union acpi_operand_object *object)
+{
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_remove_reference", object);
+
+
+ /*
+ * Allow a NULL pointer to be passed in, just ignore it. This saves
+ * each caller from having to check. Also, ignore NS nodes.
+ *
+ */
+ if (!object ||
+ (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED)) {
+ return_VOID;
+ }
+
+ /* Ensure that we have a valid object */
+
+ if (!acpi_ut_valid_internal_object (object)) {
+ return_VOID;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Obj %p Current Refs=%X [To Be Decremented]\n",
+ object, object->common.reference_count));
+
+ /*
+ * Decrement the reference count, and only actually delete the object
+ * if the reference count becomes 0. (Must also decrement the ref count
+ * of all subobjects!)
+ */
+ (void) acpi_ut_update_object_reference (object, REF_DECREMENT);
+ return_VOID;
+}
+
+
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
new file mode 100644
index 000000000000..ead27d2c4d18
--- /dev/null
+++ b/drivers/acpi/utilities/uteval.c
@@ -0,0 +1,696 @@
+/******************************************************************************
+ *
+ * Module Name: uteval - Object evaluation
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acinterp.h>
+
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("uteval")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_osi_implementation
+ *
+ * PARAMETERS: walk_state - Current walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Implementation of _OSI predefined control method
+ * Supported = _OSI (String)
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_osi_implementation (
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_operand_object *string_desc;
+ union acpi_operand_object *return_desc;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_TRACE ("ut_osi_implementation");
+
+
+ /* Validate the string input argument */
+
+ string_desc = walk_state->arguments[0].object;
+ if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
+ return_ACPI_STATUS (AE_TYPE);
+ }
+
+ /* Create a return object (Default value = 0) */
+
+ return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
+ if (!return_desc) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Compare input string to table of supported strings */
+
+ for (i = 0; i < ACPI_NUM_OSI_STRINGS; i++) {
+ if (!ACPI_STRCMP (string_desc->string.pointer,
+ (char *) acpi_gbl_valid_osi_strings[i])) {
+ /* This string is supported */
+
+ return_desc->integer.value = 0xFFFFFFFF;
+ break;
+ }
+ }
+
+ walk_state->return_desc = return_desc;
+ return_ACPI_STATUS (AE_CTRL_TERMINATE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_evaluate_object
+ *
+ * PARAMETERS: prefix_node - Starting node
+ * Path - Path to object from starting node
+ * expected_return_types - Bitmap of allowed return types
+ * return_desc - Where a return value is stored
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Evaluates a namespace object and verifies the type of the
+ * return object. Common code that simplifies accessing objects
+ * that have required return objects of fixed types.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_evaluate_object (
+ struct acpi_namespace_node *prefix_node,
+ char *path,
+ u32 expected_return_btypes,
+ union acpi_operand_object **return_desc)
+{
+ struct acpi_parameter_info info;
+ acpi_status status;
+ u32 return_btype;
+
+
+ ACPI_FUNCTION_TRACE ("ut_evaluate_object");
+
+
+ info.node = prefix_node;
+ info.parameters = NULL;
+ info.parameter_type = ACPI_PARAM_ARGS;
+
+ /* Evaluate the object/method */
+
+ status = acpi_ns_evaluate_relative (path, &info);
+ if (ACPI_FAILURE (status)) {
+ if (status == AE_NOT_FOUND) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[%4.4s.%s] was not found\n",
+ acpi_ut_get_node_name (prefix_node), path));
+ }
+ else {
+ ACPI_REPORT_METHOD_ERROR ("Method execution failed",
+ prefix_node, path, status);
+ }
+
+ return_ACPI_STATUS (status);
+ }
+
+ /* Did we get a return object? */
+
+ if (!info.return_object) {
+ if (expected_return_btypes) {
+ ACPI_REPORT_METHOD_ERROR ("No object was returned from",
+ prefix_node, path, AE_NOT_EXIST);
+
+ return_ACPI_STATUS (AE_NOT_EXIST);
+ }
+
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Map the return object type to the bitmapped type */
+
+ switch (ACPI_GET_OBJECT_TYPE (info.return_object)) {
+ case ACPI_TYPE_INTEGER:
+ return_btype = ACPI_BTYPE_INTEGER;
+ break;
+
+ case ACPI_TYPE_BUFFER:
+ return_btype = ACPI_BTYPE_BUFFER;
+ break;
+
+ case ACPI_TYPE_STRING:
+ return_btype = ACPI_BTYPE_STRING;
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ return_btype = ACPI_BTYPE_PACKAGE;
+ break;
+
+ default:
+ return_btype = 0;
+ break;
+ }
+
+ if ((acpi_gbl_enable_interpreter_slack) &&
+ (!expected_return_btypes)) {
+ /*
+ * We received a return object, but one was not expected. This can
+ * happen frequently if the "implicit return" feature is enabled.
+ * Just delete the return object and return AE_OK.
+ */
+ acpi_ut_remove_reference (info.return_object);
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Is the return object one of the expected types? */
+
+ if (!(expected_return_btypes & return_btype)) {
+ ACPI_REPORT_METHOD_ERROR ("Return object type is incorrect",
+ prefix_node, path, AE_TYPE);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Type returned from %s was incorrect: %s, expected Btypes: %X\n",
+ path, acpi_ut_get_object_type_name (info.return_object),
+ expected_return_btypes));
+
+ /* On error exit, we must delete the return object */
+
+ acpi_ut_remove_reference (info.return_object);
+ return_ACPI_STATUS (AE_TYPE);
+ }
+
+ /* Object type is OK, return it */
+
+ *return_desc = info.return_object;
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_evaluate_numeric_object
+ *
+ * PARAMETERS: *object_name - Object name to be evaluated
+ * device_node - Node for the device
+ * *Address - Where the value is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Evaluates a numeric namespace object for a selected device
+ * and stores result in *Address.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_evaluate_numeric_object (
+ char *object_name,
+ struct acpi_namespace_node *device_node,
+ acpi_integer *address)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_evaluate_numeric_object");
+
+
+ status = acpi_ut_evaluate_object (device_node, object_name,
+ ACPI_BTYPE_INTEGER, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the returned Integer */
+
+ *address = obj_desc->integer.value;
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_copy_id_string
+ *
+ * PARAMETERS: Destination - Where to copy the string
+ * Source - Source string
+ * max_length - Length of the destination buffer
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Copies an ID string for the _HID, _CID, and _UID methods.
+ * Performs removal of a leading asterisk if present -- workaround
+ * for a known issue on a bunch of machines.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ut_copy_id_string (
+ char *destination,
+ char *source,
+ acpi_size max_length)
+{
+
+
+ /*
+ * Workaround for ID strings that have a leading asterisk. This construct
+ * is not allowed by the ACPI specification (ID strings must be
+ * alphanumeric), but enough existing machines have this embedded in their
+ * ID strings that the following code is useful.
+ */
+ if (*source == '*') {
+ source++;
+ }
+
+ /* Do the actual copy */
+
+ ACPI_STRNCPY (destination, source, max_length);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_HID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * *Hid - Where the HID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _HID control method that returns the hardware
+ * ID of the device.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_HID (
+ struct acpi_namespace_node *device_node,
+ struct acpi_device_id *hid)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_execute_HID");
+
+
+ status = acpi_ut_evaluate_object (device_node, METHOD_NAME__HID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ /* Convert the Numeric HID to string */
+
+ acpi_ex_eisa_id_to_string ((u32) obj_desc->integer.value, hid->value);
+ }
+ else {
+ /* Copy the String HID from the returned object */
+
+ acpi_ut_copy_id_string (hid->value, obj_desc->string.pointer,
+ sizeof (hid->value));
+ }
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_translate_one_cid
+ *
+ * PARAMETERS: obj_desc - _CID object, must be integer or string
+ * one_cid - Where the CID string is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Return a numeric or string _CID value as a string.
+ * (Compatible ID)
+ *
+ * NOTE: Assumes a maximum _CID string length of
+ * ACPI_MAX_CID_LENGTH.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ut_translate_one_cid (
+ union acpi_operand_object *obj_desc,
+ struct acpi_compatible_id *one_cid)
+{
+
+
+ switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
+ case ACPI_TYPE_INTEGER:
+
+ /* Convert the Numeric CID to string */
+
+ acpi_ex_eisa_id_to_string ((u32) obj_desc->integer.value, one_cid->value);
+ return (AE_OK);
+
+ case ACPI_TYPE_STRING:
+
+ if (obj_desc->string.length > ACPI_MAX_CID_LENGTH) {
+ return (AE_AML_STRING_LIMIT);
+ }
+
+ /* Copy the String CID from the returned object */
+
+ acpi_ut_copy_id_string (one_cid->value, obj_desc->string.pointer,
+ ACPI_MAX_CID_LENGTH);
+ return (AE_OK);
+
+ default:
+
+ return (AE_TYPE);
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_CID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * *Cid - Where the CID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _CID control method that returns one or more
+ * compatible hardware IDs for the device.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_CID (
+ struct acpi_namespace_node *device_node,
+ struct acpi_compatible_id_list **return_cid_list)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+ u32 count;
+ u32 size;
+ struct acpi_compatible_id_list *cid_list;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_TRACE ("ut_execute_CID");
+
+
+ /* Evaluate the _CID method for this device */
+
+ status = acpi_ut_evaluate_object (device_node, METHOD_NAME__CID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING | ACPI_BTYPE_PACKAGE,
+ &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Get the number of _CIDs returned */
+
+ count = 1;
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) {
+ count = obj_desc->package.count;
+ }
+
+ /* Allocate a worst-case buffer for the _CIDs */
+
+ size = (((count - 1) * sizeof (struct acpi_compatible_id)) +
+ sizeof (struct acpi_compatible_id_list));
+
+ cid_list = ACPI_MEM_CALLOCATE ((acpi_size) size);
+ if (!cid_list) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ /* Init CID list */
+
+ cid_list->count = count;
+ cid_list->size = size;
+
+ /*
+ * A _CID can return either a single compatible ID or a package of compatible
+ * IDs. Each compatible ID can be one of the following:
+ * -- Number (32 bit compressed EISA ID) or
+ * -- String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss").
+ */
+
+ /* The _CID object can be either a single CID or a package (list) of CIDs */
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_PACKAGE) {
+ /* Translate each package element */
+
+ for (i = 0; i < count; i++) {
+ status = acpi_ut_translate_one_cid (obj_desc->package.elements[i],
+ &cid_list->id[i]);
+ if (ACPI_FAILURE (status)) {
+ break;
+ }
+ }
+ }
+ else {
+ /* Only one CID, translate to a string */
+
+ status = acpi_ut_translate_one_cid (obj_desc, cid_list->id);
+ }
+
+ /* Cleanup on error */
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_MEM_FREE (cid_list);
+ }
+ else {
+ *return_cid_list = cid_list;
+ }
+
+ /* On exit, we must delete the _CID return object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_UID
+ *
+ * PARAMETERS: device_node - Node for the device
+ * *Uid - Where the UID is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes the _UID control method that returns the hardware
+ * ID of the device.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_UID (
+ struct acpi_namespace_node *device_node,
+ struct acpi_device_id *uid)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_execute_UID");
+
+
+ status = acpi_ut_evaluate_object (device_node, METHOD_NAME__UID,
+ ACPI_BTYPE_INTEGER | ACPI_BTYPE_STRING, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
+ /* Convert the Numeric UID to string */
+
+ acpi_ex_unsigned_integer_to_string (obj_desc->integer.value, uid->value);
+ }
+ else {
+ /* Copy the String UID from the returned object */
+
+ acpi_ut_copy_id_string (uid->value, obj_desc->string.pointer,
+ sizeof (uid->value));
+ }
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_STA
+ *
+ * PARAMETERS: device_node - Node for the device
+ * *Flags - Where the status flags are returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes _STA for selected device and stores results in
+ * *Flags.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_STA (
+ struct acpi_namespace_node *device_node,
+ u32 *flags)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_execute_STA");
+
+
+ status = acpi_ut_evaluate_object (device_node, METHOD_NAME__STA,
+ ACPI_BTYPE_INTEGER, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ if (AE_NOT_FOUND == status) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "_STA on %4.4s was not found, assuming device is present\n",
+ acpi_ut_get_node_name (device_node)));
+
+ *flags = 0x0F;
+ status = AE_OK;
+ }
+
+ return_ACPI_STATUS (status);
+ }
+
+ /* Extract the status flags */
+
+ *flags = (u32) obj_desc->integer.value;
+
+ /* On exit, we must delete the return object */
+
+ acpi_ut_remove_reference (obj_desc);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_execute_Sxds
+ *
+ * PARAMETERS: device_node - Node for the device
+ * *Flags - Where the status flags are returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Executes _STA for selected device and stores results in
+ * *Flags.
+ *
+ * NOTE: Internal function, no parameter validation
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_execute_sxds (
+ struct acpi_namespace_node *device_node,
+ u8 *highest)
+{
+ union acpi_operand_object *obj_desc;
+ acpi_status status;
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ut_execute_Sxds");
+
+
+ for (i = 0; i < 4; i++) {
+ highest[i] = 0xFF;
+ status = acpi_ut_evaluate_object (device_node,
+ (char *) acpi_gbl_highest_dstate_names[i],
+ ACPI_BTYPE_INTEGER, &obj_desc);
+ if (ACPI_FAILURE (status)) {
+ if (status != AE_NOT_FOUND) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "%s on Device %4.4s, %s\n",
+ (char *) acpi_gbl_highest_dstate_names[i],
+ acpi_ut_get_node_name (device_node),
+ acpi_format_exception (status)));
+
+ return_ACPI_STATUS (status);
+ }
+ }
+ else {
+ /* Extract the Dstate value */
+
+ highest[i] = (u8) obj_desc->integer.value;
+
+ /* Delete the return object */
+
+ acpi_ut_remove_reference (obj_desc);
+ }
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
new file mode 100644
index 000000000000..25b0f8ae1bc6
--- /dev/null
+++ b/drivers/acpi/utilities/utglobal.c
@@ -0,0 +1,935 @@
+/******************************************************************************
+ *
+ * Module Name: utglobal - Global variables for the ACPI subsystem
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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.
+ */
+
+#define DEFINE_ACPI_GLOBALS
+
+#include <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utglobal")
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_format_exception
+ *
+ * PARAMETERS: Status - The acpi_status code to be formatted
+ *
+ * RETURN: A string containing the exception text
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string.
+ *
+ ******************************************************************************/
+
+const char *
+acpi_format_exception (
+ acpi_status status)
+{
+ const char *exception = "UNKNOWN_STATUS_CODE";
+ acpi_status sub_status;
+
+
+ ACPI_FUNCTION_NAME ("format_exception");
+
+
+ sub_status = (status & ~AE_CODE_MASK);
+
+ switch (status & AE_CODE_MASK) {
+ case AE_CODE_ENVIRONMENTAL:
+
+ if (sub_status <= AE_CODE_ENV_MAX) {
+ exception = acpi_gbl_exception_names_env [sub_status];
+ break;
+ }
+ goto unknown;
+
+ case AE_CODE_PROGRAMMER:
+
+ if (sub_status <= AE_CODE_PGM_MAX) {
+ exception = acpi_gbl_exception_names_pgm [sub_status -1];
+ break;
+ }
+ goto unknown;
+
+ case AE_CODE_ACPI_TABLES:
+
+ if (sub_status <= AE_CODE_TBL_MAX) {
+ exception = acpi_gbl_exception_names_tbl [sub_status -1];
+ break;
+ }
+ goto unknown;
+
+ case AE_CODE_AML:
+
+ if (sub_status <= AE_CODE_AML_MAX) {
+ exception = acpi_gbl_exception_names_aml [sub_status -1];
+ break;
+ }
+ goto unknown;
+
+ case AE_CODE_CONTROL:
+
+ if (sub_status <= AE_CODE_CTRL_MAX) {
+ exception = acpi_gbl_exception_names_ctrl [sub_status -1];
+ break;
+ }
+ goto unknown;
+
+ default:
+ goto unknown;
+ }
+
+
+ return ((const char *) exception);
+
+unknown:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown exception code: 0x%8.8X\n", status));
+ return ((const char *) exception);
+}
+
+
+/******************************************************************************
+ *
+ * Static global variable initialization.
+ *
+ ******************************************************************************/
+
+/*
+ * We want the debug switches statically initialized so they
+ * are already set when the debugger is entered.
+ */
+
+/* Debug switch - level and trace mask */
+u32 acpi_dbg_level = ACPI_DEBUG_DEFAULT;
+EXPORT_SYMBOL(acpi_dbg_level);
+
+/* Debug switch - layer (component) mask */
+
+u32 acpi_dbg_layer = ACPI_COMPONENT_DEFAULT | ACPI_ALL_DRIVERS;
+EXPORT_SYMBOL(acpi_dbg_layer);
+u32 acpi_gbl_nesting_level = 0;
+
+
+/* Debugger globals */
+
+u8 acpi_gbl_db_terminate_threads = FALSE;
+u8 acpi_gbl_abort_method = FALSE;
+u8 acpi_gbl_method_executing = FALSE;
+
+/* System flags */
+
+u32 acpi_gbl_startup_flags = 0;
+
+/* System starts uninitialized */
+
+u8 acpi_gbl_shutdown = TRUE;
+
+const u8 acpi_gbl_decode_to8bit [8] = {1,2,4,8,16,32,64,128};
+
+const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] =
+{
+ "\\_S0_",
+ "\\_S1_",
+ "\\_S2_",
+ "\\_S3_",
+ "\\_S4_",
+ "\\_S5_"
+};
+
+const char *acpi_gbl_highest_dstate_names[4] =
+{
+ "_S1D",
+ "_S2D",
+ "_S3D",
+ "_S4D"
+};
+
+/*
+ * Strings supported by the _OSI predefined (internal) method.
+ * When adding strings, be sure to update ACPI_NUM_OSI_STRINGS.
+ */
+const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STRINGS] =
+{
+ /* Operating System Vendor Strings */
+
+ "Linux",
+ "Windows 2000",
+ "Windows 2001",
+ "Windows 2001.1",
+ "Windows 2001 SP0",
+ "Windows 2001 SP1",
+ "Windows 2001 SP2",
+ "Windows 2001 SP3",
+ "Windows 2001 SP4",
+
+ /* Feature Group Strings */
+
+ "Extended Address Space Descriptor"
+};
+
+
+/******************************************************************************
+ *
+ * Namespace globals
+ *
+ ******************************************************************************/
+
+
+/*
+ * Predefined ACPI Names (Built-in to the Interpreter)
+ *
+ * NOTES:
+ * 1) _SB_ is defined to be a device to allow \_SB_._INI to be run
+ * during the initialization sequence.
+ * 2) _TZ_ is defined to be a thermal zone in order to allow ASL code to
+ * perform a Notify() operation on it.
+ */
+const struct acpi_predefined_names acpi_gbl_pre_defined_names[] =
+{ {"_GPE", ACPI_TYPE_LOCAL_SCOPE, NULL},
+ {"_PR_", ACPI_TYPE_LOCAL_SCOPE, NULL},
+ {"_SB_", ACPI_TYPE_DEVICE, NULL},
+ {"_SI_", ACPI_TYPE_LOCAL_SCOPE, NULL},
+ {"_TZ_", ACPI_TYPE_THERMAL, NULL},
+ {"_REV", ACPI_TYPE_INTEGER, (char *) ACPI_CA_SUPPORT_LEVEL},
+ {"_OS_", ACPI_TYPE_STRING, ACPI_OS_NAME},
+ {"_GL_", ACPI_TYPE_MUTEX, (char *) 1},
+
+#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
+ {"_OSI", ACPI_TYPE_METHOD, (char *) 1},
+#endif
+ {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */
+};
+
+
+/*
+ * Properties of the ACPI Object Types, both internal and external.
+ * The table is indexed by values of acpi_object_type
+ */
+const u8 acpi_gbl_ns_properties[] =
+{
+ ACPI_NS_NORMAL, /* 00 Any */
+ ACPI_NS_NORMAL, /* 01 Number */
+ ACPI_NS_NORMAL, /* 02 String */
+ ACPI_NS_NORMAL, /* 03 Buffer */
+ ACPI_NS_NORMAL, /* 04 Package */
+ ACPI_NS_NORMAL, /* 05 field_unit */
+ ACPI_NS_NEWSCOPE, /* 06 Device */
+ ACPI_NS_NORMAL, /* 07 Event */
+ ACPI_NS_NEWSCOPE, /* 08 Method */
+ ACPI_NS_NORMAL, /* 09 Mutex */
+ ACPI_NS_NORMAL, /* 10 Region */
+ ACPI_NS_NEWSCOPE, /* 11 Power */
+ ACPI_NS_NEWSCOPE, /* 12 Processor */
+ ACPI_NS_NEWSCOPE, /* 13 Thermal */
+ ACPI_NS_NORMAL, /* 14 buffer_field */
+ ACPI_NS_NORMAL, /* 15 ddb_handle */
+ ACPI_NS_NORMAL, /* 16 Debug Object */
+ ACPI_NS_NORMAL, /* 17 def_field */
+ ACPI_NS_NORMAL, /* 18 bank_field */
+ ACPI_NS_NORMAL, /* 19 index_field */
+ ACPI_NS_NORMAL, /* 20 Reference */
+ ACPI_NS_NORMAL, /* 21 Alias */
+ ACPI_NS_NORMAL, /* 22 method_alias */
+ ACPI_NS_NORMAL, /* 23 Notify */
+ ACPI_NS_NORMAL, /* 24 Address Handler */
+ ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 25 Resource Desc */
+ ACPI_NS_NEWSCOPE | ACPI_NS_LOCAL, /* 26 Resource Field */
+ ACPI_NS_NEWSCOPE, /* 27 Scope */
+ ACPI_NS_NORMAL, /* 28 Extra */
+ ACPI_NS_NORMAL, /* 29 Data */
+ ACPI_NS_NORMAL /* 30 Invalid */
+};
+
+
+/* Hex to ASCII conversion table */
+
+static const char acpi_gbl_hex_to_ascii[] =
+ {'0','1','2','3','4','5','6','7',
+ '8','9','A','B','C','D','E','F'};
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_hex_to_ascii_char
+ *
+ * PARAMETERS: Integer - Contains the hex digit
+ * Position - bit position of the digit within the
+ * integer
+ *
+ * RETURN: Ascii character
+ *
+ * DESCRIPTION: Convert a hex digit to an ascii character
+ *
+ ****************************************************************************/
+
+char
+acpi_ut_hex_to_ascii_char (
+ acpi_integer integer,
+ u32 position)
+{
+
+ return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
+}
+
+
+/******************************************************************************
+ *
+ * Table name globals
+ *
+ * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes.
+ * it is NOT an exhaustive list of all possible ACPI tables. All ACPI tables
+ * that are not used by the subsystem are simply ignored.
+ *
+ * Do NOT add any table to this list that is not consumed directly by this
+ * subsystem.
+ *
+ ******************************************************************************/
+
+struct acpi_table_list acpi_gbl_table_lists[NUM_ACPI_TABLE_TYPES];
+
+struct acpi_table_support acpi_gbl_table_data[NUM_ACPI_TABLE_TYPES] =
+{
+ /*********** Name, Signature, Global typed pointer Signature size, Type How many allowed?, Contains valid AML? */
+
+ /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof (RSDP_SIG)-1, ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE},
+ /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *) &acpi_gbl_DSDT, sizeof (DSDT_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE | ACPI_TABLE_EXECUTABLE},
+ /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *) &acpi_gbl_FADT, sizeof (FADT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE},
+ /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *) &acpi_gbl_FACS, sizeof (FACS_SIG)-1, ACPI_TABLE_SECONDARY| ACPI_TABLE_SINGLE},
+ /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof (PSDT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
+ /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof (SSDT_SIG)-1, ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE | ACPI_TABLE_EXECUTABLE},
+ /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof (RSDT_SIG)-1, ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE},
+};
+
+
+/******************************************************************************
+ *
+ * Event and Hardware globals
+ *
+ ******************************************************************************/
+
+struct acpi_bit_register_info acpi_gbl_bit_register_info[ACPI_NUM_BITREG] =
+{
+ /* Name Parent Register Register Bit Position Register Bit Mask */
+
+ /* ACPI_BITREG_TIMER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_TIMER_STATUS, ACPI_BITMASK_TIMER_STATUS},
+ /* ACPI_BITREG_BUS_MASTER_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_BUS_MASTER_STATUS, ACPI_BITMASK_BUS_MASTER_STATUS},
+ /* ACPI_BITREG_GLOBAL_LOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_STATUS},
+ /* ACPI_BITREG_POWER_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_STATUS},
+ /* ACPI_BITREG_SLEEP_BUTTON_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_STATUS},
+ /* ACPI_BITREG_RT_CLOCK_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_STATUS},
+ /* ACPI_BITREG_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_WAKE_STATUS, ACPI_BITMASK_WAKE_STATUS},
+ /* ACPI_BITREG_PCIEXP_WAKE_STATUS */ {ACPI_REGISTER_PM1_STATUS, ACPI_BITPOSITION_PCIEXP_WAKE_STATUS, ACPI_BITMASK_PCIEXP_WAKE_STATUS},
+
+ /* ACPI_BITREG_TIMER_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_TIMER_ENABLE, ACPI_BITMASK_TIMER_ENABLE},
+ /* ACPI_BITREG_GLOBAL_LOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_ENABLE},
+ /* ACPI_BITREG_POWER_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_ENABLE},
+ /* ACPI_BITREG_SLEEP_BUTTON_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_ENABLE},
+ /* ACPI_BITREG_RT_CLOCK_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_ENABLE},
+ /* ACPI_BITREG_WAKE_ENABLE */ {ACPI_REGISTER_PM1_ENABLE, 0, 0},
+ /* ACPI_BITREG_PCIEXP_WAKE_DISABLE */ {ACPI_REGISTER_PM1_ENABLE, ACPI_BITPOSITION_PCIEXP_WAKE_DISABLE, ACPI_BITMASK_PCIEXP_WAKE_DISABLE},
+
+ /* ACPI_BITREG_SCI_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SCI_ENABLE, ACPI_BITMASK_SCI_ENABLE},
+ /* ACPI_BITREG_BUS_MASTER_RLD */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_BUS_MASTER_RLD, ACPI_BITMASK_BUS_MASTER_RLD},
+ /* ACPI_BITREG_GLOBAL_LOCK_RELEASE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_GLOBAL_LOCK_RELEASE, ACPI_BITMASK_GLOBAL_LOCK_RELEASE},
+ /* ACPI_BITREG_SLEEP_TYPE_A */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_TYPE_X, ACPI_BITMASK_SLEEP_TYPE_X},
+ /* ACPI_BITREG_SLEEP_TYPE_B */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_TYPE_X, ACPI_BITMASK_SLEEP_TYPE_X},
+ /* ACPI_BITREG_SLEEP_ENABLE */ {ACPI_REGISTER_PM1_CONTROL, ACPI_BITPOSITION_SLEEP_ENABLE, ACPI_BITMASK_SLEEP_ENABLE},
+
+ /* ACPI_BITREG_ARB_DIS */ {ACPI_REGISTER_PM2_CONTROL, ACPI_BITPOSITION_ARB_DISABLE, ACPI_BITMASK_ARB_DISABLE}
+};
+
+
+struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVENTS] =
+{
+ /* ACPI_EVENT_PMTIMER */ {ACPI_BITREG_TIMER_STATUS, ACPI_BITREG_TIMER_ENABLE, ACPI_BITMASK_TIMER_STATUS, ACPI_BITMASK_TIMER_ENABLE},
+ /* ACPI_EVENT_GLOBAL */ {ACPI_BITREG_GLOBAL_LOCK_STATUS, ACPI_BITREG_GLOBAL_LOCK_ENABLE, ACPI_BITMASK_GLOBAL_LOCK_STATUS, ACPI_BITMASK_GLOBAL_LOCK_ENABLE},
+ /* ACPI_EVENT_POWER_BUTTON */ {ACPI_BITREG_POWER_BUTTON_STATUS, ACPI_BITREG_POWER_BUTTON_ENABLE, ACPI_BITMASK_POWER_BUTTON_STATUS, ACPI_BITMASK_POWER_BUTTON_ENABLE},
+ /* ACPI_EVENT_SLEEP_BUTTON */ {ACPI_BITREG_SLEEP_BUTTON_STATUS, ACPI_BITREG_SLEEP_BUTTON_ENABLE, ACPI_BITMASK_SLEEP_BUTTON_STATUS, ACPI_BITMASK_SLEEP_BUTTON_ENABLE},
+ /* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE},
+};
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_region_name
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a Space ID into a name string (Debug only)
+ *
+ ****************************************************************************/
+
+/* Region type decoding */
+
+const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS] =
+{
+/*! [Begin] no source code translation (keep these ASL Keywords as-is) */
+ "SystemMemory",
+ "SystemIO",
+ "PCI_Config",
+ "EmbeddedControl",
+ "SMBus",
+ "CMOS",
+ "PCIBARTarget",
+ "DataTable"
+/*! [End] no source code translation !*/
+};
+
+
+char *
+acpi_ut_get_region_name (
+ u8 space_id)
+{
+
+ if (space_id >= ACPI_USER_REGION_BEGIN)
+ {
+ return ("user_defined_region");
+ }
+
+ else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS)
+ {
+ return ("invalid_space_id");
+ }
+
+ return ((char *) acpi_gbl_region_types[space_id]);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_event_name
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a Event ID into a name string (Debug only)
+ *
+ ****************************************************************************/
+
+/* Event type decoding */
+
+static const char *acpi_gbl_event_types[ACPI_NUM_FIXED_EVENTS] =
+{
+ "PM_Timer",
+ "global_lock",
+ "power_button",
+ "sleep_button",
+ "real_time_clock",
+};
+
+
+char *
+acpi_ut_get_event_name (
+ u32 event_id)
+{
+
+ if (event_id > ACPI_EVENT_MAX)
+ {
+ return ("invalid_event_iD");
+ }
+
+ return ((char *) acpi_gbl_event_types[event_id]);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_type_name
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a Type ID into a name string (Debug only)
+ *
+ ****************************************************************************/
+
+/*
+ * Elements of acpi_gbl_ns_type_names below must match
+ * one-to-one with values of acpi_object_type
+ *
+ * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when
+ * stored in a table it really means that we have thus far seen no evidence to
+ * indicate what type is actually going to be stored for this entry.
+ */
+static const char acpi_gbl_bad_type[] = "UNDEFINED";
+#define TYPE_NAME_LENGTH 12 /* Maximum length of each string */
+
+static const char *acpi_gbl_ns_type_names[] = /* printable names of ACPI types */
+{
+ /* 00 */ "Untyped",
+ /* 01 */ "Integer",
+ /* 02 */ "String",
+ /* 03 */ "Buffer",
+ /* 04 */ "Package",
+ /* 05 */ "field_unit",
+ /* 06 */ "Device",
+ /* 07 */ "Event",
+ /* 08 */ "Method",
+ /* 09 */ "Mutex",
+ /* 10 */ "Region",
+ /* 11 */ "Power",
+ /* 12 */ "Processor",
+ /* 13 */ "Thermal",
+ /* 14 */ "buffer_field",
+ /* 15 */ "ddb_handle",
+ /* 16 */ "debug_object",
+ /* 17 */ "region_field",
+ /* 18 */ "bank_field",
+ /* 19 */ "index_field",
+ /* 20 */ "Reference",
+ /* 21 */ "Alias",
+ /* 22 */ "method_alias",
+ /* 23 */ "Notify",
+ /* 24 */ "addr_handler",
+ /* 25 */ "resource_desc",
+ /* 26 */ "resource_fld",
+ /* 27 */ "Scope",
+ /* 28 */ "Extra",
+ /* 29 */ "Data",
+ /* 30 */ "Invalid"
+};
+
+
+char *
+acpi_ut_get_type_name (
+ acpi_object_type type)
+{
+
+ if (type > ACPI_TYPE_INVALID)
+ {
+ return ((char *) acpi_gbl_bad_type);
+ }
+
+ return ((char *) acpi_gbl_ns_type_names[type]);
+}
+
+
+char *
+acpi_ut_get_object_type_name (
+ union acpi_operand_object *obj_desc)
+{
+
+ if (!obj_desc)
+ {
+ return ("[NULL Object Descriptor]");
+ }
+
+ return (acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)));
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_node_name
+ *
+ * PARAMETERS: Object - A namespace node
+ *
+ * RETURN: Pointer to a string
+ *
+ * DESCRIPTION: Validate the node and return the node's ACPI name.
+ *
+ ****************************************************************************/
+
+char *
+acpi_ut_get_node_name (
+ void *object)
+{
+ struct acpi_namespace_node *node = (struct acpi_namespace_node *) object;
+
+
+ /* Must return a string of exactly 4 characters == ACPI_NAME_SIZE */
+
+ if (!object)
+ {
+ return ("NULL");
+ }
+
+ /* Check for Root node */
+
+ if ((object == ACPI_ROOT_OBJECT) ||
+ (object == acpi_gbl_root_node))
+ {
+ return ("\"\\\" ");
+ }
+
+ /* Descriptor must be a namespace node */
+
+ if (node->descriptor != ACPI_DESC_TYPE_NAMED)
+ {
+ return ("####");
+ }
+
+ /* Name must be a valid ACPI name */
+
+ if (!acpi_ut_valid_acpi_name (* (u32 *) node->name.ascii))
+ {
+ return ("????");
+ }
+
+ /* Return the name */
+
+ return (node->name.ascii);
+}
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_descriptor_name
+ *
+ * PARAMETERS: Object - An ACPI object
+ *
+ * RETURN: Pointer to a string
+ *
+ * DESCRIPTION: Validate object and return the descriptor type
+ *
+ ****************************************************************************/
+
+static const char *acpi_gbl_desc_type_names[] = /* printable names of descriptor types */
+{
+ /* 00 */ "Invalid",
+ /* 01 */ "Cached",
+ /* 02 */ "State-Generic",
+ /* 03 */ "State-Update",
+ /* 04 */ "State-Package",
+ /* 05 */ "State-Control",
+ /* 06 */ "State-root_parse_scope",
+ /* 07 */ "State-parse_scope",
+ /* 08 */ "State-walk_scope",
+ /* 09 */ "State-Result",
+ /* 10 */ "State-Notify",
+ /* 11 */ "State-Thread",
+ /* 12 */ "Walk",
+ /* 13 */ "Parser",
+ /* 14 */ "Operand",
+ /* 15 */ "Node"
+};
+
+
+char *
+acpi_ut_get_descriptor_name (
+ void *object)
+{
+
+ if (!object)
+ {
+ return ("NULL OBJECT");
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (object) > ACPI_DESC_TYPE_MAX)
+ {
+ return ((char *) acpi_gbl_bad_type);
+ }
+
+ return ((char *) acpi_gbl_desc_type_names[ACPI_GET_DESCRIPTOR_TYPE (object)]);
+
+}
+
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+/*
+ * Strings and procedures used for debug only
+ */
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_mutex_name
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Translate a mutex ID into a name string (Debug only)
+ *
+ ****************************************************************************/
+
+char *
+acpi_ut_get_mutex_name (
+ u32 mutex_id)
+{
+
+ if (mutex_id > MAX_MUTEX)
+ {
+ return ("Invalid Mutex ID");
+ }
+
+ return (acpi_gbl_mutex_names[mutex_id]);
+}
+
+#endif
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_ut_valid_object_type
+ *
+ * PARAMETERS: Type - Object type to be validated
+ *
+ * RETURN: TRUE if valid object type
+ *
+ * DESCRIPTION: Validate an object type
+ *
+ ****************************************************************************/
+
+u8
+acpi_ut_valid_object_type (
+ acpi_object_type type)
+{
+
+ if (type > ACPI_TYPE_LOCAL_MAX)
+ {
+ /* Note: Assumes all TYPEs are contiguous (external/local) */
+
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ut_allocate_owner_id
+ *
+ * PARAMETERS: id_type - Type of ID (method or table)
+ *
+ * DESCRIPTION: Allocate a table or method owner id
+ *
+ ***************************************************************************/
+
+acpi_owner_id
+acpi_ut_allocate_owner_id (
+ u32 id_type)
+{
+ acpi_owner_id owner_id = 0xFFFF;
+
+
+ ACPI_FUNCTION_TRACE ("ut_allocate_owner_id");
+
+
+ if (ACPI_FAILURE (acpi_ut_acquire_mutex (ACPI_MTX_CACHES)))
+ {
+ return (0);
+ }
+
+ switch (id_type)
+ {
+ case ACPI_OWNER_TYPE_TABLE:
+
+ owner_id = acpi_gbl_next_table_owner_id;
+ acpi_gbl_next_table_owner_id++;
+
+ /* Check for wraparound */
+
+ if (acpi_gbl_next_table_owner_id == ACPI_FIRST_METHOD_ID)
+ {
+ acpi_gbl_next_table_owner_id = ACPI_FIRST_TABLE_ID;
+ ACPI_REPORT_WARNING (("Table owner ID wraparound\n"));
+ }
+ break;
+
+
+ case ACPI_OWNER_TYPE_METHOD:
+
+ owner_id = acpi_gbl_next_method_owner_id;
+ acpi_gbl_next_method_owner_id++;
+
+ if (acpi_gbl_next_method_owner_id == ACPI_FIRST_TABLE_ID)
+ {
+ /* Check for wraparound */
+
+ acpi_gbl_next_method_owner_id = ACPI_FIRST_METHOD_ID;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ (void) acpi_ut_release_mutex (ACPI_MTX_CACHES);
+ return_VALUE (owner_id);
+}
+
+
+/****************************************************************************
+ *
+ * FUNCTION: acpi_ut_init_globals
+ *
+ * PARAMETERS: none
+ *
+ * DESCRIPTION: Init library globals. All globals that require specific
+ * initialization should be initialized here!
+ *
+ ***************************************************************************/
+
+void
+acpi_ut_init_globals (
+ void)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ut_init_globals");
+
+
+ /* Memory allocation and cache lists */
+
+ ACPI_MEMSET (acpi_gbl_memory_lists, 0, sizeof (struct acpi_memory_list) * ACPI_NUM_MEM_LISTS);
+
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_generic_state *) NULL)->common.next), NULL);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_parse_object *) NULL)->common.next), NULL);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_parse_object *) NULL)->common.next), NULL);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].link_offset = (u16) ACPI_PTR_DIFF (&(((union acpi_operand_object *) NULL)->cache.next), NULL);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].link_offset = (u16) ACPI_PTR_DIFF (&(((struct acpi_walk_state *) NULL)->next), NULL);
+
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].object_size = sizeof (struct acpi_namespace_node);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].object_size = sizeof (union acpi_generic_state);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].object_size = sizeof (struct acpi_parse_obj_common);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].object_size = sizeof (struct acpi_parse_obj_named);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].object_size = sizeof (union acpi_operand_object);
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].object_size = sizeof (struct acpi_walk_state);
+
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].max_cache_depth = ACPI_MAX_STATE_CACHE_DEPTH;
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].max_cache_depth = ACPI_MAX_PARSE_CACHE_DEPTH;
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].max_cache_depth = ACPI_MAX_EXTPARSE_CACHE_DEPTH;
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].max_cache_depth = ACPI_MAX_OBJECT_CACHE_DEPTH;
+ acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].max_cache_depth = ACPI_MAX_WALK_CACHE_DEPTH;
+
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_GLOBAL].list_name = "Global Memory Allocation");
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].list_name = "Namespace Nodes");
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_STATE].list_name = "State Object Cache");
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE].list_name = "Parse Node Cache");
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_PSNODE_EXT].list_name = "Extended Parse Node Cache");
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_OPERAND].list_name = "Operand Object Cache");
+ ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_WALK].list_name = "Tree Walk Node Cache");
+
+ /* ACPI table structure */
+
+ for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++)
+ {
+ acpi_gbl_table_lists[i].next = NULL;
+ acpi_gbl_table_lists[i].count = 0;
+ }
+
+ /* Mutex locked flags */
+
+ for (i = 0; i < NUM_MUTEX; i++)
+ {
+ acpi_gbl_mutex_info[i].mutex = NULL;
+ acpi_gbl_mutex_info[i].owner_id = ACPI_MUTEX_NOT_ACQUIRED;
+ acpi_gbl_mutex_info[i].use_count = 0;
+ }
+
+ /* GPE support */
+
+ acpi_gbl_gpe_xrupt_list_head = NULL;
+ acpi_gbl_gpe_fadt_blocks[0] = NULL;
+ acpi_gbl_gpe_fadt_blocks[1] = NULL;
+
+ /* Global notify handlers */
+
+ acpi_gbl_system_notify.handler = NULL;
+ acpi_gbl_device_notify.handler = NULL;
+ acpi_gbl_exception_handler = NULL;
+ acpi_gbl_init_handler = NULL;
+
+ /* Global "typed" ACPI table pointers */
+
+ acpi_gbl_RSDP = NULL;
+ acpi_gbl_XSDT = NULL;
+ acpi_gbl_FACS = NULL;
+ acpi_gbl_FADT = NULL;
+ acpi_gbl_DSDT = NULL;
+
+ /* Global Lock support */
+
+ acpi_gbl_global_lock_acquired = FALSE;
+ acpi_gbl_global_lock_thread_count = 0;
+ acpi_gbl_global_lock_handle = 0;
+
+ /* Miscellaneous variables */
+
+ acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER;
+ acpi_gbl_rsdp_original_location = 0;
+ acpi_gbl_cm_single_step = FALSE;
+ acpi_gbl_db_terminate_threads = FALSE;
+ acpi_gbl_shutdown = FALSE;
+ acpi_gbl_ns_lookup_count = 0;
+ acpi_gbl_ps_find_count = 0;
+ acpi_gbl_acpi_hardware_present = TRUE;
+ acpi_gbl_next_table_owner_id = ACPI_FIRST_TABLE_ID;
+ acpi_gbl_next_method_owner_id = ACPI_FIRST_METHOD_ID;
+ acpi_gbl_debugger_configuration = DEBUGGER_THREADING;
+ acpi_gbl_db_output_flags = ACPI_DB_CONSOLE_OUTPUT;
+
+ /* Hardware oriented */
+
+ acpi_gbl_events_initialized = FALSE;
+ acpi_gbl_system_awake_and_running = TRUE;
+
+ /* Namespace */
+
+ acpi_gbl_root_node = NULL;
+
+ acpi_gbl_root_node_struct.name.integer = ACPI_ROOT_NAME;
+ acpi_gbl_root_node_struct.descriptor = ACPI_DESC_TYPE_NAMED;
+ acpi_gbl_root_node_struct.type = ACPI_TYPE_DEVICE;
+ acpi_gbl_root_node_struct.child = NULL;
+ acpi_gbl_root_node_struct.peer = NULL;
+ acpi_gbl_root_node_struct.object = NULL;
+ acpi_gbl_root_node_struct.flags = ANOBJ_END_OF_PEER_LIST;
+
+
+#ifdef ACPI_DEBUG_OUTPUT
+ acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
+#endif
+
+ return_VOID;
+}
+
+
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
new file mode 100644
index 000000000000..bdbadaf48d29
--- /dev/null
+++ b/drivers/acpi/utilities/utinit.c
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Module Name: utinit - Common ACPI subsystem initialization
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/acevents.h>
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utinit")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_fadt_register_error
+ *
+ * PARAMETERS: *register_name - Pointer to string identifying register
+ * Value - Actual register contents value
+ * acpi_test_spec_section - TDS section containing assertion
+ * acpi_assertion - Assertion number being tested
+ *
+ * RETURN: AE_BAD_VALUE
+ *
+ * DESCRIPTION: Display failure message and link failure to TDS assertion
+ *
+ ******************************************************************************/
+
+static void
+acpi_ut_fadt_register_error (
+ char *register_name,
+ u32 value,
+ acpi_size offset)
+{
+
+ ACPI_REPORT_WARNING (
+ ("Invalid FADT value %s=%X at offset %X FADT=%p\n",
+ register_name, value, (u32) offset, acpi_gbl_FADT));
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ut_validate_fadt
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Validate various ACPI registers in the FADT
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_validate_fadt (
+ void)
+{
+
+ /*
+ * Verify Fixed ACPI Description Table fields,
+ * but don't abort on any problems, just display error
+ */
+ if (acpi_gbl_FADT->pm1_evt_len < 4) {
+ acpi_ut_fadt_register_error ("PM1_EVT_LEN",
+ (u32) acpi_gbl_FADT->pm1_evt_len,
+ ACPI_FADT_OFFSET (pm1_evt_len));
+ }
+
+ if (!acpi_gbl_FADT->pm1_cnt_len) {
+ acpi_ut_fadt_register_error ("PM1_CNT_LEN", 0,
+ ACPI_FADT_OFFSET (pm1_cnt_len));
+ }
+
+ if (!acpi_gbl_FADT->xpm1a_evt_blk.address) {
+ acpi_ut_fadt_register_error ("X_PM1a_EVT_BLK", 0,
+ ACPI_FADT_OFFSET (xpm1a_evt_blk.address));
+ }
+
+ if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) {
+ acpi_ut_fadt_register_error ("X_PM1a_CNT_BLK", 0,
+ ACPI_FADT_OFFSET (xpm1a_cnt_blk.address));
+ }
+
+ if (!acpi_gbl_FADT->xpm_tmr_blk.address) {
+ acpi_ut_fadt_register_error ("X_PM_TMR_BLK", 0,
+ ACPI_FADT_OFFSET (xpm_tmr_blk.address));
+ }
+
+ if ((acpi_gbl_FADT->xpm2_cnt_blk.address &&
+ !acpi_gbl_FADT->pm2_cnt_len)) {
+ acpi_ut_fadt_register_error ("PM2_CNT_LEN",
+ (u32) acpi_gbl_FADT->pm2_cnt_len,
+ ACPI_FADT_OFFSET (pm2_cnt_len));
+ }
+
+ if (acpi_gbl_FADT->pm_tm_len < 4) {
+ acpi_ut_fadt_register_error ("PM_TM_LEN",
+ (u32) acpi_gbl_FADT->pm_tm_len,
+ ACPI_FADT_OFFSET (pm_tm_len));
+ }
+
+ /* Length of GPE blocks must be a multiple of 2 */
+
+ if (acpi_gbl_FADT->xgpe0_blk.address &&
+ (acpi_gbl_FADT->gpe0_blk_len & 1)) {
+ acpi_ut_fadt_register_error ("(x)GPE0_BLK_LEN",
+ (u32) acpi_gbl_FADT->gpe0_blk_len,
+ ACPI_FADT_OFFSET (gpe0_blk_len));
+ }
+
+ if (acpi_gbl_FADT->xgpe1_blk.address &&
+ (acpi_gbl_FADT->gpe1_blk_len & 1)) {
+ acpi_ut_fadt_register_error ("(x)GPE1_BLK_LEN",
+ (u32) acpi_gbl_FADT->gpe1_blk_len,
+ ACPI_FADT_OFFSET (gpe1_blk_len));
+ }
+
+ return (AE_OK);
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_ut_terminate
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: free global memory
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_terminate (void)
+{
+ struct acpi_gpe_block_info *gpe_block;
+ struct acpi_gpe_block_info *next_gpe_block;
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info;
+ struct acpi_gpe_xrupt_info *next_gpe_xrupt_info;
+
+
+ ACPI_FUNCTION_TRACE ("ut_terminate");
+
+
+ /* Free global tables, etc. */
+
+
+ /* Free global GPE blocks and related info structures */
+
+ gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
+ while (gpe_xrupt_info) {
+ gpe_block = gpe_xrupt_info->gpe_block_list_head;
+ while (gpe_block) {
+ next_gpe_block = gpe_block->next;
+ ACPI_MEM_FREE (gpe_block->event_info);
+ ACPI_MEM_FREE (gpe_block->register_info);
+ ACPI_MEM_FREE (gpe_block);
+
+ gpe_block = next_gpe_block;
+ }
+ next_gpe_xrupt_info = gpe_xrupt_info->next;
+ ACPI_MEM_FREE (gpe_xrupt_info);
+ gpe_xrupt_info = next_gpe_xrupt_info;
+ }
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_subsystem_shutdown
+ *
+ * PARAMETERS: none
+ *
+ * RETURN: none
+ *
+ * DESCRIPTION: Shutdown the various subsystems. Don't delete the mutex
+ * objects here -- because the AML debugger may be still running.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_subsystem_shutdown (void)
+{
+
+ ACPI_FUNCTION_TRACE ("ut_subsystem_shutdown");
+
+ /* Just exit if subsystem is already shutdown */
+
+ if (acpi_gbl_shutdown) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "ACPI Subsystem is already terminated\n"));
+ return_VOID;
+ }
+
+ /* Subsystem appears active, go ahead and shut it down */
+
+ acpi_gbl_shutdown = TRUE;
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem...\n"));
+
+ /* Close the acpi_event Handling */
+
+ acpi_ev_terminate ();
+
+ /* Close the Namespace */
+
+ acpi_ns_terminate ();
+
+ /* Close the globals */
+
+ acpi_ut_terminate ();
+
+ /* Purge the local caches */
+
+ (void) acpi_purge_cached_objects ();
+
+ /* Debug only - display leftover memory allocation, if any */
+
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+ acpi_ut_dump_allocations (ACPI_UINT32_MAX, NULL);
+#endif
+
+ return_VOID;
+}
+
+
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
new file mode 100644
index 000000000000..2525c1a93547
--- /dev/null
+++ b/drivers/acpi/utilities/utmath.c
@@ -0,0 +1,333 @@
+/*******************************************************************************
+ *
+ * Module Name: utmath - Integer math support routines
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utmath")
+
+/*
+ * Support for double-precision integer divide. This code is included here
+ * in order to support kernel environments where the double-precision math
+ * library is not available.
+ */
+
+#ifndef ACPI_USE_NATIVE_DIVIDE
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_short_divide
+ *
+ * PARAMETERS: Dividend - 64-bit dividend
+ * Divisor - 32-bit divisor
+ * out_quotient - Pointer to where the quotient is returned
+ * out_remainder - Pointer to where the remainder is returned
+ *
+ * RETURN: Status (Checks for divide-by-zero)
+ *
+ * DESCRIPTION: Perform a short (maximum 64 bits divided by 32 bits)
+ * divide and modulo. The result is a 64-bit quotient and a
+ * 32-bit remainder.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_short_divide (
+ acpi_integer dividend,
+ u32 divisor,
+ acpi_integer *out_quotient,
+ u32 *out_remainder)
+{
+ union uint64_overlay dividend_ovl;
+ union uint64_overlay quotient;
+ u32 remainder32;
+
+
+ ACPI_FUNCTION_TRACE ("ut_short_divide");
+
+
+ /* Always check for a zero divisor */
+
+ if (divisor == 0) {
+ ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
+ return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
+ }
+
+ dividend_ovl.full = dividend;
+
+ /*
+ * The quotient is 64 bits, the remainder is always 32 bits,
+ * and is generated by the second divide.
+ */
+ ACPI_DIV_64_BY_32 (0, dividend_ovl.part.hi, divisor,
+ quotient.part.hi, remainder32);
+ ACPI_DIV_64_BY_32 (remainder32, dividend_ovl.part.lo, divisor,
+ quotient.part.lo, remainder32);
+
+ /* Return only what was requested */
+
+ if (out_quotient) {
+ *out_quotient = quotient.full;
+ }
+ if (out_remainder) {
+ *out_remainder = remainder32;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_divide
+ *
+ * PARAMETERS: in_dividend - Dividend
+ * in_divisor - Divisor
+ * out_quotient - Pointer to where the quotient is returned
+ * out_remainder - Pointer to where the remainder is returned
+ *
+ * RETURN: Status (Checks for divide-by-zero)
+ *
+ * DESCRIPTION: Perform a divide and modulo.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_divide (
+ acpi_integer in_dividend,
+ acpi_integer in_divisor,
+ acpi_integer *out_quotient,
+ acpi_integer *out_remainder)
+{
+ union uint64_overlay dividend;
+ union uint64_overlay divisor;
+ union uint64_overlay quotient;
+ union uint64_overlay remainder;
+ union uint64_overlay normalized_dividend;
+ union uint64_overlay normalized_divisor;
+ u32 partial1;
+ union uint64_overlay partial2;
+ union uint64_overlay partial3;
+
+
+ ACPI_FUNCTION_TRACE ("ut_divide");
+
+
+ /* Always check for a zero divisor */
+
+ if (in_divisor == 0) {
+ ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
+ return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
+ }
+
+ divisor.full = in_divisor;
+ dividend.full = in_dividend;
+ if (divisor.part.hi == 0) {
+ /*
+ * 1) Simplest case is where the divisor is 32 bits, we can
+ * just do two divides
+ */
+ remainder.part.hi = 0;
+
+ /*
+ * The quotient is 64 bits, the remainder is always 32 bits,
+ * and is generated by the second divide.
+ */
+ ACPI_DIV_64_BY_32 (0, dividend.part.hi, divisor.part.lo,
+ quotient.part.hi, partial1);
+ ACPI_DIV_64_BY_32 (partial1, dividend.part.lo, divisor.part.lo,
+ quotient.part.lo, remainder.part.lo);
+ }
+
+ else {
+ /*
+ * 2) The general case where the divisor is a full 64 bits
+ * is more difficult
+ */
+ quotient.part.hi = 0;
+ normalized_dividend = dividend;
+ normalized_divisor = divisor;
+
+ /* Normalize the operands (shift until the divisor is < 32 bits) */
+
+ do {
+ ACPI_SHIFT_RIGHT_64 (normalized_divisor.part.hi,
+ normalized_divisor.part.lo);
+ ACPI_SHIFT_RIGHT_64 (normalized_dividend.part.hi,
+ normalized_dividend.part.lo);
+
+ } while (normalized_divisor.part.hi != 0);
+
+ /* Partial divide */
+
+ ACPI_DIV_64_BY_32 (normalized_dividend.part.hi,
+ normalized_dividend.part.lo,
+ normalized_divisor.part.lo,
+ quotient.part.lo, partial1);
+
+ /*
+ * The quotient is always 32 bits, and simply requires adjustment.
+ * The 64-bit remainder must be generated.
+ */
+ partial1 = quotient.part.lo * divisor.part.hi;
+ partial2.full = (acpi_integer) quotient.part.lo * divisor.part.lo;
+ partial3.full = (acpi_integer) partial2.part.hi + partial1;
+
+ remainder.part.hi = partial3.part.lo;
+ remainder.part.lo = partial2.part.lo;
+
+ if (partial3.part.hi == 0) {
+ if (partial3.part.lo >= dividend.part.hi) {
+ if (partial3.part.lo == dividend.part.hi) {
+ if (partial2.part.lo > dividend.part.lo) {
+ quotient.part.lo--;
+ remainder.full -= divisor.full;
+ }
+ }
+ else {
+ quotient.part.lo--;
+ remainder.full -= divisor.full;
+ }
+ }
+
+ remainder.full = remainder.full - dividend.full;
+ remainder.part.hi = (u32) -((s32) remainder.part.hi);
+ remainder.part.lo = (u32) -((s32) remainder.part.lo);
+
+ if (remainder.part.lo) {
+ remainder.part.hi--;
+ }
+ }
+ }
+
+ /* Return only what was requested */
+
+ if (out_quotient) {
+ *out_quotient = quotient.full;
+ }
+ if (out_remainder) {
+ *out_remainder = remainder.full;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+#else
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_short_divide, acpi_ut_divide
+ *
+ * DESCRIPTION: Native versions of the ut_divide functions. Use these if either
+ * 1) The target is a 64-bit platform and therefore 64-bit
+ * integer math is supported directly by the machine.
+ * 2) The target is a 32-bit or 16-bit platform, and the
+ * double-precision integer math library is available to
+ * perform the divide.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_short_divide (
+ acpi_integer in_dividend,
+ u32 divisor,
+ acpi_integer *out_quotient,
+ u32 *out_remainder)
+{
+
+ ACPI_FUNCTION_TRACE ("ut_short_divide");
+
+
+ /* Always check for a zero divisor */
+
+ if (divisor == 0) {
+ ACPI_REPORT_ERROR (("acpi_ut_short_divide: Divide by zero\n"));
+ return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
+ }
+
+ /* Return only what was requested */
+
+ if (out_quotient) {
+ *out_quotient = in_dividend / divisor;
+ }
+ if (out_remainder) {
+ *out_remainder = (u32) in_dividend % divisor;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+acpi_status
+acpi_ut_divide (
+ acpi_integer in_dividend,
+ acpi_integer in_divisor,
+ acpi_integer *out_quotient,
+ acpi_integer *out_remainder)
+{
+ ACPI_FUNCTION_TRACE ("ut_divide");
+
+
+ /* Always check for a zero divisor */
+
+ if (in_divisor == 0) {
+ ACPI_REPORT_ERROR (("acpi_ut_divide: Divide by zero\n"));
+ return_ACPI_STATUS (AE_AML_DIVIDE_BY_ZERO);
+ }
+
+
+ /* Return only what was requested */
+
+ if (out_quotient) {
+ *out_quotient = in_dividend / in_divisor;
+ }
+ if (out_remainder) {
+ *out_remainder = in_dividend % in_divisor;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+#endif
+
+
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
new file mode 100644
index 000000000000..f6598547389b
--- /dev/null
+++ b/drivers/acpi/utilities/utmisc.c
@@ -0,0 +1,1516 @@
+/*******************************************************************************
+ *
+ * Module Name: utmisc - common utility procedures
+ *
+ ******************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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>
+
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utmisc")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_print_string
+ *
+ * PARAMETERS: String - Null terminated ASCII string
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Dump an ASCII string with support for ACPI-defined escape
+ * sequences.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_print_string (
+ char *string,
+ u8 max_length)
+{
+ u32 i;
+
+
+ if (!string) {
+ acpi_os_printf ("<\"NULL STRING PTR\">");
+ return;
+ }
+
+ acpi_os_printf ("\"");
+ for (i = 0; string[i] && (i < max_length); i++) {
+ /* Escape sequences */
+
+ switch (string[i]) {
+ case 0x07:
+ acpi_os_printf ("\\a"); /* BELL */
+ break;
+
+ case 0x08:
+ acpi_os_printf ("\\b"); /* BACKSPACE */
+ break;
+
+ case 0x0C:
+ acpi_os_printf ("\\f"); /* FORMFEED */
+ break;
+
+ case 0x0A:
+ acpi_os_printf ("\\n"); /* LINEFEED */
+ break;
+
+ case 0x0D:
+ acpi_os_printf ("\\r"); /* CARRIAGE RETURN*/
+ break;
+
+ case 0x09:
+ acpi_os_printf ("\\t"); /* HORIZONTAL TAB */
+ break;
+
+ case 0x0B:
+ acpi_os_printf ("\\v"); /* VERTICAL TAB */
+ break;
+
+ case '\'': /* Single Quote */
+ case '\"': /* Double Quote */
+ case '\\': /* Backslash */
+ acpi_os_printf ("\\%c", (int) string[i]);
+ break;
+
+ default:
+
+ /* Check for printable character or hex escape */
+
+ if (ACPI_IS_PRINT (string[i]))
+ {
+ /* This is a normal character */
+
+ acpi_os_printf ("%c", (int) string[i]);
+ }
+ else
+ {
+ /* All others will be Hex escapes */
+
+ acpi_os_printf ("\\x%2.2X", (s32) string[i]);
+ }
+ break;
+ }
+ }
+ acpi_os_printf ("\"");
+
+ if (i == max_length && string[i]) {
+ acpi_os_printf ("...");
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_dword_byte_swap
+ *
+ * PARAMETERS: Value - Value to be converted
+ *
+ * DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes)
+ *
+ ******************************************************************************/
+
+u32
+acpi_ut_dword_byte_swap (
+ u32 value)
+{
+ union {
+ u32 value;
+ u8 bytes[4];
+ } out;
+
+ union {
+ u32 value;
+ u8 bytes[4];
+ } in;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ in.value = value;
+
+ out.bytes[0] = in.bytes[3];
+ out.bytes[1] = in.bytes[2];
+ out.bytes[2] = in.bytes[1];
+ out.bytes[3] = in.bytes[0];
+
+ return (out.value);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_set_integer_width
+ *
+ * PARAMETERS: Revision From DSDT header
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Set the global integer bit width based upon the revision
+ * of the DSDT. For Revision 1 and 0, Integers are 32 bits.
+ * For Revision 2 and above, Integers are 64 bits. Yes, this
+ * makes a difference.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_set_integer_width (
+ u8 revision)
+{
+
+ if (revision <= 1) {
+ acpi_gbl_integer_bit_width = 32;
+ acpi_gbl_integer_nybble_width = 8;
+ acpi_gbl_integer_byte_width = 4;
+ }
+ else {
+ acpi_gbl_integer_bit_width = 64;
+ acpi_gbl_integer_nybble_width = 16;
+ acpi_gbl_integer_byte_width = 8;
+ }
+}
+
+
+#ifdef ACPI_DEBUG_OUTPUT
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_display_init_pathname
+ *
+ * PARAMETERS: obj_handle - Handle whose pathname will be displayed
+ * Path - Additional path string to be appended.
+ * (NULL if no extra path)
+ *
+ * RETURN: acpi_status
+ *
+ * DESCRIPTION: Display full pathname of an object, DEBUG ONLY
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_display_init_pathname (
+ u8 type,
+ struct acpi_namespace_node *obj_handle,
+ char *path)
+{
+ acpi_status status;
+ struct acpi_buffer buffer;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Only print the path if the appropriate debug level is enabled */
+
+ if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
+ return;
+ }
+
+ /* Get the full pathname to the node */
+
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+ status = acpi_ns_handle_to_pathname (obj_handle, &buffer);
+ if (ACPI_FAILURE (status)) {
+ return;
+ }
+
+ /* Print what we're doing */
+
+ switch (type) {
+ case ACPI_TYPE_METHOD:
+ acpi_os_printf ("Executing ");
+ break;
+
+ default:
+ acpi_os_printf ("Initializing ");
+ break;
+ }
+
+ /* Print the object type and pathname */
+
+ acpi_os_printf ("%-12s %s", acpi_ut_get_type_name (type), (char *) buffer.pointer);
+
+ /* Extra path is used to append names like _STA, _INI, etc. */
+
+ if (path) {
+ acpi_os_printf (".%s", path);
+ }
+ acpi_os_printf ("\n");
+
+ ACPI_MEM_FREE (buffer.pointer);
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_valid_acpi_name
+ *
+ * PARAMETERS: Character - The character to be examined
+ *
+ * RETURN: 1 if Character may appear in a name, else 0
+ *
+ * DESCRIPTION: Check for a valid ACPI name. Each character must be one of:
+ * 1) Upper case alpha
+ * 2) numeric
+ * 3) underscore
+ *
+ ******************************************************************************/
+
+u8
+acpi_ut_valid_acpi_name (
+ u32 name)
+{
+ char *name_ptr = (char *) &name;
+ char character;
+ acpi_native_uint i;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ for (i = 0; i < ACPI_NAME_SIZE; i++) {
+ character = *name_ptr;
+ name_ptr++;
+
+ if (!((character == '_') ||
+ (character >= 'A' && character <= 'Z') ||
+ (character >= '0' && character <= '9'))) {
+ return (FALSE);
+ }
+ }
+
+ return (TRUE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_valid_acpi_character
+ *
+ * PARAMETERS: Character - The character to be examined
+ *
+ * RETURN: 1 if Character may appear in a name, else 0
+ *
+ * DESCRIPTION: Check for a printable character
+ *
+ ******************************************************************************/
+
+u8
+acpi_ut_valid_acpi_character (
+ char character)
+{
+
+ ACPI_FUNCTION_ENTRY ();
+
+ return ((u8) ((character == '_') ||
+ (character >= 'A' && character <= 'Z') ||
+ (character >= '0' && character <= '9')));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_strtoul64
+ *
+ * PARAMETERS: String - Null terminated string
+ * Base - Radix of the string: 10, 16, or ACPI_ANY_BASE
+ * ret_integer - Where the converted integer is returned
+ *
+ * RETURN: Status and Converted value
+ *
+ * DESCRIPTION: Convert a string into an unsigned value.
+ * NOTE: Does not support Octal strings, not needed.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_strtoul64 (
+ char *string,
+ u32 base,
+ acpi_integer *ret_integer)
+{
+ u32 this_digit = 0;
+ acpi_integer return_value = 0;
+ acpi_integer quotient;
+
+
+ ACPI_FUNCTION_TRACE ("ut_stroul64");
+
+
+ if ((!string) || !(*string)) {
+ goto error_exit;
+ }
+
+ switch (base) {
+ case ACPI_ANY_BASE:
+ case 10:
+ case 16:
+ break;
+
+ default:
+ /* Invalid Base */
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ /* Skip over any white space in the buffer */
+
+ while (ACPI_IS_SPACE (*string) || *string == '\t') {
+ string++;
+ }
+
+ /*
+ * If the input parameter Base is zero, then we need to
+ * determine if it is decimal or hexadecimal:
+ */
+ if (base == 0) {
+ if ((*string == '0') &&
+ (ACPI_TOLOWER (*(string + 1)) == 'x')) {
+ base = 16;
+ string += 2;
+ }
+ else {
+ base = 10;
+ }
+ }
+
+ /*
+ * For hexadecimal base, skip over the leading
+ * 0 or 0x, if they are present.
+ */
+ if ((base == 16) &&
+ (*string == '0') &&
+ (ACPI_TOLOWER (*(string + 1)) == 'x')) {
+ string += 2;
+ }
+
+ /* Any string left? */
+
+ if (!(*string)) {
+ goto error_exit;
+ }
+
+ /* Main loop: convert the string to a 64-bit integer */
+
+ while (*string) {
+ if (ACPI_IS_DIGIT (*string)) {
+ /* Convert ASCII 0-9 to Decimal value */
+
+ this_digit = ((u8) *string) - '0';
+ }
+ else {
+ if (base == 10) {
+ /* Digit is out of range */
+
+ goto error_exit;
+ }
+
+ this_digit = (u8) ACPI_TOUPPER (*string);
+ if (ACPI_IS_XDIGIT ((char) this_digit)) {
+ /* Convert ASCII Hex char to value */
+
+ this_digit = this_digit - 'A' + 10;
+ }
+ else {
+ /*
+ * We allow non-hex chars, just stop now, same as end-of-string.
+ * See ACPI spec, string-to-integer conversion.
+ */
+ break;
+ }
+ }
+
+ /* Divide the digit into the correct position */
+
+ (void) acpi_ut_short_divide ((ACPI_INTEGER_MAX - (acpi_integer) this_digit),
+ base, &quotient, NULL);
+ if (return_value > quotient) {
+ goto error_exit;
+ }
+
+ return_value *= base;
+ return_value += this_digit;
+ string++;
+ }
+
+ /* All done, normal exit */
+
+ *ret_integer = return_value;
+ return_ACPI_STATUS (AE_OK);
+
+
+error_exit:
+ /* Base was set/validated above */
+
+ if (base == 10) {
+ return_ACPI_STATUS (AE_BAD_DECIMAL_CONSTANT);
+ }
+ else {
+ return_ACPI_STATUS (AE_BAD_HEX_CONSTANT);
+ }
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_strupr
+ *
+ * PARAMETERS: src_string - The source string to convert to
+ *
+ * RETURN: src_string
+ *
+ * DESCRIPTION: Convert string to uppercase
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+char *
+acpi_ut_strupr (
+ char *src_string)
+{
+ char *string;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Walk entire string, uppercasing the letters */
+
+ for (string = src_string; *string; ) {
+ *string = (char) ACPI_TOUPPER (*string);
+ string++;
+ }
+
+ return (src_string);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_mutex_initialize
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create the system mutex objects.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_mutex_initialize (
+ void)
+{
+ u32 i;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("ut_mutex_initialize");
+
+
+ /*
+ * Create each of the predefined mutex objects
+ */
+ for (i = 0; i < NUM_MUTEX; i++) {
+ status = acpi_ut_create_mutex (i);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ status = acpi_os_create_lock (&acpi_gbl_gpe_lock);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_mutex_terminate
+ *
+ * PARAMETERS: None.
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Delete all of the system mutex objects.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_mutex_terminate (
+ void)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE ("ut_mutex_terminate");
+
+
+ /*
+ * Delete each predefined mutex object
+ */
+ for (i = 0; i < NUM_MUTEX; i++) {
+ (void) acpi_ut_delete_mutex (i);
+ }
+
+ acpi_os_delete_lock (acpi_gbl_gpe_lock);
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_mutex
+ *
+ * PARAMETERS: mutex_iD - ID of the mutex to be created
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a mutex object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_create_mutex (
+ acpi_mutex_handle mutex_id)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ut_create_mutex", mutex_id);
+
+
+ if (mutex_id > MAX_MUTEX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ if (!acpi_gbl_mutex_info[mutex_id].mutex) {
+ status = acpi_os_create_semaphore (1, 1,
+ &acpi_gbl_mutex_info[mutex_id].mutex);
+ acpi_gbl_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED;
+ acpi_gbl_mutex_info[mutex_id].use_count = 0;
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_mutex
+ *
+ * PARAMETERS: mutex_iD - ID of the mutex to be deleted
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Delete a mutex object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_delete_mutex (
+ acpi_mutex_handle mutex_id)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ut_delete_mutex", mutex_id);
+
+
+ if (mutex_id > MAX_MUTEX) {
+ return_ACPI_STATUS (AE_BAD_PARAMETER);
+ }
+
+ status = acpi_os_delete_semaphore (acpi_gbl_mutex_info[mutex_id].mutex);
+
+ acpi_gbl_mutex_info[mutex_id].mutex = NULL;
+ acpi_gbl_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED;
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_acquire_mutex
+ *
+ * PARAMETERS: mutex_iD - ID of the mutex to be acquired
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Acquire a mutex object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_acquire_mutex (
+ acpi_mutex_handle mutex_id)
+{
+ acpi_status status;
+ u32 this_thread_id;
+
+
+ ACPI_FUNCTION_NAME ("ut_acquire_mutex");
+
+
+ if (mutex_id > MAX_MUTEX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ this_thread_id = acpi_os_get_thread_id ();
+
+#ifdef ACPI_MUTEX_DEBUG
+ {
+ u32 i;
+ /*
+ * Mutex debug code, for internal debugging only.
+ *
+ * Deadlock prevention. Check if this thread owns any mutexes of value
+ * greater than or equal to this one. If so, the thread has violated
+ * the mutex ordering rule. This indicates a coding error somewhere in
+ * the ACPI subsystem code.
+ */
+ for (i = mutex_id; i < MAX_MUTEX; i++) {
+ if (acpi_gbl_mutex_info[i].owner_id == this_thread_id) {
+ if (i == mutex_id) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Mutex [%s] already acquired by this thread [%X]\n",
+ acpi_ut_get_mutex_name (mutex_id), this_thread_id));
+
+ return (AE_ALREADY_ACQUIRED);
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid acquire order: Thread %X owns [%s], wants [%s]\n",
+ this_thread_id, acpi_ut_get_mutex_name (i),
+ acpi_ut_get_mutex_name (mutex_id)));
+
+ return (AE_ACQUIRE_DEADLOCK);
+ }
+ }
+ }
+#endif
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
+ "Thread %X attempting to acquire Mutex [%s]\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
+
+ status = acpi_os_wait_semaphore (acpi_gbl_mutex_info[mutex_id].mutex,
+ 1, ACPI_WAIT_FOREVER);
+ if (ACPI_SUCCESS (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
+
+ acpi_gbl_mutex_info[mutex_id].use_count++;
+ acpi_gbl_mutex_info[mutex_id].owner_id = this_thread_id;
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not acquire Mutex [%s] %s\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id),
+ acpi_format_exception (status)));
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_release_mutex
+ *
+ * PARAMETERS: mutex_iD - ID of the mutex to be released
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Release a mutex object.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_release_mutex (
+ acpi_mutex_handle mutex_id)
+{
+ acpi_status status;
+ u32 i;
+ u32 this_thread_id;
+
+
+ ACPI_FUNCTION_NAME ("ut_release_mutex");
+
+
+ this_thread_id = acpi_os_get_thread_id ();
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
+ "Thread %X releasing Mutex [%s]\n", this_thread_id,
+ acpi_ut_get_mutex_name (mutex_id)));
+
+ if (mutex_id > MAX_MUTEX) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ /*
+ * Mutex must be acquired in order to release it!
+ */
+ if (acpi_gbl_mutex_info[mutex_id].owner_id == ACPI_MUTEX_NOT_ACQUIRED) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Mutex [%s] is not acquired, cannot release\n",
+ acpi_ut_get_mutex_name (mutex_id)));
+
+ return (AE_NOT_ACQUIRED);
+ }
+
+ /*
+ * Deadlock prevention. Check if this thread owns any mutexes of value
+ * greater than this one. If so, the thread has violated the mutex
+ * ordering rule. This indicates a coding error somewhere in
+ * the ACPI subsystem code.
+ */
+ for (i = mutex_id; i < MAX_MUTEX; i++) {
+ if (acpi_gbl_mutex_info[i].owner_id == this_thread_id) {
+ if (i == mutex_id) {
+ continue;
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid release order: owns [%s], releasing [%s]\n",
+ acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id)));
+
+ return (AE_RELEASE_DEADLOCK);
+ }
+ }
+
+ /* Mark unlocked FIRST */
+
+ acpi_gbl_mutex_info[mutex_id].owner_id = ACPI_MUTEX_NOT_ACQUIRED;
+
+ status = acpi_os_signal_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, 1);
+
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not release Mutex [%s] %s\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id),
+ acpi_format_exception (status)));
+ }
+ else {
+ ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X released Mutex [%s]\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_update_state_and_push
+ *
+ * PARAMETERS: *Object - Object to be added to the new state
+ * Action - Increment/Decrement
+ * state_list - List the state will be added to
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Create a new state and push it
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_create_update_state_and_push (
+ union acpi_operand_object *object,
+ u16 action,
+ union acpi_generic_state **state_list)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Ignore null objects; these are expected */
+
+ if (!object) {
+ return (AE_OK);
+ }
+
+ state = acpi_ut_create_update_state (object, action);
+ if (!state) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_ut_push_generic_state (state_list, state);
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_pkg_state_and_push
+ *
+ * PARAMETERS: *Object - Object to be added to the new state
+ * Action - Increment/Decrement
+ * state_list - List the state will be added to
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Create a new state and push it
+ *
+ ******************************************************************************/
+#ifdef ACPI_FUTURE_USAGE
+acpi_status
+acpi_ut_create_pkg_state_and_push (
+ void *internal_object,
+ void *external_object,
+ u16 index,
+ union acpi_generic_state **state_list)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ state = acpi_ut_create_pkg_state (internal_object, external_object, index);
+ if (!state) {
+ return (AE_NO_MEMORY);
+ }
+
+ acpi_ut_push_generic_state (state_list, state);
+ return (AE_OK);
+}
+#endif /* ACPI_FUTURE_USAGE */
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_push_generic_state
+ *
+ * PARAMETERS: list_head - Head of the state stack
+ * State - State object to push
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Push a state object onto a state stack
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_push_generic_state (
+ union acpi_generic_state **list_head,
+ union acpi_generic_state *state)
+{
+ ACPI_FUNCTION_TRACE ("ut_push_generic_state");
+
+
+ /* Push the state object onto the front of the list (stack) */
+
+ state->common.next = *list_head;
+ *list_head = state;
+
+ return_VOID;
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_pop_generic_state
+ *
+ * PARAMETERS: list_head - Head of the state stack
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop a state object from a state stack
+ *
+ ******************************************************************************/
+
+union acpi_generic_state *
+acpi_ut_pop_generic_state (
+ union acpi_generic_state **list_head)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_TRACE ("ut_pop_generic_state");
+
+
+ /* Remove the state object at the head of the list (stack) */
+
+ state = *list_head;
+ if (state) {
+ /* Update the list head */
+
+ *list_head = state->common.next;
+ }
+
+ return_PTR (state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_generic_state
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a generic state object. Attempt to obtain one from
+ * the global state cache; If none available, create a new one.
+ *
+ ******************************************************************************/
+
+union acpi_generic_state *
+acpi_ut_create_generic_state (void)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ state = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_STATE);
+
+ /* Initialize */
+
+ if (state) {
+ state->common.data_type = ACPI_DESC_TYPE_STATE;
+ }
+
+ return (state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_thread_state
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Thread State
+ *
+ * DESCRIPTION: Create a "Thread State" - a flavor of the generic state used
+ * to track per-thread info during method execution
+ *
+ ******************************************************************************/
+
+struct acpi_thread_state *
+acpi_ut_create_thread_state (
+ void)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_TRACE ("ut_create_thread_state");
+
+
+ /* Create the generic state object */
+
+ state = acpi_ut_create_generic_state ();
+ if (!state) {
+ return_PTR (NULL);
+ }
+
+ /* Init fields specific to the update struct */
+
+ state->common.data_type = ACPI_DESC_TYPE_STATE_THREAD;
+ state->thread.thread_id = acpi_os_get_thread_id ();
+
+ return_PTR ((struct acpi_thread_state *) state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_update_state
+ *
+ * PARAMETERS: Object - Initial Object to be installed in the
+ * state
+ * Action - Update action to be performed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create an "Update State" - a flavor of the generic state used
+ * to update reference counts and delete complex objects such
+ * as packages.
+ *
+ ******************************************************************************/
+
+union acpi_generic_state *
+acpi_ut_create_update_state (
+ union acpi_operand_object *object,
+ u16 action)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_create_update_state", object);
+
+
+ /* Create the generic state object */
+
+ state = acpi_ut_create_generic_state ();
+ if (!state) {
+ return_PTR (NULL);
+ }
+
+ /* Init fields specific to the update struct */
+
+ state->common.data_type = ACPI_DESC_TYPE_STATE_UPDATE;
+ state->update.object = object;
+ state->update.value = action;
+
+ return_PTR (state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_pkg_state
+ *
+ * PARAMETERS: Object - Initial Object to be installed in the
+ * state
+ * Action - Update action to be performed
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a "Package State"
+ *
+ ******************************************************************************/
+
+union acpi_generic_state *
+acpi_ut_create_pkg_state (
+ void *internal_object,
+ void *external_object,
+ u16 index)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_create_pkg_state", internal_object);
+
+
+ /* Create the generic state object */
+
+ state = acpi_ut_create_generic_state ();
+ if (!state) {
+ return_PTR (NULL);
+ }
+
+ /* Init fields specific to the update struct */
+
+ state->common.data_type = ACPI_DESC_TYPE_STATE_PACKAGE;
+ state->pkg.source_object = (union acpi_operand_object *) internal_object;
+ state->pkg.dest_object = external_object;
+ state->pkg.index = index;
+ state->pkg.num_packages = 1;
+
+ return_PTR (state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_control_state
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Create a "Control State" - a flavor of the generic state used
+ * to support nested IF/WHILE constructs in the AML.
+ *
+ ******************************************************************************/
+
+union acpi_generic_state *
+acpi_ut_create_control_state (
+ void)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_TRACE ("ut_create_control_state");
+
+
+ /* Create the generic state object */
+
+ state = acpi_ut_create_generic_state ();
+ if (!state) {
+ return_PTR (NULL);
+ }
+
+ /* Init fields specific to the control struct */
+
+ state->common.data_type = ACPI_DESC_TYPE_STATE_CONTROL;
+ state->common.state = ACPI_CONTROL_CONDITIONAL_EXECUTING;
+
+ return_PTR (state);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_generic_state
+ *
+ * PARAMETERS: State - The state object to be deleted
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Put a state object back into the global state cache. The object
+ * is not actually freed at this time.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_delete_generic_state (
+ union acpi_generic_state *state)
+{
+ ACPI_FUNCTION_TRACE ("ut_delete_generic_state");
+
+
+ acpi_ut_release_to_cache (ACPI_MEM_LIST_STATE, state);
+ return_VOID;
+}
+
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_generic_state_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Purge the global state object cache. Used during subsystem
+ * termination.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_delete_generic_state_cache (
+ void)
+{
+ ACPI_FUNCTION_TRACE ("ut_delete_generic_state_cache");
+
+
+ acpi_ut_delete_generic_cache (ACPI_MEM_LIST_STATE);
+ return_VOID;
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_walk_package_tree
+ *
+ * PARAMETERS: obj_desc - The Package object on which to resolve refs
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Walk through a package
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_walk_package_tree (
+ union acpi_operand_object *source_object,
+ void *target_object,
+ acpi_pkg_callback walk_callback,
+ void *context)
+{
+ acpi_status status = AE_OK;
+ union acpi_generic_state *state_list = NULL;
+ union acpi_generic_state *state;
+ u32 this_index;
+ union acpi_operand_object *this_source_obj;
+
+
+ ACPI_FUNCTION_TRACE ("ut_walk_package_tree");
+
+
+ state = acpi_ut_create_pkg_state (source_object, target_object, 0);
+ if (!state) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+
+ while (state) {
+ /* Get one element of the package */
+
+ this_index = state->pkg.index;
+ this_source_obj = (union acpi_operand_object *)
+ state->pkg.source_object->package.elements[this_index];
+
+ /*
+ * Check for:
+ * 1) An uninitialized package element. It is completely
+ * legal to declare a package and leave it uninitialized
+ * 2) Not an internal object - can be a namespace node instead
+ * 3) Any type other than a package. Packages are handled in else
+ * case below.
+ */
+ if ((!this_source_obj) ||
+ (ACPI_GET_DESCRIPTOR_TYPE (this_source_obj) != ACPI_DESC_TYPE_OPERAND) ||
+ (ACPI_GET_OBJECT_TYPE (this_source_obj) != ACPI_TYPE_PACKAGE)) {
+ status = walk_callback (ACPI_COPY_TYPE_SIMPLE, this_source_obj,
+ state, context);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ state->pkg.index++;
+ while (state->pkg.index >= state->pkg.source_object->package.count) {
+ /*
+ * We've handled all of the objects at this level, This means
+ * that we have just completed a package. That package may
+ * have contained one or more packages itself.
+ *
+ * Delete this state and pop the previous state (package).
+ */
+ acpi_ut_delete_generic_state (state);
+ state = acpi_ut_pop_generic_state (&state_list);
+
+ /* Finished when there are no more states */
+
+ if (!state) {
+ /*
+ * We have handled all of the objects in the top level
+ * package just add the length of the package objects
+ * and exit
+ */
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /*
+ * Go back up a level and move the index past the just
+ * completed package object.
+ */
+ state->pkg.index++;
+ }
+ }
+ else {
+ /* This is a subobject of type package */
+
+ status = walk_callback (ACPI_COPY_TYPE_PACKAGE, this_source_obj,
+ state, context);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Push the current state and create a new one
+ * The callback above returned a new target package object.
+ */
+ acpi_ut_push_generic_state (&state_list, state);
+ state = acpi_ut_create_pkg_state (this_source_obj,
+ state->pkg.this_target_obj, 0);
+ if (!state) {
+ return_ACPI_STATUS (AE_NO_MEMORY);
+ }
+ }
+ }
+
+ /* We should never get here */
+
+ return_ACPI_STATUS (AE_AML_INTERNAL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_generate_checksum
+ *
+ * PARAMETERS: Buffer - Buffer to be scanned
+ * Length - number of bytes to examine
+ *
+ * RETURN: checksum
+ *
+ * DESCRIPTION: Generate a checksum on a raw buffer
+ *
+ ******************************************************************************/
+
+u8
+acpi_ut_generate_checksum (
+ u8 *buffer,
+ u32 length)
+{
+ u32 i;
+ signed char sum = 0;
+
+
+ for (i = 0; i < length; i++) {
+ sum = (signed char) (sum + buffer[i]);
+ }
+
+ return ((u8) (0 - sum));
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_resource_end_tag
+ *
+ * PARAMETERS: obj_desc - The resource template buffer object
+ *
+ * RETURN: Pointer to the end tag
+ *
+ * DESCRIPTION: Find the END_TAG resource descriptor in a resource template
+ *
+ ******************************************************************************/
+
+
+u8 *
+acpi_ut_get_resource_end_tag (
+ union acpi_operand_object *obj_desc)
+{
+ u8 buffer_byte;
+ u8 *buffer;
+ u8 *end_buffer;
+
+
+ buffer = obj_desc->buffer.pointer;
+ end_buffer = buffer + obj_desc->buffer.length;
+
+ while (buffer < end_buffer) {
+ buffer_byte = *buffer;
+ if (buffer_byte & ACPI_RDESC_TYPE_MASK) {
+ /* Large Descriptor - Length is next 2 bytes */
+
+ buffer += ((*(buffer+1) | (*(buffer+2) << 8)) + 3);
+ }
+ else {
+ /* Small Descriptor. End Tag will be found here */
+
+ if ((buffer_byte & ACPI_RDESC_SMALL_MASK) == ACPI_RDESC_TYPE_END_TAG) {
+ /* Found the end tag descriptor, all done. */
+
+ return (buffer);
+ }
+
+ /* Length is in the header */
+
+ buffer += ((buffer_byte & 0x07) + 1);
+ }
+ }
+
+ /* End tag not found */
+
+ return (NULL);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_report_error
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print error message
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_report_error (
+ char *module_name,
+ u32 line_number,
+ u32 component_id)
+{
+
+
+ acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_report_warning
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print warning message
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_report_warning (
+ char *module_name,
+ u32 line_number,
+ u32 component_id)
+{
+
+ acpi_os_printf ("%8s-%04d: *** Warning: ", module_name, line_number);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_report_info
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * component_id - Caller's component ID (for error output)
+ * Message - Error message to use on failure
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Print information message
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_report_info (
+ char *module_name,
+ u32 line_number,
+ u32 component_id)
+{
+
+ acpi_os_printf ("%8s-%04d: *** Info: ", module_name, line_number);
+}
+
+
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
new file mode 100644
index 000000000000..9ee40a484e07
--- /dev/null
+++ b/drivers/acpi/utilities/utobject.c
@@ -0,0 +1,671 @@
+/******************************************************************************
+ *
+ * Module Name: utobject - ACPI object create/delete/size/cache routines
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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/amlcode.h>
+
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utobject")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_internal_object_dbg
+ *
+ * PARAMETERS: module_name - Source file name of caller
+ * line_number - Line number of caller
+ * component_id - Component type of caller
+ * Type - ACPI Type of the new object
+ *
+ * RETURN: Object - The new object. Null on failure
+ *
+ * DESCRIPTION: Create and initialize a new internal object.
+ *
+ * NOTE: We always allocate the worst-case object descriptor because
+ * these objects are cached, and we want them to be
+ * one-size-satisifies-any-request. This in itself may not be
+ * the most memory efficient, but the efficiency of the object
+ * cache should more than make up for this!
+ *
+ ******************************************************************************/
+
+union acpi_operand_object *
+acpi_ut_create_internal_object_dbg (
+ char *module_name,
+ u32 line_number,
+ u32 component_id,
+ acpi_object_type type)
+{
+ union acpi_operand_object *object;
+ union acpi_operand_object *second_object;
+
+
+ ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg", acpi_ut_get_type_name (type));
+
+
+ /* Allocate the raw object descriptor */
+
+ object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id);
+ if (!object) {
+ return_PTR (NULL);
+ }
+
+ switch (type) {
+ case ACPI_TYPE_REGION:
+ case ACPI_TYPE_BUFFER_FIELD:
+
+ /* These types require a secondary object */
+
+ second_object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id);
+ if (!second_object) {
+ acpi_ut_delete_object_desc (object);
+ return_PTR (NULL);
+ }
+
+ second_object->common.type = ACPI_TYPE_LOCAL_EXTRA;
+ second_object->common.reference_count = 1;
+
+ /* Link the second object to the first */
+
+ object->common.next_object = second_object;
+ break;
+
+ default:
+ /* All others have no secondary object */
+ break;
+ }
+
+ /* Save the object type in the object descriptor */
+
+ object->common.type = (u8) type;
+
+ /* Init the reference count */
+
+ object->common.reference_count = 1;
+
+ /* Any per-type initialization should go here */
+
+ return_PTR (object);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_buffer_object
+ *
+ * PARAMETERS: buffer_size - Size of buffer to be created
+ *
+ * RETURN: Pointer to a new Buffer object
+ *
+ * DESCRIPTION: Create a fully initialized buffer object
+ *
+ ******************************************************************************/
+
+union acpi_operand_object *
+acpi_ut_create_buffer_object (
+ acpi_size buffer_size)
+{
+ union acpi_operand_object *buffer_desc;
+ u8 *buffer = NULL;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ut_create_buffer_object", buffer_size);
+
+
+ /* Create a new Buffer object */
+
+ buffer_desc = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
+ if (!buffer_desc) {
+ return_PTR (NULL);
+ }
+
+ /* Create an actual buffer only if size > 0 */
+
+ if (buffer_size > 0) {
+ /* Allocate the actual buffer */
+
+ buffer = ACPI_MEM_CALLOCATE (buffer_size);
+ if (!buffer) {
+ ACPI_REPORT_ERROR (("create_buffer: could not allocate size %X\n",
+ (u32) buffer_size));
+ acpi_ut_remove_reference (buffer_desc);
+ return_PTR (NULL);
+ }
+ }
+
+ /* Complete buffer object initialization */
+
+ buffer_desc->buffer.flags |= AOPOBJ_DATA_VALID;
+ buffer_desc->buffer.pointer = buffer;
+ buffer_desc->buffer.length = (u32) buffer_size;
+
+ /* Return the new buffer descriptor */
+
+ return_PTR (buffer_desc);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_create_string_object
+ *
+ * PARAMETERS: string_size - Size of string to be created. Does not
+ * include NULL terminator, this is added
+ * automatically.
+ *
+ * RETURN: Pointer to a new String object
+ *
+ * DESCRIPTION: Create a fully initialized string object
+ *
+ ******************************************************************************/
+
+union acpi_operand_object *
+acpi_ut_create_string_object (
+ acpi_size string_size)
+{
+ union acpi_operand_object *string_desc;
+ char *string;
+
+
+ ACPI_FUNCTION_TRACE_U32 ("ut_create_string_object", string_size);
+
+
+ /* Create a new String object */
+
+ string_desc = acpi_ut_create_internal_object (ACPI_TYPE_STRING);
+ if (!string_desc) {
+ return_PTR (NULL);
+ }
+
+ /*
+ * Allocate the actual string buffer -- (Size + 1) for NULL terminator.
+ * NOTE: Zero-length strings are NULL terminated
+ */
+ string = ACPI_MEM_CALLOCATE (string_size + 1);
+ if (!string) {
+ ACPI_REPORT_ERROR (("create_string: could not allocate size %X\n",
+ (u32) string_size));
+ acpi_ut_remove_reference (string_desc);
+ return_PTR (NULL);
+ }
+
+ /* Complete string object initialization */
+
+ string_desc->string.pointer = string;
+ string_desc->string.length = (u32) string_size;
+
+ /* Return the new string descriptor */
+
+ return_PTR (string_desc);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_valid_internal_object
+ *
+ * PARAMETERS: Object - Object to be validated
+ *
+ * RETURN: Validate a pointer to be an union acpi_operand_object
+ *
+ ******************************************************************************/
+
+u8
+acpi_ut_valid_internal_object (
+ void *object)
+{
+
+ ACPI_FUNCTION_NAME ("ut_valid_internal_object");
+
+
+ /* Check for a null pointer */
+
+ if (!object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "**** Null Object Ptr\n"));
+ return (FALSE);
+ }
+
+ /* Check the descriptor type field */
+
+ switch (ACPI_GET_DESCRIPTOR_TYPE (object)) {
+ case ACPI_DESC_TYPE_OPERAND:
+
+ /* The object appears to be a valid union acpi_operand_object */
+
+ return (TRUE);
+
+ default:
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "%p is not not an ACPI operand obj [%s]\n",
+ object, acpi_ut_get_descriptor_name (object)));
+ break;
+ }
+
+ return (FALSE);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_allocate_object_desc_dbg
+ *
+ * PARAMETERS: module_name - Caller's module name (for error output)
+ * line_number - Caller's line number (for error output)
+ * component_id - Caller's component ID (for error output)
+ *
+ * RETURN: Pointer to newly allocated object descriptor. Null on error
+ *
+ * DESCRIPTION: Allocate a new object descriptor. Gracefully handle
+ * error conditions.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ut_allocate_object_desc_dbg (
+ char *module_name,
+ u32 line_number,
+ u32 component_id)
+{
+ union acpi_operand_object *object;
+
+
+ ACPI_FUNCTION_TRACE ("ut_allocate_object_desc_dbg");
+
+
+ object = acpi_ut_acquire_from_cache (ACPI_MEM_LIST_OPERAND);
+ if (!object) {
+ _ACPI_REPORT_ERROR (module_name, line_number, component_id,
+ ("Could not allocate an object descriptor\n"));
+
+ return_PTR (NULL);
+ }
+
+ /* Mark the descriptor type */
+
+ ACPI_SET_DESCRIPTOR_TYPE (object, ACPI_DESC_TYPE_OPERAND);
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "%p Size %X\n",
+ object, (u32) sizeof (union acpi_operand_object)));
+
+ return_PTR (object);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_object_desc
+ *
+ * PARAMETERS: Object - An Acpi internal object to be deleted
+ *
+ * RETURN: None.
+ *
+ * DESCRIPTION: Free an ACPI object descriptor or add it to the object cache
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_delete_object_desc (
+ union acpi_operand_object *object)
+{
+ ACPI_FUNCTION_TRACE_PTR ("ut_delete_object_desc", object);
+
+
+ /* Object must be an union acpi_operand_object */
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (object) != ACPI_DESC_TYPE_OPERAND) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "%p is not an ACPI Operand object [%s]\n", object,
+ acpi_ut_get_descriptor_name (object)));
+ return_VOID;
+ }
+
+ acpi_ut_release_to_cache (ACPI_MEM_LIST_OPERAND, object);
+
+ return_VOID;
+}
+
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_delete_object_cache
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Purge the global state object cache. Used during subsystem
+ * termination.
+ *
+ ******************************************************************************/
+
+void
+acpi_ut_delete_object_cache (
+ void)
+{
+ ACPI_FUNCTION_TRACE ("ut_delete_object_cache");
+
+
+ acpi_ut_delete_generic_cache (ACPI_MEM_LIST_OPERAND);
+ return_VOID;
+}
+#endif
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_simple_object_size
+ *
+ * PARAMETERS: *internal_object - Pointer to the object we are examining
+ * *obj_length - Where the length is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to determine the space required to
+ * contain a simple object for return to an external user.
+ *
+ * The length includes the object structure plus any additional
+ * needed space.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_get_simple_object_size (
+ union acpi_operand_object *internal_object,
+ acpi_size *obj_length)
+{
+ acpi_size length;
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_get_simple_object_size", internal_object);
+
+
+ /* Handle a null object (Could be a uninitialized package element -- which is legal) */
+
+ if (!internal_object) {
+ *obj_length = 0;
+ return_ACPI_STATUS (AE_OK);
+ }
+
+ /* Start with the length of the Acpi object */
+
+ length = sizeof (union acpi_object);
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (internal_object) == ACPI_DESC_TYPE_NAMED) {
+ /* Object is a named object (reference), just return the length */
+
+ *obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD (length);
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * The final length depends on the object type
+ * Strings and Buffers are packed right up against the parent object and
+ * must be accessed bytewise or there may be alignment problems on
+ * certain processors
+ */
+ switch (ACPI_GET_OBJECT_TYPE (internal_object)) {
+ case ACPI_TYPE_STRING:
+
+ length += (acpi_size) internal_object->string.length + 1;
+ break;
+
+
+ case ACPI_TYPE_BUFFER:
+
+ length += (acpi_size) internal_object->buffer.length;
+ break;
+
+
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_PROCESSOR:
+ case ACPI_TYPE_POWER:
+
+ /*
+ * No extra data for these types
+ */
+ break;
+
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ switch (internal_object->reference.opcode) {
+ case AML_INT_NAMEPATH_OP:
+
+ /*
+ * Get the actual length of the full pathname to this object.
+ * The reference will be converted to the pathname to the object
+ */
+ length += ACPI_ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node));
+ break;
+
+ default:
+
+ /*
+ * No other reference opcodes are supported.
+ * Notably, Locals and Args are not supported, but this may be
+ * required eventually.
+ */
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unsupported Reference opcode=%X in object %p\n",
+ internal_object->reference.opcode, internal_object));
+ status = AE_TYPE;
+ break;
+ }
+ break;
+
+
+ default:
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported type=%X in object %p\n",
+ ACPI_GET_OBJECT_TYPE (internal_object), internal_object));
+ status = AE_TYPE;
+ break;
+ }
+
+ /*
+ * Account for the space required by the object rounded up to the next
+ * multiple of the machine word size. This keeps each object aligned
+ * on a machine word boundary. (preventing alignment faults on some
+ * machines.)
+ */
+ *obj_length = ACPI_ROUND_UP_TO_NATIVE_WORD (length);
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_element_length
+ *
+ * PARAMETERS: acpi_pkg_callback
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Get the length of one package element.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_get_element_length (
+ u8 object_type,
+ union acpi_operand_object *source_object,
+ union acpi_generic_state *state,
+ void *context)
+{
+ acpi_status status = AE_OK;
+ struct acpi_pkg_info *info = (struct acpi_pkg_info *) context;
+ acpi_size object_space;
+
+
+ switch (object_type) {
+ case ACPI_COPY_TYPE_SIMPLE:
+
+ /*
+ * Simple object - just get the size (Null object/entry is handled
+ * here also) and sum it into the running package length
+ */
+ status = acpi_ut_get_simple_object_size (source_object, &object_space);
+ if (ACPI_FAILURE (status)) {
+ return (status);
+ }
+
+ info->length += object_space;
+ break;
+
+
+ case ACPI_COPY_TYPE_PACKAGE:
+
+ /* Package object - nothing much to do here, let the walk handle it */
+
+ info->num_packages++;
+ state->pkg.this_target_obj = NULL;
+ break;
+
+
+ default:
+
+ /* No other types allowed */
+
+ return (AE_BAD_PARAMETER);
+ }
+
+ return (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_package_object_size
+ *
+ * PARAMETERS: *internal_object - Pointer to the object we are examining
+ * *obj_length - Where the length is returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to determine the space required to
+ * contain a package object for return to an external user.
+ *
+ * This is moderately complex since a package contains other
+ * objects including packages.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_get_package_object_size (
+ union acpi_operand_object *internal_object,
+ acpi_size *obj_length)
+{
+ acpi_status status;
+ struct acpi_pkg_info info;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ut_get_package_object_size", internal_object);
+
+
+ info.length = 0;
+ info.object_space = 0;
+ info.num_packages = 1;
+
+ status = acpi_ut_walk_package_tree (internal_object, NULL,
+ acpi_ut_get_element_length, &info);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * We have handled all of the objects in all levels of the package.
+ * just add the length of the package objects themselves.
+ * Round up to the next machine word.
+ */
+ info.length += ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object)) *
+ (acpi_size) info.num_packages;
+
+ /* Return the total package length */
+
+ *obj_length = info.length;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_get_object_size
+ *
+ * PARAMETERS: *internal_object - Pointer to the object we are examining
+ * *obj_length - Where the length will be returned
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: This function is called to determine the space required to
+ * contain an object for return to an API user.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ut_get_object_size(
+ union acpi_operand_object *internal_object,
+ acpi_size *obj_length)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ if ((ACPI_GET_DESCRIPTOR_TYPE (internal_object) == ACPI_DESC_TYPE_OPERAND) &&
+ (ACPI_GET_OBJECT_TYPE (internal_object) == ACPI_TYPE_PACKAGE)) {
+ status = acpi_ut_get_package_object_size (internal_object, obj_length);
+ }
+ else {
+ status = acpi_ut_get_simple_object_size (internal_object, obj_length);
+ }
+
+ return (status);
+}
+
+
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
new file mode 100644
index 000000000000..97a91f3f06f0
--- /dev/null
+++ b/drivers/acpi/utilities/utxface.c
@@ -0,0 +1,525 @@
+/******************************************************************************
+ *
+ * Module Name: utxface - External interfaces for "global" ACPI functions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * 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 <linux/module.h>
+
+#include <acpi/acpi.h>
+#include <acpi/acevents.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acdispat.h>
+#include <acpi/acdebug.h>
+
+#define _COMPONENT ACPI_UTILITIES
+ ACPI_MODULE_NAME ("utxface")
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_initialize_subsystem
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Initializes all global variables. This is the first function
+ * called, so any early initialization belongs here.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_initialize_subsystem (
+ void)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE ("acpi_initialize_subsystem");
+
+
+ ACPI_DEBUG_EXEC (acpi_ut_init_stack_ptr_trace ());
+
+
+ /* Initialize all globals used by the subsystem */
+
+ acpi_ut_init_globals ();
+
+ /* Initialize the OS-Dependent layer */
+
+ status = acpi_os_initialize ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("OSD failed to initialize, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ /* Create the default mutex objects */
+
+ status = acpi_ut_mutex_initialize ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Global mutex creation failure, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Initialize the namespace manager and
+ * the root of the namespace tree
+ */
+
+ status = acpi_ns_root_initialize ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_REPORT_ERROR (("Namespace initialization failure, %s\n",
+ acpi_format_exception (status)));
+ return_ACPI_STATUS (status);
+ }
+
+
+ /* If configured, initialize the AML debugger */
+
+ ACPI_DEBUGGER_EXEC (status = acpi_db_initialize ());
+
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_enable_subsystem
+ *
+ * PARAMETERS: Flags - Init/enable Options
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Completes the subsystem initialization including hardware.
+ * Puts system into ACPI mode if it isn't already.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_enable_subsystem (
+ u32 flags)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_enable_subsystem");
+
+
+ /*
+ * We must initialize the hardware before we can enable ACPI.
+ * The values from the FADT are validated here.
+ */
+ if (!(flags & ACPI_NO_HARDWARE_INIT)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI hardware\n"));
+
+ status = acpi_hw_initialize ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Enable ACPI mode */
+
+ if (!(flags & ACPI_NO_ACPI_ENABLE)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Going into ACPI mode\n"));
+
+ acpi_gbl_original_mode = acpi_hw_get_mode();
+
+ status = acpi_enable ();
+ if (ACPI_FAILURE (status)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "acpi_enable failed.\n"));
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Install the default op_region handlers. These are installed unless
+ * other handlers have already been installed via the
+ * install_address_space_handler interface.
+ */
+ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing default address space handlers\n"));
+
+ status = acpi_ev_install_region_handlers ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Initialize ACPI Event handling (Fixed and General Purpose)
+ *
+ * NOTE: We must have the hardware AND events initialized before we can execute
+ * ANY control methods SAFELY. Any control method can require ACPI hardware
+ * support, so the hardware MUST be initialized before execution!
+ */
+ if (!(flags & ACPI_NO_EVENT_INIT)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n"));
+
+ status = acpi_ev_initialize_events ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /* Install the SCI handler and Global Lock handler */
+
+ if (!(flags & ACPI_NO_HANDLER_INIT)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n"));
+
+ status = acpi_ev_install_xrupt_handlers ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ return_ACPI_STATUS (status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_initialize_objects
+ *
+ * PARAMETERS: Flags - Init/enable Options
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Completes namespace initialization by initializing device
+ * objects and executing AML code for Regions, buffers, etc.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_initialize_objects (
+ u32 flags)
+{
+ acpi_status status = AE_OK;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_initialize_objects");
+
+
+ /*
+ * Run all _REG methods
+ *
+ * NOTE: Any objects accessed
+ * by the _REG methods will be automatically initialized, even if they
+ * contain executable AML (see call to acpi_ns_initialize_objects below).
+ */
+ if (!(flags & ACPI_NO_ADDRESS_SPACE_INIT)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Executing _REG op_region methods\n"));
+
+ status = acpi_ev_initialize_op_regions ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Initialize the objects that remain uninitialized. This
+ * runs the executable AML that may be part of the declaration of these
+ * objects: operation_regions, buffer_fields, Buffers, and Packages.
+ */
+ if (!(flags & ACPI_NO_OBJECT_INIT)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of ACPI Objects\n"));
+
+ status = acpi_ns_initialize_objects ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Initialize all device objects in the namespace
+ * This runs the _STA and _INI methods.
+ */
+ if (!(flags & ACPI_NO_DEVICE_INIT)) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Devices\n"));
+
+ status = acpi_ns_initialize_devices ();
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+ }
+
+ /*
+ * Empty the caches (delete the cached objects) on the assumption that
+ * the table load filled them up more than they will be at runtime --
+ * thus wasting non-paged memory.
+ */
+ status = acpi_purge_cached_objects ();
+
+ acpi_gbl_startup_flags |= ACPI_INITIALIZED_OK;
+ return_ACPI_STATUS (status);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_terminate
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Shutdown the ACPI subsystem. Release all resources.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_terminate (void)
+{
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_terminate");
+
+
+ /* Terminate the AML Debugger if present */
+
+ ACPI_DEBUGGER_EXEC(acpi_gbl_db_terminate_threads = TRUE);
+
+ /* Shutdown and free all resources */
+
+ acpi_ut_subsystem_shutdown ();
+
+
+ /* Free the mutex objects */
+
+ acpi_ut_mutex_terminate ();
+
+
+#ifdef ACPI_DEBUGGER
+
+ /* Shut down the debugger */
+
+ acpi_db_terminate ();
+#endif
+
+ /* Now we can shutdown the OS-dependent layer */
+
+ status = acpi_os_terminate ();
+ return_ACPI_STATUS (status);
+}
+
+
+#ifdef ACPI_FUTURE_USAGE
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_subsystem_status
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status of the ACPI subsystem
+ *
+ * DESCRIPTION: Other drivers that use the ACPI subsystem should call this
+ * before making any other calls, to ensure the subsystem initial-
+ * ized successfully.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_subsystem_status (void)
+{
+ if (acpi_gbl_startup_flags & ACPI_INITIALIZED_OK) {
+ return (AE_OK);
+ }
+ else {
+ return (AE_ERROR);
+ }
+}
+
+
+/******************************************************************************
+ *
+ * FUNCTION: acpi_get_system_info
+ *
+ * PARAMETERS: out_buffer - a pointer to a buffer to receive the
+ * resources for the device
+ * buffer_length - the number of bytes available in the buffer
+ *
+ * RETURN: Status - the status of the call
+ *
+ * DESCRIPTION: This function is called to get information about the current
+ * state of the ACPI subsystem. It will return system information
+ * in the out_buffer.
+ *
+ * If the function fails an appropriate status will be returned
+ * and the value of out_buffer is undefined.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_get_system_info (
+ struct acpi_buffer *out_buffer)
+{
+ struct acpi_system_info *info_ptr;
+ u32 i;
+ acpi_status status;
+
+
+ ACPI_FUNCTION_TRACE ("acpi_get_system_info");
+
+
+ /* Parameter validation */
+
+ status = acpi_ut_validate_buffer (out_buffer);
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /* Validate/Allocate/Clear caller buffer */
+
+ status = acpi_ut_initialize_buffer (out_buffer, sizeof (struct acpi_system_info));
+ if (ACPI_FAILURE (status)) {
+ return_ACPI_STATUS (status);
+ }
+
+ /*
+ * Populate the return buffer
+ */
+ info_ptr = (struct acpi_system_info *) out_buffer->pointer;
+
+ info_ptr->acpi_ca_version = ACPI_CA_VERSION;
+
+ /* System flags (ACPI capabilities) */
+
+ info_ptr->flags = ACPI_SYS_MODE_ACPI;
+
+ /* Timer resolution - 24 or 32 bits */
+
+ if (!acpi_gbl_FADT) {
+ info_ptr->timer_resolution = 0;
+ }
+ else if (acpi_gbl_FADT->tmr_val_ext == 0) {
+ info_ptr->timer_resolution = 24;
+ }
+ else {
+ info_ptr->timer_resolution = 32;
+ }
+
+ /* Clear the reserved fields */
+
+ info_ptr->reserved1 = 0;
+ info_ptr->reserved2 = 0;
+
+ /* Current debug levels */
+
+ info_ptr->debug_layer = acpi_dbg_layer;
+ info_ptr->debug_level = acpi_dbg_level;
+
+ /* Current status of the ACPI tables, per table type */
+
+ info_ptr->num_table_types = NUM_ACPI_TABLE_TYPES;
+ for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) {
+ info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count;
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+EXPORT_SYMBOL(acpi_get_system_info);
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_install_initialization_handler
+ *
+ * PARAMETERS: Handler - Callback procedure
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install an initialization handler
+ *
+ * TBD: When a second function is added, must save the Function also.
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_install_initialization_handler (
+ acpi_init_handler handler,
+ u32 function)
+{
+
+ if (!handler) {
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (acpi_gbl_init_handler) {
+ return (AE_ALREADY_EXISTS);
+ }
+
+ acpi_gbl_init_handler = handler;
+ return AE_OK;
+}
+
+#endif /* ACPI_FUTURE_USAGE */
+
+
+/*****************************************************************************
+ *
+ * FUNCTION: acpi_purge_cached_objects
+ *
+ * PARAMETERS: None
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Empty all caches (delete the cached objects)
+ *
+ ****************************************************************************/
+
+acpi_status
+acpi_purge_cached_objects (void)
+{
+ ACPI_FUNCTION_TRACE ("acpi_purge_cached_objects");
+
+
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+ acpi_ut_delete_generic_state_cache ();
+ acpi_ut_delete_object_cache ();
+ acpi_ds_delete_walk_state_cache ();
+ acpi_ps_delete_parse_cache ();
+#endif
+
+ return_ACPI_STATUS (AE_OK);
+}
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
new file mode 100644
index 000000000000..1ce2047c3804
--- /dev/null
+++ b/drivers/acpi/utils.c
@@ -0,0 +1,423 @@
+/*
+ * acpi_utils.c - ACPI Utility Functions ($Revision: 10 $)
+ *
+ * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
+ * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@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 <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+
+#define _COMPONENT ACPI_BUS_COMPONENT
+ACPI_MODULE_NAME ("acpi_utils")
+
+
+/* --------------------------------------------------------------------------
+ Object Evaluation Helpers
+ -------------------------------------------------------------------------- */
+
+#ifdef ACPI_DEBUG_OUTPUT
+#define acpi_util_eval_error(h,p,s) {\
+ char prefix[80] = {'\0'};\
+ struct acpi_buffer buffer = {sizeof(prefix), prefix};\
+ acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",\
+ (char *) prefix, p, acpi_format_exception(s))); }
+#else
+#define acpi_util_eval_error(h,p,s)
+#endif
+
+
+acpi_status
+acpi_extract_package (
+ union acpi_object *package,
+ struct acpi_buffer *format,
+ struct acpi_buffer *buffer)
+{
+ u32 size_required = 0;
+ u32 tail_offset = 0;
+ char *format_string = NULL;
+ u32 format_count = 0;
+ u32 i = 0;
+ u8 *head = NULL;
+ u8 *tail = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_extract_package");
+
+ if (!package || (package->type != ACPI_TYPE_PACKAGE) || (package->package.count < 1)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'package' argument\n"));
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (!format || !format->pointer || (format->length < 1)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'format' argument\n"));
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ if (!buffer) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid 'buffer' argument\n"));
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ format_count = (format->length/sizeof(char)) - 1;
+ if (format_count > package->package.count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Format specifies more objects [%d] than exist in package [%d].", format_count, package->package.count));
+ return_ACPI_STATUS(AE_BAD_DATA);
+ }
+
+ format_string = (char*)format->pointer;
+
+ /*
+ * Calculate size_required.
+ */
+ for (i=0; i<format_count; i++) {
+
+ union acpi_object *element = &(package->package.elements[i]);
+
+ if (!element) {
+ return_ACPI_STATUS(AE_BAD_DATA);
+ }
+
+ switch (element->type) {
+
+ case ACPI_TYPE_INTEGER:
+ switch (format_string[i]) {
+ case 'N':
+ size_required += sizeof(acpi_integer);
+ tail_offset += sizeof(acpi_integer);
+ break;
+ case 'S':
+ size_required += sizeof(char*) + sizeof(acpi_integer) + sizeof(char);
+ tail_offset += sizeof(char*);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d]: got number, expecing [%c].\n", i, format_string[i]));
+ return_ACPI_STATUS(AE_BAD_DATA);
+ break;
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ switch (format_string[i]) {
+ case 'S':
+ size_required += sizeof(char*) + (element->string.length * sizeof(char)) + sizeof(char);
+ tail_offset += sizeof(char*);
+ break;
+ case 'B':
+ size_required += sizeof(u8*) + (element->buffer.length * sizeof(u8));
+ tail_offset += sizeof(u8*);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid package element [%d] got string/buffer, expecing [%c].\n", i, format_string[i]));
+ return_ACPI_STATUS(AE_BAD_DATA);
+ break;
+ }
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unsupported element at index=%d\n", i));
+ /* TBD: handle nested packages... */
+ return_ACPI_STATUS(AE_SUPPORT);
+ break;
+ }
+ }
+
+ /*
+ * Validate output buffer.
+ */
+ if (buffer->length < size_required) {
+ buffer->length = size_required;
+ return_ACPI_STATUS(AE_BUFFER_OVERFLOW);
+ }
+ else if (buffer->length != size_required || !buffer->pointer) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ head = buffer->pointer;
+ tail = buffer->pointer + tail_offset;
+
+ /*
+ * Extract package data.
+ */
+ for (i=0; i<format_count; i++) {
+
+ u8 **pointer = NULL;
+ union acpi_object *element = &(package->package.elements[i]);
+
+ if (!element) {
+ return_ACPI_STATUS(AE_BAD_DATA);
+ }
+
+ switch (element->type) {
+
+ case ACPI_TYPE_INTEGER:
+ switch (format_string[i]) {
+ case 'N':
+ *((acpi_integer*)head) = element->integer.value;
+ head += sizeof(acpi_integer);
+ break;
+ case 'S':
+ pointer = (u8**)head;
+ *pointer = tail;
+ *((acpi_integer*)tail) = element->integer.value;
+ head += sizeof(acpi_integer*);
+ tail += sizeof(acpi_integer);
+ /* NULL terminate string */
+ *tail = (char)0;
+ tail += sizeof(char);
+ break;
+ default:
+ /* Should never get here */
+ break;
+ }
+ break;
+
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_BUFFER:
+ switch (format_string[i]) {
+ case 'S':
+ pointer = (u8**)head;
+ *pointer = tail;
+ memcpy(tail, element->string.pointer, element->string.length);
+ head += sizeof(char*);
+ tail += element->string.length * sizeof(char);
+ /* NULL terminate string */
+ *tail = (char)0;
+ tail += sizeof(char);
+ break;
+ case 'B':
+ pointer = (u8**)head;
+ *pointer = tail;
+ memcpy(tail, element->buffer.pointer, element->buffer.length);
+ head += sizeof(u8*);
+ tail += element->buffer.length * sizeof(u8);
+ break;
+ default:
+ /* Should never get here */
+ break;
+ }
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+ /* TBD: handle nested packages... */
+ default:
+ /* Should never get here */
+ break;
+ }
+ }
+
+ return_ACPI_STATUS(AE_OK);
+}
+EXPORT_SYMBOL(acpi_extract_package);
+
+
+acpi_status
+acpi_evaluate_integer (
+ acpi_handle handle,
+ acpi_string pathname,
+ struct acpi_object_list *arguments,
+ unsigned long *data)
+{
+ acpi_status status = AE_OK;
+ union acpi_object *element;
+ struct acpi_buffer buffer = {0,NULL};
+
+ ACPI_FUNCTION_TRACE("acpi_evaluate_integer");
+
+ if (!data)
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+ element = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+ if(!element)
+ return_ACPI_STATUS(AE_NO_MEMORY);
+
+ memset(element, 0, sizeof(union acpi_object));
+ buffer.length = sizeof(union acpi_object);
+ buffer.pointer = element;
+ status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_util_eval_error(handle, pathname, status);
+ return_ACPI_STATUS(status);
+ }
+
+ if (element->type != ACPI_TYPE_INTEGER) {
+ acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
+ return_ACPI_STATUS(AE_BAD_DATA);
+ }
+
+ *data = element->integer.value;
+ kfree(element);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%lu]\n", *data));
+
+ return_ACPI_STATUS(AE_OK);
+}
+EXPORT_SYMBOL(acpi_evaluate_integer);
+
+
+#if 0
+acpi_status
+acpi_evaluate_string (
+ acpi_handle handle,
+ acpi_string pathname,
+ acpi_object_list *arguments,
+ acpi_string *data)
+{
+ acpi_status status = AE_OK;
+ acpi_object *element = NULL;
+ acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+
+ ACPI_FUNCTION_TRACE("acpi_evaluate_string");
+
+ if (!data)
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+
+ status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_util_eval_error(handle, pathname, status);
+ return_ACPI_STATUS(status);
+ }
+
+ element = (acpi_object *) buffer.pointer;
+
+ if ((element->type != ACPI_TYPE_STRING)
+ || (element->type != ACPI_TYPE_BUFFER)
+ || !element->string.length) {
+ acpi_util_eval_error(handle, pathname, AE_BAD_DATA);
+ return_ACPI_STATUS(AE_BAD_DATA);
+ }
+
+ *data = kmalloc(element->string.length + 1, GFP_KERNEL);
+ if (!data) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Memory allocation error\n"));
+ return_VALUE(-ENOMEM);
+ }
+ memset(*data, 0, element->string.length + 1);
+
+ memcpy(*data, element->string.pointer, element->string.length);
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Return value [%s]\n", *data));
+
+ acpi_os_free(buffer.pointer);
+
+ return_ACPI_STATUS(AE_OK);
+}
+#endif
+
+
+acpi_status
+acpi_evaluate_reference (
+ acpi_handle handle,
+ acpi_string pathname,
+ struct acpi_object_list *arguments,
+ struct acpi_handle_list *list)
+{
+ acpi_status status = AE_OK;
+ union acpi_object *package = NULL;
+ union acpi_object *element = NULL;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ u32 i = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_evaluate_reference");
+
+ if (!list) {
+ return_ACPI_STATUS(AE_BAD_PARAMETER);
+ }
+
+ /* Evaluate object. */
+
+ status = acpi_evaluate_object(handle, pathname, arguments, &buffer);
+ if (ACPI_FAILURE(status))
+ goto end;
+
+ package = (union acpi_object *) buffer.pointer;
+
+ if ((buffer.length == 0) || !package) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "No return object (len %X ptr %p)\n",
+ (unsigned)buffer.length, package));
+ status = AE_BAD_DATA;
+ acpi_util_eval_error(handle, pathname, status);
+ goto end;
+ }
+ if (package->type != ACPI_TYPE_PACKAGE) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Expecting a [Package], found type %X\n",
+ package->type));
+ status = AE_BAD_DATA;
+ acpi_util_eval_error(handle, pathname, status);
+ goto end;
+ }
+ if (!package->package.count) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "[Package] has zero elements (%p)\n",
+ package));
+ status = AE_BAD_DATA;
+ acpi_util_eval_error(handle, pathname, status);
+ goto end;
+ }
+
+ if (package->package.count > ACPI_MAX_HANDLES) {
+ return_ACPI_STATUS(AE_NO_MEMORY);
+ }
+ list->count = package->package.count;
+
+ /* Extract package data. */
+
+ for (i = 0; i < list->count; i++) {
+
+ element = &(package->package.elements[i]);
+
+ if (element->type != ACPI_TYPE_ANY) {
+ status = AE_BAD_DATA;
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Expecting a [Reference] package element, found type %X\n",
+ element->type));
+ acpi_util_eval_error(handle, pathname, status);
+ break;
+ }
+
+ /* Get the acpi_handle. */
+
+ list->handles[i] = element->reference.handle;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found reference [%p]\n",
+ list->handles[i]));
+ }
+
+end:
+ if (ACPI_FAILURE(status)) {
+ list->count = 0;
+ //kfree(list->handles);
+ }
+
+ acpi_os_free(buffer.pointer);
+
+ return_ACPI_STATUS(status);
+}
+EXPORT_SYMBOL(acpi_evaluate_reference);
+
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
new file mode 100644
index 000000000000..71fa1011715f
--- /dev/null
+++ b/drivers/acpi/video.c
@@ -0,0 +1,1989 @@
+/*
+ * video.c - ACPI Video Driver ($Revision:$)
+ *
+ * Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
+ * Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * 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/list.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+#define ACPI_VIDEO_COMPONENT 0x08000000
+#define ACPI_VIDEO_CLASS "video"
+#define ACPI_VIDEO_DRIVER_NAME "ACPI Video Driver"
+#define ACPI_VIDEO_BUS_NAME "Video Bus"
+#define ACPI_VIDEO_DEVICE_NAME "Video Device"
+#define ACPI_VIDEO_NOTIFY_SWITCH 0x80
+#define ACPI_VIDEO_NOTIFY_PROBE 0x81
+#define ACPI_VIDEO_NOTIFY_CYCLE 0x82
+#define ACPI_VIDEO_NOTIFY_NEXT_OUTPUT 0x83
+#define ACPI_VIDEO_NOTIFY_PREV_OUTPUT 0x84
+
+#define ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS 0x82
+#define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x83
+#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x84
+#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS 0x85
+#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF 0x86
+
+
+#define ACPI_VIDEO_HEAD_INVALID (~0u - 1)
+#define ACPI_VIDEO_HEAD_END (~0u)
+
+
+#define _COMPONENT ACPI_VIDEO_COMPONENT
+ACPI_MODULE_NAME ("acpi_video")
+
+MODULE_AUTHOR("Bruno Ducrot");
+MODULE_DESCRIPTION(ACPI_VIDEO_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+
+static int acpi_video_bus_add (struct acpi_device *device);
+static int acpi_video_bus_remove (struct acpi_device *device, int type);
+static int acpi_video_bus_match (struct acpi_device *device, struct acpi_driver *driver);
+
+static struct acpi_driver acpi_video_bus = {
+ .name = ACPI_VIDEO_DRIVER_NAME,
+ .class = ACPI_VIDEO_CLASS,
+ .ops = {
+ .add = acpi_video_bus_add,
+ .remove = acpi_video_bus_remove,
+ .match = acpi_video_bus_match,
+ },
+};
+
+struct acpi_video_bus_flags {
+ u8 multihead:1; /* can switch video heads */
+ u8 rom:1; /* can retrieve a video rom */
+ u8 post:1; /* can configure the head to */
+ u8 reserved:5;
+};
+
+struct acpi_video_bus_cap {
+ u8 _DOS:1; /*Enable/Disable output switching*/
+ u8 _DOD:1; /*Enumerate all devices attached to display adapter*/
+ u8 _ROM:1; /*Get ROM Data*/
+ u8 _GPD:1; /*Get POST Device*/
+ u8 _SPD:1; /*Set POST Device*/
+ u8 _VPO:1; /*Video POST Options*/
+ u8 reserved:2;
+};
+
+struct acpi_video_device_attrib{
+ u32 display_index:4; /* A zero-based instance of the Display*/
+ u32 display_port_attachment:4; /*This field differenates displays type*/
+ u32 display_type:4; /*Describe the specific type in use*/
+ u32 vendor_specific:4; /*Chipset Vendor Specifi*/
+ u32 bios_can_detect:1; /*BIOS can detect the device*/
+ u32 depend_on_vga:1; /*Non-VGA output device whose power is related to
+ the VGA device.*/
+ u32 pipe_id:3; /*For VGA multiple-head devices.*/
+ u32 reserved:10; /*Must be 0*/
+ u32 device_id_scheme:1; /*Device ID Scheme*/
+};
+
+struct acpi_video_enumerated_device {
+ union {
+ u32 int_val;
+ struct acpi_video_device_attrib attrib;
+ } value;
+ struct acpi_video_device *bind_info;
+};
+
+struct acpi_video_bus {
+ acpi_handle handle;
+ u8 dos_setting;
+ struct acpi_video_enumerated_device *attached_array;
+ u8 attached_count;
+ struct acpi_video_bus_cap cap;
+ struct acpi_video_bus_flags flags;
+ struct semaphore sem;
+ struct list_head video_device_list;
+ struct proc_dir_entry *dir;
+};
+
+struct acpi_video_device_flags {
+ u8 crt:1;
+ u8 lcd:1;
+ u8 tvout:1;
+ u8 bios:1;
+ u8 unknown:1;
+ u8 reserved:3;
+};
+
+struct acpi_video_device_cap {
+ u8 _ADR:1; /*Return the unique ID */
+ u8 _BCL:1; /*Query list of brightness control levels supported*/
+ u8 _BCM:1; /*Set the brightness level*/
+ u8 _DDC:1; /*Return the EDID for this device*/
+ u8 _DCS:1; /*Return status of output device*/
+ u8 _DGS:1; /*Query graphics state*/
+ u8 _DSS:1; /*Device state set*/
+ u8 _reserved:1;
+};
+
+struct acpi_video_device_brightness {
+ int curr;
+ int count;
+ int *levels;
+};
+
+struct acpi_video_device {
+ acpi_handle handle;
+ unsigned long device_id;
+ struct acpi_video_device_flags flags;
+ struct acpi_video_device_cap cap;
+ struct list_head entry;
+ struct acpi_video_bus *video;
+ struct acpi_device *dev;
+ struct acpi_video_device_brightness *brightness;
+};
+
+
+/* bus */
+static int acpi_video_bus_info_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_info_fops = {
+ .open = acpi_video_bus_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int acpi_video_bus_ROM_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_ROM_fops = {
+ .open = acpi_video_bus_ROM_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int acpi_video_bus_POST_info_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_POST_info_fops = {
+ .open = acpi_video_bus_POST_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int acpi_video_bus_POST_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_POST_fops = {
+ .open = acpi_video_bus_POST_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+
+static int acpi_video_bus_DOS_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_bus_DOS_fops = {
+ .open = acpi_video_bus_DOS_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* device */
+static int acpi_video_device_info_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_info_fops = {
+ .open = acpi_video_device_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int acpi_video_device_state_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_state_fops = {
+ .open = acpi_video_device_state_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int acpi_video_device_brightness_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_brightness_fops = {
+ .open = acpi_video_device_brightness_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int acpi_video_device_EDID_open_fs(struct inode *inode, struct file *file);
+static struct file_operations acpi_video_device_EDID_fops = {
+ .open = acpi_video_device_EDID_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static char device_decode[][30] = {
+ "motherboard VGA device",
+ "PCI VGA device",
+ "AGP VGA device",
+ "UNKNOWN",
+};
+
+static void acpi_video_device_notify ( acpi_handle handle, u32 event, void *data);
+static void acpi_video_device_rebind( struct acpi_video_bus *video);
+static void acpi_video_device_bind( struct acpi_video_bus *video, struct acpi_video_device *device);
+static int acpi_video_device_enumerate(struct acpi_video_bus *video);
+static int acpi_video_switch_output( struct acpi_video_bus *video, int event);
+static int acpi_video_get_next_level( struct acpi_video_device *device, u32 level_current,u32 event);
+static void acpi_video_switch_brightness ( struct acpi_video_device *device, int event);
+
+
+/* --------------------------------------------------------------------------
+ Video Management
+ -------------------------------------------------------------------------- */
+
+/* device */
+
+static int
+acpi_video_device_query (
+ struct acpi_video_device *device,
+ unsigned long *state)
+{
+ int status;
+ ACPI_FUNCTION_TRACE("acpi_video_device_query");
+ status = acpi_evaluate_integer(device->handle, "_DGS", NULL, state);
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_device_get_state (
+ struct acpi_video_device *device,
+ unsigned long *state)
+{
+ int status;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_get_state");
+
+ status = acpi_evaluate_integer(device->handle, "_DCS", NULL, state);
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_device_set_state (
+ struct acpi_video_device *device,
+ int state)
+{
+ int status;
+ union acpi_object arg0 = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list args = {1, &arg0};
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_set_state");
+
+ arg0.integer.value = state;
+ status = acpi_evaluate_integer(device->handle, "_DSS", &args, NULL);
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_device_lcd_query_levels (
+ struct acpi_video_device *device,
+ union acpi_object **levels)
+{
+ int status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_lcd_query_levels");
+
+ *levels = NULL;
+
+ status = acpi_evaluate_object(device->handle, "_BCL", NULL, &buffer);
+ if (!ACPI_SUCCESS(status))
+ return_VALUE(status);
+ obj = (union acpi_object *) buffer.pointer;
+ if (!obj && (obj->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _BCL data\n"));
+ status = -EFAULT;
+ goto err;
+ }
+
+ *levels = obj;
+
+ return_VALUE(0);
+
+err:
+ if (buffer.pointer)
+ kfree(buffer.pointer);
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_device_lcd_set_level (
+ struct acpi_video_device *device,
+ int level)
+{
+ int status;
+ union acpi_object arg0 = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list args = {1, &arg0};
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_lcd_set_level");
+
+ arg0.integer.value = level;
+ status = acpi_evaluate_object(device->handle, "_BCM", &args, NULL);
+
+ printk(KERN_DEBUG "set_level status: %x\n", status);
+ return_VALUE(status);
+}
+
+static int
+acpi_video_device_lcd_get_level_current (
+ struct acpi_video_device *device,
+ unsigned long *level)
+{
+ int status;
+ ACPI_FUNCTION_TRACE("acpi_video_device_lcd_get_level_current");
+
+ status = acpi_evaluate_integer(device->handle, "_BQC", NULL, level);
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_device_EDID (
+ struct acpi_video_device *device,
+ union acpi_object **edid,
+ ssize_t length)
+{
+ int status;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+ union acpi_object arg0 = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list args = {1, &arg0};
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_get_EDID");
+
+ *edid = NULL;
+
+ if (!device)
+ return_VALUE(-ENODEV);
+ if (length == 128)
+ arg0.integer.value = 1;
+ else if (length == 256)
+ arg0.integer.value = 2;
+ else
+ return_VALUE(-EINVAL);
+
+ status = acpi_evaluate_object(device->handle, "_DDC", &args, &buffer);
+ if (ACPI_FAILURE(status))
+ return_VALUE(-ENODEV);
+
+ obj = (union acpi_object *) buffer.pointer;
+
+ if (obj && obj->type == ACPI_TYPE_BUFFER)
+ *edid = obj;
+ else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DDC data\n"));
+ status = -EFAULT;
+ kfree(obj);
+ }
+
+ return_VALUE(status);
+}
+
+
+/* bus */
+
+static int
+acpi_video_bus_set_POST (
+ struct acpi_video_bus *video,
+ unsigned long option)
+{
+ int status;
+ unsigned long tmp;
+ union acpi_object arg0 = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list args = {1, &arg0};
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_set_POST");
+
+ arg0.integer.value = option;
+
+ status = acpi_evaluate_integer(video->handle, "_SPD", &args, &tmp);
+ if (ACPI_SUCCESS(status))
+ status = tmp ? (-EINVAL):(AE_OK);
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_bus_get_POST (
+ struct acpi_video_bus *video,
+ unsigned long *id)
+{
+ int status;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_get_POST");
+
+ status = acpi_evaluate_integer(video->handle, "_GPD", NULL, id);
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_bus_POST_options (
+ struct acpi_video_bus *video,
+ unsigned long *options)
+{
+ int status;
+ ACPI_FUNCTION_TRACE("acpi_video_bus_POST_options");
+
+ status = acpi_evaluate_integer(video->handle, "_VPO", NULL, options);
+ *options &= 3;
+
+ return_VALUE(status);
+}
+
+/*
+ * Arg:
+ * video : video bus device pointer
+ * bios_flag :
+ * 0. The system BIOS should NOT automatically switch(toggle)
+ * the active display output.
+ * 1. The system BIOS should automatically switch (toggle) the
+ * active display output. No swich event.
+ * 2. The _DGS value should be locked.
+ * 3. The system BIOS should not automatically switch (toggle) the
+ * active display output, but instead generate the display switch
+ * event notify code.
+ * lcd_flag :
+ * 0. The system BIOS should automatically control the brightness level
+ * of the LCD, when the power changes from AC to DC
+ * 1. The system BIOS should NOT automatically control the brightness
+ * level of the LCD, when the power changes from AC to DC.
+ * Return Value:
+ * -1 wrong arg.
+ */
+
+static int
+acpi_video_bus_DOS(
+ struct acpi_video_bus *video,
+ int bios_flag,
+ int lcd_flag)
+{
+ acpi_integer status = 0;
+ union acpi_object arg0 = {ACPI_TYPE_INTEGER};
+ struct acpi_object_list args = {1, &arg0};
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_DOS");
+
+ if (bios_flag < 0 || bios_flag >3 || lcd_flag < 0 || lcd_flag > 1){
+ status = -1;
+ goto Failed;
+ }
+ arg0.integer.value = (lcd_flag << 2) | bios_flag;
+ video->dos_setting = arg0.integer.value;
+ acpi_evaluate_object(video->handle, "_DOS", &args, NULL);
+
+Failed:
+ return_VALUE(status);
+}
+
+/*
+ * Arg:
+ * device : video output device (LCD, CRT, ..)
+ *
+ * Return Value:
+ * None
+ *
+ * Find out all required AML method defined under the output
+ * device.
+ */
+
+static void
+acpi_video_device_find_cap (struct acpi_video_device *device)
+{
+ acpi_integer status;
+ acpi_handle h_dummy1;
+ int i;
+ union acpi_object *obj = NULL;
+ struct acpi_video_device_brightness *br = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_find_cap");
+
+ memset( &device->cap, 0, 4);
+
+ if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_ADR", &h_dummy1))) {
+ device->cap._ADR = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCL", &h_dummy1))) {
+ device->cap._BCL= 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_BCM", &h_dummy1))) {
+ device->cap._BCM= 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DDC", &h_dummy1))) {
+ device->cap._DDC= 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DCS", &h_dummy1))) {
+ device->cap._DCS = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DGS", &h_dummy1))) {
+ device->cap._DGS = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(device->handle, "_DSS", &h_dummy1))) {
+ device->cap._DSS = 1;
+ }
+
+ status = acpi_video_device_lcd_query_levels(device, &obj);
+
+ if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
+ int count = 0;
+ union acpi_object *o;
+
+ br = kmalloc(sizeof &br, GFP_KERNEL);
+ if (!br) {
+ printk(KERN_ERR "can't allocate memory\n");
+ } else {
+ memset(br, 0, sizeof &br);
+ br->levels = kmalloc(obj->package.count * sizeof &br->levels, GFP_KERNEL);
+ if (!br->levels)
+ goto out;
+
+ for (i = 0; i < obj->package.count; i++) {
+ o = (union acpi_object *) &obj->package.elements[i];
+ if (o->type != ACPI_TYPE_INTEGER) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
+ continue;
+ }
+ br->levels[count] = (u32) o->integer.value;
+ count++;
+ }
+out:
+ if (count < 2) {
+ if (br->levels)
+ kfree(br->levels);
+ kfree(br);
+ } else {
+ br->count = count;
+ device->brightness = br;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "found %d brightness levels\n", count));
+ }
+ }
+ }
+
+ if (obj)
+ kfree(obj);
+
+ return_VOID;
+}
+
+/*
+ * Arg:
+ * device : video output device (VGA)
+ *
+ * Return Value:
+ * None
+ *
+ * Find out all required AML method defined under the video bus device.
+ */
+
+static void
+acpi_video_bus_find_cap (struct acpi_video_bus *video)
+{
+ acpi_handle h_dummy1;
+
+ memset(&video->cap ,0, 4);
+ if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOS", &h_dummy1))) {
+ video->cap._DOS = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_DOD", &h_dummy1))) {
+ video->cap._DOD = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_ROM", &h_dummy1))) {
+ video->cap._ROM = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_GPD", &h_dummy1))) {
+ video->cap._GPD = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_SPD", &h_dummy1))) {
+ video->cap._SPD = 1;
+ }
+ if( ACPI_SUCCESS(acpi_get_handle(video->handle, "_VPO", &h_dummy1))) {
+ video->cap._VPO = 1;
+ }
+}
+
+/*
+ * Check whether the video bus device has required AML method to
+ * support the desired features
+ */
+
+static int
+acpi_video_bus_check (
+ struct acpi_video_bus *video)
+{
+ acpi_status status = -ENOENT;
+
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_check");
+
+ if (!video)
+ return_VALUE(-EINVAL);
+
+ /* Since there is no HID, CID and so on for VGA driver, we have
+ * to check well known required nodes.
+ */
+
+ /* Does this device able to support video switching ? */
+ if(video->cap._DOS){
+ video->flags.multihead = 1;
+ status = 0;
+ }
+
+ /* Does this device able to retrieve a retrieve a video ROM ? */
+ if(video->cap._ROM){
+ video->flags.rom = 1;
+ status = 0;
+ }
+
+ /* Does this device able to configure which video device to POST ? */
+ if(video->cap._GPD && video->cap._SPD && video->cap._VPO){
+ video->flags.post = 1;
+ status = 0;
+ }
+
+ return_VALUE(status);
+}
+
+/* --------------------------------------------------------------------------
+ FS Interface (/proc)
+ -------------------------------------------------------------------------- */
+
+static struct proc_dir_entry *acpi_video_dir;
+
+/* video devices */
+
+static int
+acpi_video_device_info_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_device *dev = (struct acpi_video_device *) seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_info_seq_show");
+
+ if (!dev)
+ goto end;
+
+ seq_printf(seq, "device_id: 0x%04x\n", (u32) dev->device_id);
+ seq_printf(seq, "type: ");
+ if (dev->flags.crt)
+ seq_printf(seq, "CRT\n");
+ else if (dev->flags.lcd)
+ seq_printf(seq, "LCD\n");
+ else if (dev->flags.tvout)
+ seq_printf(seq, "TVOUT\n");
+ else
+ seq_printf(seq, "UNKNOWN\n");
+
+ seq_printf(seq,"known by bios: %s\n",
+ dev->flags.bios ? "yes":"no");
+
+end:
+ return_VALUE(0);
+}
+
+static int
+acpi_video_device_info_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_device_info_seq_show,
+ PDE(inode)->data);
+}
+
+static int
+acpi_video_device_state_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ int status;
+ struct acpi_video_device *dev = (struct acpi_video_device *) seq->private;
+ unsigned long state;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_state_seq_show");
+
+ if (!dev)
+ goto end;
+
+ status = acpi_video_device_get_state(dev, &state);
+ seq_printf(seq, "state: ");
+ if (ACPI_SUCCESS(status))
+ seq_printf(seq, "0x%02lx\n", state);
+ else
+ seq_printf(seq, "<not supported>\n");
+
+ status = acpi_video_device_query(dev, &state);
+ seq_printf(seq, "query: ");
+ if (ACPI_SUCCESS(status))
+ seq_printf(seq, "0x%02lx\n", state);
+ else
+ seq_printf(seq, "<not supported>\n");
+
+end:
+ return_VALUE(0);
+}
+
+static int
+acpi_video_device_state_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_device_state_seq_show,
+ PDE(inode)->data);
+}
+
+static ssize_t
+acpi_video_device_write_state (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *data)
+{
+ int status;
+ struct seq_file *m = (struct seq_file *) file->private_data;
+ struct acpi_video_device *dev = (struct acpi_video_device *) m->private;
+ char str[12] = {0};
+ u32 state = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_write_state");
+
+ if (!dev || count + 1 > sizeof str)
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(str, buffer, count))
+ return_VALUE(-EFAULT);
+
+ str[count] = 0;
+ state = simple_strtoul(str, NULL, 0);
+ state &= ((1ul<<31) | (1ul<<30) | (1ul<<0));
+
+ status = acpi_video_device_set_state(dev, state);
+
+ if (status)
+ return_VALUE(-EFAULT);
+
+ return_VALUE(count);
+}
+
+static int
+acpi_video_device_brightness_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_device *dev = (struct acpi_video_device *) seq->private;
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_brightness_seq_show");
+
+ if (!dev || !dev->brightness) {
+ seq_printf(seq, "<not supported>\n");
+ return_VALUE(0);
+ }
+
+ seq_printf(seq, "levels: ");
+ for (i = 0; i < dev->brightness->count; i++)
+ seq_printf(seq, " %d", dev->brightness->levels[i]);
+ seq_printf(seq, "\ncurrent: %d\n", dev->brightness->curr);
+
+ return_VALUE(0);
+}
+
+static int
+acpi_video_device_brightness_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_device_brightness_seq_show,
+ PDE(inode)->data);
+}
+
+static ssize_t
+acpi_video_device_write_brightness (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *data)
+{
+ struct seq_file *m = (struct seq_file *) file->private_data;
+ struct acpi_video_device *dev = (struct acpi_video_device *) m->private;
+ char str[4] = {0};
+ unsigned int level = 0;
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_write_brightness");
+
+ if (!dev || count + 1 > sizeof str)
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(str, buffer, count))
+ return_VALUE(-EFAULT);
+
+ str[count] = 0;
+ level = simple_strtoul(str, NULL, 0);
+
+ if (level > 100)
+ return_VALUE(-EFAULT);
+
+ /* validate though the list of available levels */
+ for (i = 0; i < dev->brightness->count; i++)
+ if (level == dev->brightness->levels[i]) {
+ if (ACPI_SUCCESS(acpi_video_device_lcd_set_level(dev, level)))
+ dev->brightness->curr = level;
+ break;
+ }
+
+ return_VALUE(count);
+}
+
+static int
+acpi_video_device_EDID_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_device *dev = (struct acpi_video_device *) seq->private;
+ int status;
+ int i;
+ union acpi_object *edid = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_EDID_seq_show");
+
+ if (!dev)
+ goto out;
+
+ status = acpi_video_device_EDID (dev, &edid, 128);
+ if (ACPI_FAILURE(status)) {
+ status = acpi_video_device_EDID (dev, &edid, 256);
+ }
+
+ if (ACPI_FAILURE(status)) {
+ goto out;
+ }
+
+ if (edid && edid->type == ACPI_TYPE_BUFFER) {
+ for (i = 0; i < edid->buffer.length; i++)
+ seq_putc(seq, edid->buffer.pointer[i]);
+ }
+
+out:
+ if (!edid)
+ seq_printf(seq, "<not supported>\n");
+ else
+ kfree(edid);
+
+ return_VALUE(0);
+}
+
+static int
+acpi_video_device_EDID_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_device_EDID_seq_show,
+ PDE(inode)->data);
+}
+
+
+static int
+acpi_video_device_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+ struct acpi_video_device *vid_dev;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_add_fs");
+
+ if (!device)
+ return_VALUE(-ENODEV);
+
+ vid_dev = (struct acpi_video_device *) acpi_driver_data(device);
+ if (!vid_dev)
+ return_VALUE(-ENODEV);
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ vid_dev->video->dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ acpi_device_dir(device)->owner = THIS_MODULE;
+ }
+
+ /* 'info' [R] */
+ entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create 'info' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_device_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'state' [R/W] */
+ entry = create_proc_entry("state", S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create 'state' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_device_state_fops;
+ entry->proc_fops->write = acpi_video_device_write_state;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'brightness' [R/W] */
+ entry = create_proc_entry("brightness", S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create 'brightness' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_device_brightness_fops;
+ entry->proc_fops->write = acpi_video_device_write_brightness;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'EDID' [R] */
+ entry = create_proc_entry("EDID", S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Unable to create 'brightness' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_device_EDID_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+static int
+acpi_video_device_remove_fs (
+ struct acpi_device *device)
+{
+ struct acpi_video_device *vid_dev;
+ ACPI_FUNCTION_TRACE("acpi_video_device_remove_fs");
+
+ vid_dev = (struct acpi_video_device *) acpi_driver_data(device);
+ if (!vid_dev || !vid_dev->video || !vid_dev->video->dir)
+ return_VALUE(-ENODEV);
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry("info", acpi_device_dir(device));
+ remove_proc_entry("state", acpi_device_dir(device));
+ remove_proc_entry("brightness", acpi_device_dir(device));
+ remove_proc_entry("EDID", acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device),
+ vid_dev->video->dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+
+/* video bus */
+static int
+acpi_video_bus_info_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_bus *video = (struct acpi_video_bus *) seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_info_seq_show");
+
+ if (!video)
+ goto end;
+
+ seq_printf(seq, "Switching heads: %s\n",
+ video->flags.multihead ? "yes":"no");
+ seq_printf(seq, "Video ROM: %s\n",
+ video->flags.rom ? "yes":"no");
+ seq_printf(seq, "Device to be POSTed on boot: %s\n",
+ video->flags.post ? "yes":"no");
+
+end:
+ return_VALUE(0);
+}
+
+static int
+acpi_video_bus_info_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_bus_info_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_ROM_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_bus *video = (struct acpi_video_bus *) seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_ROM_seq_show");
+
+ if (!video)
+ goto end;
+
+ printk(KERN_INFO PREFIX "Please implement %s\n", __FUNCTION__);
+ seq_printf(seq, "<TODO>\n");
+
+end:
+ return_VALUE(0);
+}
+
+static int
+acpi_video_bus_ROM_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_bus_ROM_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_POST_info_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_bus *video = (struct acpi_video_bus *) seq->private;
+ unsigned long options;
+ int status;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_POST_info_seq_show");
+
+ if (!video)
+ goto end;
+
+ status = acpi_video_bus_POST_options(video, &options);
+ if (ACPI_SUCCESS(status)) {
+ if (!(options & 1)) {
+ printk(KERN_WARNING PREFIX "The motherboard VGA device is not listed as a possible POST device.\n");
+ printk(KERN_WARNING PREFIX "This indicate a BIOS bug. Please contact the manufacturer.\n");
+ }
+ printk("%lx\n", options);
+ seq_printf(seq, "can POST: <intgrated video>");
+ if (options & 2)
+ seq_printf(seq, " <PCI video>");
+ if (options & 4)
+ seq_printf(seq, " <AGP video>");
+ seq_putc(seq, '\n');
+ } else
+ seq_printf(seq, "<not supported>\n");
+end:
+ return_VALUE(0);
+}
+
+static int
+acpi_video_bus_POST_info_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_bus_POST_info_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_POST_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_bus *video = (struct acpi_video_bus *) seq->private;
+ int status;
+ unsigned long id;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_POST_seq_show");
+
+ if (!video)
+ goto end;
+
+ status = acpi_video_bus_get_POST (video, &id);
+ if (!ACPI_SUCCESS(status)) {
+ seq_printf(seq, "<not supported>\n");
+ goto end;
+ }
+ seq_printf(seq, "device posted is <%s>\n", device_decode[id & 3]);
+
+end:
+ return_VALUE(0);
+}
+
+static int
+acpi_video_bus_DOS_seq_show (
+ struct seq_file *seq,
+ void *offset)
+{
+ struct acpi_video_bus *video = (struct acpi_video_bus *) seq->private;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_DOS_seq_show");
+
+ seq_printf(seq, "DOS setting: <%d>\n", video->dos_setting );
+
+ return_VALUE(0);
+}
+
+static int
+acpi_video_bus_POST_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_bus_POST_seq_show, PDE(inode)->data);
+}
+
+static int
+acpi_video_bus_DOS_open_fs (
+ struct inode *inode,
+ struct file *file)
+{
+ return single_open(file, acpi_video_bus_DOS_seq_show, PDE(inode)->data);
+}
+
+static ssize_t
+acpi_video_bus_write_POST (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *data)
+{
+ int status;
+ struct seq_file *m = (struct seq_file *) file->private_data;
+ struct acpi_video_bus *video = (struct acpi_video_bus *) m->private;
+ char str[12] = {0};
+ unsigned long opt, options;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_write_POST");
+
+
+ if (!video || count + 1 > sizeof str)
+ return_VALUE(-EINVAL);
+
+ status = acpi_video_bus_POST_options(video, &options);
+ if (!ACPI_SUCCESS(status))
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(str, buffer, count))
+ return_VALUE(-EFAULT);
+
+ str[count] = 0;
+ opt = strtoul(str, NULL, 0);
+ if (opt > 3)
+ return_VALUE(-EFAULT);
+
+ /* just in case an OEM 'forget' the motherboard... */
+ options |= 1;
+
+ if (options & (1ul << opt)) {
+ status = acpi_video_bus_set_POST (video, opt);
+ if (!ACPI_SUCCESS(status))
+ return_VALUE(-EFAULT);
+
+ }
+
+
+ return_VALUE(count);
+}
+
+static ssize_t
+acpi_video_bus_write_DOS (
+ struct file *file,
+ const char __user *buffer,
+ size_t count,
+ loff_t *data)
+{
+ int status;
+ struct seq_file *m = (struct seq_file *) file->private_data;
+ struct acpi_video_bus *video = (struct acpi_video_bus *) m->private;
+ char str[12] = {0};
+ unsigned long opt;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_write_DOS");
+
+
+ if (!video || count + 1 > sizeof str)
+ return_VALUE(-EINVAL);
+
+ if (copy_from_user(str, buffer, count))
+ return_VALUE(-EFAULT);
+
+ str[count] = 0;
+ opt = strtoul(str, NULL, 0);
+ if (opt > 7)
+ return_VALUE(-EFAULT);
+
+ status = acpi_video_bus_DOS (video, opt & 0x3, (opt & 0x4)>>2);
+
+ if (!ACPI_SUCCESS(status))
+ return_VALUE(-EFAULT);
+
+ return_VALUE(count);
+}
+
+static int
+acpi_video_bus_add_fs (
+ struct acpi_device *device)
+{
+ struct proc_dir_entry *entry = NULL;
+ struct acpi_video_bus *video;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_add_fs");
+
+ video = (struct acpi_video_bus *) acpi_driver_data(device);
+
+ if (!acpi_device_dir(device)) {
+ acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
+ acpi_video_dir);
+ if (!acpi_device_dir(device))
+ return_VALUE(-ENODEV);
+ video->dir = acpi_device_dir(device);
+ acpi_device_dir(device)->owner = THIS_MODULE;
+ }
+
+ /* 'info' [R] */
+ entry = create_proc_entry("info", S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'info' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_bus_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'ROM' [R] */
+ entry = create_proc_entry("ROM", S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'ROM' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_bus_ROM_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'POST_info' [R] */
+ entry = create_proc_entry("POST_info", S_IRUGO, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'POST_info' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_bus_POST_info_fops;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'POST' [R/W] */
+ entry = create_proc_entry("POST", S_IFREG|S_IRUGO|S_IRUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'POST' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_bus_POST_fops;
+ entry->proc_fops->write = acpi_video_bus_write_POST;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ /* 'DOS' [R/W] */
+ entry = create_proc_entry("DOS", S_IFREG|S_IRUGO|S_IRUSR, acpi_device_dir(device));
+ if (!entry)
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to create 'DOS' fs entry\n"));
+ else {
+ entry->proc_fops = &acpi_video_bus_DOS_fops;
+ entry->proc_fops->write = acpi_video_bus_write_DOS;
+ entry->data = acpi_driver_data(device);
+ entry->owner = THIS_MODULE;
+ }
+
+ return_VALUE(0);
+}
+
+static int
+acpi_video_bus_remove_fs (
+ struct acpi_device *device)
+{
+ struct acpi_video_bus *video;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_remove_fs");
+
+ video = (struct acpi_video_bus *) acpi_driver_data(device);
+
+ if (acpi_device_dir(device)) {
+ remove_proc_entry("info", acpi_device_dir(device));
+ remove_proc_entry("ROM", acpi_device_dir(device));
+ remove_proc_entry("POST_info", acpi_device_dir(device));
+ remove_proc_entry("POST", acpi_device_dir(device));
+ remove_proc_entry("DOS", acpi_device_dir(device));
+ remove_proc_entry(acpi_device_bid(device),
+ acpi_video_dir);
+ acpi_device_dir(device) = NULL;
+ }
+
+ return_VALUE(0);
+}
+
+/* --------------------------------------------------------------------------
+ Driver Interface
+ -------------------------------------------------------------------------- */
+
+/* device interface */
+
+static int
+acpi_video_bus_get_one_device (
+ struct acpi_device *device,
+ struct acpi_video_bus *video)
+{
+ unsigned long device_id;
+ int status, result;
+ struct acpi_video_device *data;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_get_one_device");
+
+ if (!device || !video)
+ return_VALUE(-EINVAL);
+
+ status = acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+ if (ACPI_SUCCESS(status)) {
+
+ data = kmalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
+ if (!data)
+ return_VALUE(-ENOMEM);
+
+ memset(data, 0, sizeof(struct acpi_video_device));
+
+ data->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
+ strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+ acpi_driver_data(device) = data;
+
+ data->device_id = device_id;
+ data->video = video;
+ data->dev = device;
+
+ switch (device_id & 0xffff) {
+ case 0x0100:
+ data->flags.crt = 1;
+ break;
+ case 0x0400:
+ data->flags.lcd = 1;
+ break;
+ case 0x0200:
+ data->flags.tvout = 1;
+ break;
+ default:
+ data->flags.unknown = 1;
+ break;
+ }
+
+ acpi_video_device_bind(video, data);
+ acpi_video_device_find_cap(data);
+
+ status = acpi_install_notify_handler(data->handle,
+ ACPI_DEVICE_NOTIFY, acpi_video_device_notify, data);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ down(&video->sem);
+ list_add_tail(&data->entry, &video->video_device_list);
+ up(&video->sem);
+
+ acpi_video_device_add_fs(device);
+
+ return_VALUE(0);
+ }
+
+end:
+ return_VALUE(-ENOENT);
+}
+
+/*
+ * Arg:
+ * video : video bus device
+ *
+ * Return:
+ * none
+ *
+ * Enumerate the video device list of the video bus,
+ * bind the ids with the corresponding video devices
+ * under the video bus.
+ */
+
+static void
+acpi_video_device_rebind( struct acpi_video_bus *video)
+{
+ struct list_head * node, * next;
+ list_for_each_safe(node, next, &video->video_device_list) {
+ struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry);
+ acpi_video_device_bind( video, dev);
+ }
+}
+
+/*
+ * Arg:
+ * video : video bus device
+ * device : video output device under the video
+ * bus
+ *
+ * Return:
+ * none
+ *
+ * Bind the ids with the corresponding video devices
+ * under the video bus.
+ */
+
+static void
+acpi_video_device_bind( struct acpi_video_bus *video,
+ struct acpi_video_device *device)
+{
+ int i;
+ ACPI_FUNCTION_TRACE("acpi_video_device_bind");
+
+#define IDS_VAL(i) video->attached_array[i].value.int_val
+#define IDS_BIND(i) video->attached_array[i].bind_info
+
+ for (i = 0; IDS_VAL(i) != ACPI_VIDEO_HEAD_INVALID &&
+ i < video->attached_count; i++) {
+ if (device->device_id == (IDS_VAL(i)& 0xffff)) {
+ IDS_BIND(i) = device;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
+ }
+ }
+#undef IDS_VAL
+#undef IDS_BIND
+}
+
+/*
+ * Arg:
+ * video : video bus device
+ *
+ * Return:
+ * < 0 : error
+ *
+ * Call _DOD to enumerate all devices attached to display adapter
+ *
+ */
+
+static int acpi_video_device_enumerate(struct acpi_video_bus *video)
+{
+ int status;
+ int count;
+ int i;
+ struct acpi_video_enumerated_device *active_device_list;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *dod = NULL;
+ union acpi_object *obj;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_enumerate");
+
+ status = acpi_evaluate_object(video->handle, "_DOD", NULL, &buffer);
+ if (!ACPI_SUCCESS(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _DOD\n"));
+ return_VALUE(status);
+ }
+
+ dod = (union acpi_object *) buffer.pointer;
+ if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
+ status = -EFAULT;
+ goto out;
+ }
+
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
+ dod->package.count));
+
+ active_device_list= kmalloc(
+ (1+dod->package.count)*sizeof(struct acpi_video_enumerated_device),
+ GFP_KERNEL);
+
+ if (!active_device_list) {
+ status = -ENOMEM;
+ goto out;
+ }
+
+ count = 0;
+ for (i = 0; i < dod->package.count; i++) {
+ obj = (union acpi_object *) &dod->package.elements[i];
+
+ if (obj->type != ACPI_TYPE_INTEGER) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _DOD data\n"));
+ active_device_list[i].value.int_val = ACPI_VIDEO_HEAD_INVALID;
+ }
+ active_device_list[i].value.int_val = obj->integer.value;
+ active_device_list[i].bind_info = NULL;
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i, (int) obj->integer.value));
+ count++;
+ }
+ active_device_list[count].value.int_val = ACPI_VIDEO_HEAD_END;
+
+ if(video->attached_array)
+ kfree(video->attached_array);
+
+ video->attached_array = active_device_list;
+ video->attached_count = count;
+out:
+ acpi_os_free(buffer.pointer);
+ return_VALUE(status);
+}
+
+/*
+ * Arg:
+ * video : video bus device
+ * event : Nontify Event
+ *
+ * Return:
+ * < 0 : error
+ *
+ * 1. Find out the current active output device.
+ * 2. Identify the next output device to switch
+ * 3. call _DSS to do actual switch.
+ */
+
+static int
+acpi_video_switch_output(
+ struct acpi_video_bus *video,
+ int event)
+{
+ struct list_head * node, * next;
+ struct acpi_video_device *dev=NULL;
+ struct acpi_video_device *dev_next=NULL;
+ struct acpi_video_device *dev_prev=NULL;
+ unsigned long state;
+ int status = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_video_switch_output");
+
+ list_for_each_safe(node, next, &video->video_device_list) {
+ struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry);
+ status = acpi_video_device_get_state(dev, &state);
+ if (state & 0x2){
+ dev_next = container_of(node->next, struct acpi_video_device, entry);
+ dev_prev = container_of(node->prev, struct acpi_video_device, entry);
+ goto out;
+ }
+ }
+ dev_next = container_of(node->next, struct acpi_video_device, entry);
+ dev_prev = container_of(node->prev, struct acpi_video_device, entry);
+out:
+ switch (event) {
+ case ACPI_VIDEO_NOTIFY_CYCLE:
+ case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
+ acpi_video_device_set_state(dev, 0);
+ acpi_video_device_set_state(dev_next, 0x80000001);
+ break;
+ case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
+ acpi_video_device_set_state(dev, 0);
+ acpi_video_device_set_state(dev_prev, 0x80000001);
+ default:
+ break;
+ }
+
+ return_VALUE(status);
+}
+
+static int
+acpi_video_get_next_level(
+ struct acpi_video_device *device,
+ u32 level_current,
+ u32 event)
+{
+ /*Fix me*/
+ return level_current;
+}
+
+
+static void
+acpi_video_switch_brightness (
+ struct acpi_video_device *device,
+ int event)
+{
+ unsigned long level_current, level_next;
+ acpi_video_device_lcd_get_level_current(device, &level_current);
+ level_next = acpi_video_get_next_level(device, level_current, event);
+ acpi_video_device_lcd_set_level(device, level_next);
+}
+
+static int
+acpi_video_bus_get_devices (
+ struct acpi_video_bus *video,
+ struct acpi_device *device)
+{
+ int status = 0;
+ struct list_head *node, *next;
+
+ ACPI_FUNCTION_TRACE("acpi_video_get_devices");
+
+ acpi_video_device_enumerate(video);
+
+ list_for_each_safe(node, next, &device->children) {
+ struct acpi_device *dev = list_entry(node, struct acpi_device, node);
+
+ if (!dev)
+ continue;
+
+ status = acpi_video_bus_get_one_device(dev, video);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Cant attach device\n"));
+ continue;
+ }
+
+ }
+ return_VALUE(status);
+}
+
+static int
+acpi_video_bus_put_one_device(
+ struct acpi_video_device *device)
+{
+ struct acpi_video_bus *video;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_put_one_device");
+
+ if (!device || !device->video)
+ return_VALUE(-ENOENT);
+
+ video = device->video;
+
+ down(&video->sem);
+ list_del(&device->entry);
+ up(&video->sem);
+ acpi_video_device_remove_fs(device->dev);
+
+ return_VALUE(0);
+}
+
+static int
+acpi_video_bus_put_devices (
+ struct acpi_video_bus *video)
+{
+ int status;
+ struct list_head *node, *next;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_put_devices");
+
+ list_for_each_safe(node, next, &video->video_device_list) {
+ struct acpi_video_device *data = list_entry(node, struct acpi_video_device, entry);
+ if (!data)
+ continue;
+
+ status = acpi_video_bus_put_one_device(data);
+ if(ACPI_FAILURE(status))
+ printk(KERN_WARNING PREFIX "hhuuhhuu bug in acpi video driver.\n");
+
+ if (data->brightness)
+ kfree(data->brightness);
+
+ kfree(data);
+ }
+
+ return_VALUE(0);
+}
+
+/* acpi_video interface */
+
+static int
+acpi_video_bus_start_devices(
+ struct acpi_video_bus *video)
+{
+ return acpi_video_bus_DOS(video, 1, 0);
+}
+
+static int
+acpi_video_bus_stop_devices(
+ struct acpi_video_bus *video)
+{
+ return acpi_video_bus_DOS(video, 0, 1);
+}
+
+static void
+acpi_video_bus_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_video_bus *video = (struct acpi_video_bus *) data;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_notify");
+ printk("video bus notify\n");
+
+ if (!video)
+ return_VOID;
+
+ if (acpi_bus_get_device(handle, &device))
+ return_VOID;
+
+ switch (event) {
+ case ACPI_VIDEO_NOTIFY_SWITCH: /* User request that a switch occur,
+ * most likely via hotkey. */
+ acpi_bus_generate_event(device, event, 0);
+ break;
+
+ case ACPI_VIDEO_NOTIFY_PROBE: /* User plug or remove a video
+ * connector. */
+ acpi_video_device_enumerate(video);
+ acpi_video_device_rebind(video);
+ acpi_video_switch_output(video, event);
+ acpi_bus_generate_event(device, event, 0);
+ break;
+
+ case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed.*/
+ case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
+ case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
+ acpi_video_switch_output(video, event);
+ acpi_bus_generate_event(device, event, 0);
+ break;
+
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+
+ return_VOID;
+}
+
+static void
+acpi_video_device_notify (
+ acpi_handle handle,
+ u32 event,
+ void *data)
+{
+ struct acpi_video_device *video_device = (struct acpi_video_device *) data;
+ struct acpi_device *device = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_video_device_notify");
+
+ printk("video device notify\n");
+ if (!video_device)
+ return_VOID;
+
+ if (acpi_bus_get_device(handle, &device))
+ return_VOID;
+
+ switch (event) {
+ case ACPI_VIDEO_NOTIFY_SWITCH: /* change in status (cycle output device) */
+ case ACPI_VIDEO_NOTIFY_PROBE: /* change in status (output device status) */
+ acpi_bus_generate_event(device, event, 0);
+ break;
+ case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
+ case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
+ case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
+ case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
+ case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
+ acpi_video_switch_brightness (video_device, event);
+ acpi_bus_generate_event(device, event, 0);
+ break;
+ default:
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Unsupported event [0x%x]\n", event));
+ break;
+ }
+ return_VOID;
+}
+
+static int
+acpi_video_bus_add (
+ struct acpi_device *device)
+{
+ int result = 0;
+ acpi_status status = 0;
+ struct acpi_video_bus *video = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_add");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ video = kmalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
+ if (!video)
+ return_VALUE(-ENOMEM);
+ memset(video, 0, sizeof(struct acpi_video_bus));
+
+ video->handle = device->handle;
+ strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
+ strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+ acpi_driver_data(device) = video;
+
+ acpi_video_bus_find_cap(video);
+ result = acpi_video_bus_check(video);
+ if (result)
+ goto end;
+
+ result = acpi_video_bus_add_fs(device);
+ if (result)
+ goto end;
+
+ init_MUTEX(&video->sem);
+ INIT_LIST_HEAD(&video->video_device_list);
+
+ acpi_video_bus_get_devices(video, device);
+ acpi_video_bus_start_devices(video);
+
+ status = acpi_install_notify_handler(video->handle,
+ ACPI_DEVICE_NOTIFY, acpi_video_bus_notify, video);
+ if (ACPI_FAILURE(status)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error installing notify handler\n"));
+ result = -ENODEV;
+ goto end;
+ }
+
+ printk(KERN_INFO PREFIX "%s [%s] (multi-head: %s rom: %s post: %s)\n",
+ ACPI_VIDEO_DEVICE_NAME, acpi_device_bid(device),
+ video->flags.multihead ? "yes":"no",
+ video->flags.rom ? "yes":"no",
+ video->flags.post ? "yes":"no");
+
+end:
+ if (result) {
+ acpi_video_bus_remove_fs(device);
+ kfree(video);
+ }
+
+ return_VALUE(result);
+}
+
+static int
+acpi_video_bus_remove (
+ struct acpi_device *device,
+ int type)
+{
+ acpi_status status = 0;
+ struct acpi_video_bus *video = NULL;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_remove");
+
+ if (!device || !acpi_driver_data(device))
+ return_VALUE(-EINVAL);
+
+ video = (struct acpi_video_bus *) acpi_driver_data(device);
+
+ acpi_video_bus_stop_devices(video);
+
+ status = acpi_remove_notify_handler(video->handle,
+ ACPI_DEVICE_NOTIFY, acpi_video_bus_notify);
+ if (ACPI_FAILURE(status))
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Error removing notify handler\n"));
+
+ acpi_video_bus_put_devices(video);
+ acpi_video_bus_remove_fs(device);
+
+ if (video->attached_array)
+ kfree(video->attached_array);
+ kfree(video);
+
+ return_VALUE(0);
+}
+
+
+static int
+acpi_video_bus_match (
+ struct acpi_device *device,
+ struct acpi_driver *driver)
+{
+ acpi_handle h_dummy1;
+ acpi_handle h_dummy2;
+ acpi_handle h_dummy3;
+
+ ACPI_FUNCTION_TRACE("acpi_video_bus_match");
+
+ if (!device || !driver)
+ return_VALUE(-EINVAL);
+
+ /* Since there is no HID, CID for ACPI Video drivers, we have
+ * to check well known required nodes for each feature we support.
+ */
+
+ /* Does this device able to support video switching ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+ return_VALUE(0);
+
+ /* Does this device able to retrieve a video ROM ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+ return_VALUE(0);
+
+ /* Does this device able to configure which video head to be POSTed ? */
+ if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
+ ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+ return_VALUE(0);
+
+
+ return_VALUE(-ENODEV);
+}
+
+
+static int __init
+acpi_video_init (void)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_video_init");
+
+ /*
+ acpi_dbg_level = 0xFFFFFFFF;
+ acpi_dbg_layer = 0x08000000;
+ */
+
+ acpi_video_dir = proc_mkdir(ACPI_VIDEO_CLASS, acpi_root_dir);
+ if (!acpi_video_dir)
+ return_VALUE(-ENODEV);
+ acpi_video_dir->owner = THIS_MODULE;
+
+ result = acpi_bus_register_driver(&acpi_video_bus);
+ if (result < 0) {
+ remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+ return_VALUE(-ENODEV);
+ }
+
+ return_VALUE(0);
+}
+
+static void __exit
+acpi_video_exit (void)
+{
+ ACPI_FUNCTION_TRACE("acpi_video_exit");
+
+ acpi_bus_unregister_driver(&acpi_video_bus);
+
+ remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir);
+
+ return_VOID;
+}
+
+module_init(acpi_video_init);
+module_exit(acpi_video_exit);