Merge branch 'acpi-cca'
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 18 Jun 2015 23:17:35 +0000 (01:17 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 18 Jun 2015 23:17:35 +0000 (01:17 +0200)
* acpi-cca:
  ufs: fix TRUE and FALSE re-define build error
  megaraid_sas: fix TRUE and FALSE re-define build error
  amd-xgbe: Unify coherency checking logic with device_dma_is_coherent()
  crypto: ccp - Unify coherency checking logic with device_dma_is_coherent()
  device property: Introduces device_dma_is_coherent()
  arm64 : Introduce support for ACPI _CCA object
  ACPI / scan: Parse _CCA and setup device coherency

76 files changed:
Documentation/acpi/enumeration.txt
Documentation/kernel-parameters.txt
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/ac.c
drivers/acpi/acpi_lpss.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpi_video.c [new file with mode: 0644]
drivers/acpi/acpica/acdebug.h
drivers/acpi/acpica/aclocal.h
drivers/acpi/acpica/acparser.h
drivers/acpi/acpica/acpredef.h
drivers/acpi/acpica/acutils.h
drivers/acpi/acpica/dsmethod.c
drivers/acpi/acpica/hwpci.c
drivers/acpi/acpica/nsprepkg.c
drivers/acpi/acpica/nsrepair.c
drivers/acpi/acpica/psopinfo.c
drivers/acpi/acpica/utfileio.c
drivers/acpi/acpica/uthex.c
drivers/acpi/acpica/utxferror.c
drivers/acpi/apei/ghes.c
drivers/acpi/battery.c
drivers/acpi/bus.c
drivers/acpi/device_pm.c
drivers/acpi/ec.c
drivers/acpi/fan.c
drivers/acpi/hed.c
drivers/acpi/internal.h
drivers/acpi/osl.c
drivers/acpi/pci_irq.c
drivers/acpi/power.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_pdc.c
drivers/acpi/resource.c
drivers/acpi/scan.c
drivers/acpi/utils.c
drivers/acpi/video.c [deleted file]
drivers/acpi/video_detect.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/pci/pci-acpi.c
drivers/platform/x86/Kconfig
drivers/platform/x86/acer-wmi.c
drivers/platform/x86/apple-gmux.c
drivers/platform/x86/asus-laptop.c
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/dell-wmi.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/ideapad-laptop.c
drivers/platform/x86/intel_oaktrail.c
drivers/platform/x86/msi-laptop.c
drivers/platform/x86/msi-wmi.c
drivers/platform/x86/samsung-laptop.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/toshiba_acpi.c
drivers/pnp/system.c
drivers/xen/xen-acpi-cpuhotplug.c
include/acpi/acpi_bus.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/actbl.h
include/acpi/actbl1.h
include/acpi/actbl2.h
include/acpi/actbl3.h
include/acpi/actypes.h
include/acpi/acuuid.h [new file with mode: 0644]
include/acpi/platform/acenv.h
include/acpi/platform/acenvex.h
include/acpi/video.h
include/linux/acpi.h
init/main.c

index 15dfce7..b731b29 100644 (file)
@@ -42,7 +42,7 @@ Adding ACPI support for an existing driver should be pretty
 straightforward. Here is the simplest example:
 
        #ifdef CONFIG_ACPI
-       static struct acpi_device_id mydrv_acpi_match[] = {
+       static const struct acpi_device_id mydrv_acpi_match[] = {
                /* ACPI IDs here */
                { }
        };
@@ -166,7 +166,7 @@ the platform device drivers. Below is an example where we add ACPI support
 to at25 SPI eeprom driver (this is meant for the above ACPI snippet):
 
        #ifdef CONFIG_ACPI
-       static struct acpi_device_id at25_acpi_match[] = {
+       static const struct acpi_device_id at25_acpi_match[] = {
                { "AT25", 0 },
                { },
        };
@@ -230,7 +230,7 @@ Below is an example of how to add ACPI support to the existing mpu3050
 input driver:
 
        #ifdef CONFIG_ACPI
-       static struct acpi_device_id mpu3050_acpi_match[] = {
+       static const struct acpi_device_id mpu3050_acpi_match[] = {
                { "MPU3050", 0 },
                { },
        };
@@ -359,3 +359,54 @@ the id should be set like:
 The ACPI id "XYZ0001" is then used to lookup an ACPI device directly under
 the MFD device and if found, that ACPI companion device is bound to the
 resulting child platform device.
+
+Device Tree namespace link device ID
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The Device Tree protocol uses device indentification based on the "compatible"
+property whose value is a string or an array of strings recognized as device
+identifiers by drivers and the driver core.  The set of all those strings may be
+regarded as a device indentification namespace analogous to the ACPI/PNP device
+ID namespace.  Consequently, in principle it should not be necessary to allocate
+a new (and arguably redundant) ACPI/PNP device ID for a devices with an existing
+identification string in the Device Tree (DT) namespace, especially if that ID
+is only needed to indicate that a given device is compatible with another one,
+presumably having a matching driver in the kernel already.
+
+In ACPI, the device identification object called _CID (Compatible ID) is used to
+list the IDs of devices the given one is compatible with, but those IDs must
+belong to one of the namespaces prescribed by the ACPI specification (see
+Section 6.1.2 of ACPI 6.0 for details) and the DT namespace is not one of them.
+Moreover, the specification mandates that either a _HID or an _ADR identificaion
+object be present for all ACPI objects representing devices (Section 6.1 of ACPI
+6.0).  For non-enumerable bus types that object must be _HID and its value must
+be a device ID from one of the namespaces prescribed by the specification too.
+
+The special DT namespace link device ID, PRP0001, provides a means to use the
+existing DT-compatible device identification in ACPI and to satisfy the above
+requirements following from the ACPI specification at the same time.  Namely,
+if PRP0001 is returned by _HID, the ACPI subsystem will look for the
+"compatible" property in the device object's _DSD and will use the value of that
+property to identify the corresponding device in analogy with the original DT
+device identification algorithm.  If the "compatible" property is not present
+or its value is not valid, the device will not be enumerated by the ACPI
+subsystem.  Otherwise, it will be enumerated automatically as a platform device
+(except when an I2C or SPI link from the device to its parent is present, in
+which case the ACPI core will leave the device enumeration to the parent's
+driver) and the identification strings from the "compatible" property value will
+be used to find a driver for the device along with the device IDs listed by _CID
+(if present).
+
+Analogously, if PRP0001 is present in the list of device IDs returned by _CID,
+the identification strings listed by the "compatible" property value (if present
+and valid) will be used to look for a driver matching the device, but in that
+case their relative priority with respect to the other device IDs listed by
+_HID and _CID depends on the position of PRP0001 in the _CID return package.
+Specifically, the device IDs returned by _HID and preceding PRP0001 in the _CID
+return package will be checked first.  Also in that case the bus type the device
+will be enumerated to depends on the device ID returned by _HID.
+
+It is valid to define device objects with a _HID returning PRP0001 and without
+the "compatible" property in the _DSD or a _CID as long as one of their
+ancestors provides a _DSD with a valid "compatible" property.  Such device
+objects are then simply regarded as additional "blocks" providing hierarchical
+configuration information to the driver of the composite ancestor device.
index 6726139..10f8792 100644 (file)
@@ -179,11 +179,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 
                        See also Documentation/power/runtime_pm.txt, pci=noacpi
 
-       acpi_rsdp=      [ACPI,EFI,KEXEC]
-                       Pass the RSDP address to the kernel, mostly used
-                       on machines running EFI runtime service to boot the
-                       second kernel for kdump.
-
        acpi_apic_instance=     [ACPI, IOAPIC]
                        Format: <int>
                        2: use 2nd APIC table, if available
@@ -197,6 +192,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        (e.g. thinkpad_acpi, sony_acpi, etc.) instead
                        of the ACPI video.ko driver.
 
+       acpica_no_return_repair [HW, ACPI]
+                       Disable AML predefined validation mechanism
+                       This mechanism can repair the evaluation result to make
+                       the return objects more ACPI specification compliant.
+                       This option is useful for developers to identify the
+                       root cause of an AML interpreter issue when the issue
+                       has something to do with the repair mechanism.
+
        acpi.debug_layer=       [HW,ACPI,ACPI_DEBUG]
        acpi.debug_level=       [HW,ACPI,ACPI_DEBUG]
                        Format: <int>
@@ -225,6 +228,22 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        unusable.  The "log_buf_len" parameter may be useful
                        if you need to capture more output.
 
+       acpi_enforce_resources= [ACPI]
+                       { strict | lax | no }
+                       Check for resource conflicts between native drivers
+                       and ACPI OperationRegions (SystemIO and SystemMemory
+                       only). IO ports and memory declared in ACPI might be
+                       used by the ACPI subsystem in arbitrary AML code and
+                       can interfere with legacy drivers.
+                       strict (default): access to resources claimed by ACPI
+                       is denied; legacy drivers trying to access reserved
+                       resources will fail to bind to device using them.
+                       lax: access to resources claimed by ACPI is allowed;
+                       legacy drivers trying to access reserved resources
+                       will bind successfully but a warning message is logged.
+                       no: ACPI OperationRegions are not marked as reserved,
+                       no further checks are performed.
+
        acpi_force_table_verification   [HW,ACPI]
                        Enable table checksum verification during early stage.
                        By default, this is disabled due to x86 early mapping
@@ -253,6 +272,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        This feature is enabled by default.
                        This option allows to turn off the feature.
 
+       acpi_no_memhotplug [ACPI] Disable memory hotplug.  Useful for kdump
+                          kernels.
+
        acpi_no_static_ssdt     [HW,ACPI]
                        Disable installation of static SSDTs at early boot time
                        By default, SSDTs contained in the RSDT/XSDT will be
@@ -263,13 +285,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        dynamic table installation which will install SSDT
                        tables to /sys/firmware/acpi/tables/dynamic.
 
-       acpica_no_return_repair [HW, ACPI]
-                       Disable AML predefined validation mechanism
-                       This mechanism can repair the evaluation result to make
-                       the return objects more ACPI specification compliant.
-                       This option is useful for developers to identify the
-                       root cause of an AML interpreter issue when the issue
-                       has something to do with the repair mechanism.
+       acpi_rsdp=      [ACPI,EFI,KEXEC]
+                       Pass the RSDP address to the kernel, mostly used
+                       on machines running EFI runtime service to boot the
+                       second kernel for kdump.
 
        acpi_os_name=   [HW,ACPI] Tell ACPI BIOS the name of the OS
                        Format: To spoof as Windows 98: ="Microsoft Windows"
@@ -365,25 +384,6 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Use timer override. For some broken Nvidia NF5 boards
                        that require a timer override, but don't have HPET
 
-       acpi_enforce_resources= [ACPI]
-                       { strict | lax | no }
-                       Check for resource conflicts between native drivers
-                       and ACPI OperationRegions (SystemIO and SystemMemory
-                       only). IO ports and memory declared in ACPI might be
-                       used by the ACPI subsystem in arbitrary AML code and
-                       can interfere with legacy drivers.
-                       strict (default): access to resources claimed by ACPI
-                       is denied; legacy drivers trying to access reserved
-                       resources will fail to bind to device using them.
-                       lax: access to resources claimed by ACPI is allowed;
-                       legacy drivers trying to access reserved resources
-                       will bind successfully but a warning message is logged.
-                       no: ACPI OperationRegions are not marked as reserved,
-                       no further checks are performed.
-
-       acpi_no_memhotplug [ACPI] Disable memory hotplug.  Useful for kdump
-                          kernels.
-
        add_efi_memmap  [EFI; X86] Include EFI memory map in
                        kernel's map of available physical RAM.
 
index 212735f..35da507 100644 (file)
@@ -65,7 +65,7 @@ config ACPI_SLEEP
 
 config ACPI_PROCFS_POWER
        bool "Deprecated power /proc/acpi directories"
-       depends on PROC_FS
+       depends on X86 && PROC_FS
        help
          For backwards compatibility, this option allows
           deprecated power /proc/acpi/ directories to exist, even when
index 8a063e2..73d840b 100644 (file)
@@ -52,9 +52,6 @@ acpi-$(CONFIG_X86)            += acpi_cmos_rtc.o
 acpi-$(CONFIG_DEBUG_FS)                += debugfs.o
 acpi-$(CONFIG_ACPI_NUMA)       += numa.o
 acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
-ifdef CONFIG_ACPI_VIDEO
-acpi-y                         += video_detect.o
-endif
 acpi-y                         += acpi_lpat.o
 acpi-$(CONFIG_ACPI_GENERIC_GSI) += gsi.o
 
@@ -95,3 +92,5 @@ obj-$(CONFIG_ACPI_EXTLOG)     += acpi_extlog.o
 obj-$(CONFIG_PMIC_OPREGION)    += pmic/intel_pmic.o
 obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
 obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
+
+video-objs                     += acpi_video.o video_detect.o
index bbcc2b5..9b5354a 100644 (file)
@@ -308,7 +308,7 @@ static int thinkpad_e530_quirk(const struct dmi_system_id *d)
        return 0;
 }
 
-static struct dmi_system_id ac_dmi_table[] = {
+static const struct dmi_system_id ac_dmi_table[] = {
        {
        .callback = thinkpad_e530_quirk,
        .ident = "thinkpad e530",
index 37fb190..569ee09 100644 (file)
@@ -129,50 +129,50 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
        writel(0, pdata->mmio_base + LPSS_I2C_ENABLE);
 }
 
-static struct lpss_device_desc lpt_dev_desc = {
+static const struct lpss_device_desc lpt_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
        .prv_offset = 0x800,
 };
 
-static struct lpss_device_desc lpt_i2c_dev_desc = {
+static const struct lpss_device_desc lpt_i2c_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_LTR,
        .prv_offset = 0x800,
 };
 
-static struct lpss_device_desc lpt_uart_dev_desc = {
+static const struct lpss_device_desc lpt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_LTR,
        .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
 
-static struct lpss_device_desc lpt_sdio_dev_desc = {
+static const struct lpss_device_desc lpt_sdio_dev_desc = {
        .flags = LPSS_LTR,
        .prv_offset = 0x1000,
        .prv_size_override = 0x1018,
 };
 
-static struct lpss_device_desc byt_pwm_dev_desc = {
+static const struct lpss_device_desc byt_pwm_dev_desc = {
        .flags = LPSS_SAVE_CTX,
 };
 
-static struct lpss_device_desc byt_uart_dev_desc = {
+static const struct lpss_device_desc byt_uart_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
        .clk_con_id = "baudclk",
        .prv_offset = 0x800,
        .setup = lpss_uart_setup,
 };
 
-static struct lpss_device_desc byt_spi_dev_desc = {
+static const struct lpss_device_desc byt_spi_dev_desc = {
        .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
        .prv_offset = 0x400,
 };
 
-static struct lpss_device_desc byt_sdio_dev_desc = {
+static const struct lpss_device_desc byt_sdio_dev_desc = {
        .flags = LPSS_CLK,
 };
 
-static struct lpss_device_desc byt_i2c_dev_desc = {
+static const struct lpss_device_desc byt_i2c_dev_desc = {
        .flags = LPSS_CLK | LPSS_SAVE_CTX,
        .prv_offset = 0x800,
        .setup = byt_i2c_setup,
@@ -323,14 +323,14 @@ out:
 static int acpi_lpss_create_device(struct acpi_device *adev,
                                   const struct acpi_device_id *id)
 {
-       struct lpss_device_desc *dev_desc;
+       const struct lpss_device_desc *dev_desc;
        struct lpss_private_data *pdata;
        struct resource_entry *rentry;
        struct list_head resource_list;
        struct platform_device *pdev;
        int ret;
 
-       dev_desc = (struct lpss_device_desc *)id->driver_data;
+       dev_desc = (const struct lpss_device_desc *)id->driver_data;
        if (!dev_desc) {
                pdev = acpi_create_platform_device(adev);
                return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
index 58f335c..92a5f73 100644 (file)
@@ -170,7 +170,7 @@ static int acpi_processor_hotadd_init(struct acpi_processor *pr)
        acpi_status status;
        int ret;
 
-       if (pr->phys_id == PHYS_CPUID_INVALID)
+       if (invalid_phys_cpuid(pr->phys_id))
                return -ENODEV;
 
        status = acpi_evaluate_integer(pr->handle, "_STA", NULL, &sta);
@@ -215,8 +215,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
        union acpi_object object = { 0 };
        struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
        struct acpi_processor *pr = acpi_driver_data(device);
-       phys_cpuid_t phys_id;
-       int cpu_index, device_declaration = 0;
+       int device_declaration = 0;
        acpi_status status = AE_OK;
        static int cpu0_initialized;
        unsigned long long value;
@@ -263,29 +262,28 @@ static int acpi_processor_get_info(struct acpi_device *device)
                pr->acpi_id = value;
        }
 
-       phys_id = acpi_get_phys_id(pr->handle, device_declaration, pr->acpi_id);
-       if (phys_id == PHYS_CPUID_INVALID)
+       pr->phys_id = acpi_get_phys_id(pr->handle, device_declaration,
+                                       pr->acpi_id);
+       if (invalid_phys_cpuid(pr->phys_id))
                acpi_handle_debug(pr->handle, "failed to get CPU physical ID.\n");
-       pr->phys_id = phys_id;
 
-       cpu_index = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
+       pr->id = acpi_map_cpuid(pr->phys_id, pr->acpi_id);
        if (!cpu0_initialized && !acpi_has_cpu_in_madt()) {
                cpu0_initialized = 1;
                /*
                 * Handle UP system running SMP kernel, with no CPU
                 * entry in MADT
                 */
-               if ((cpu_index == -1) && (num_online_cpus() == 1))
-                       cpu_index = 0;
+               if (invalid_logical_cpuid(pr->id) && (num_online_cpus() == 1))
+                       pr->id = 0;
        }
-       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 (pr->id == -1) {
+       if (invalid_logical_cpuid(pr->id)) {
                int ret = acpi_processor_hotadd_init(pr);
                if (ret)
                        return ret;
diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c
new file mode 100644 (file)
index 0000000..8c2fe2f
--- /dev/null
@@ -0,0 +1,2060 @@
+/*
+ *  video.c - ACPI Video Driver
+ *
+ *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
+ *  Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
+ *  Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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/mutex.h>
+#include <linux/input.h>
+#include <linux/backlight.h>
+#include <linux/thermal.h>
+#include <linux/sort.h>
+#include <linux/pci.h>
+#include <linux/pci_ids.h>
+#include <linux/slab.h>
+#include <linux/dmi.h>
+#include <linux/suspend.h>
+#include <linux/acpi.h>
+#include <acpi/video.h>
+#include <asm/uaccess.h>
+
+#define PREFIX "ACPI: "
+
+#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     0x85
+#define        ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS        0x86
+#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS       0x87
+#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS      0x88
+#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF          0x89
+
+#define MAX_NAME_LEN   20
+
+#define _COMPONENT             ACPI_VIDEO_COMPONENT
+ACPI_MODULE_NAME("video");
+
+MODULE_AUTHOR("Bruno Ducrot");
+MODULE_DESCRIPTION("ACPI Video Driver");
+MODULE_LICENSE("GPL");
+
+static bool brightness_switch_enabled = 1;
+module_param(brightness_switch_enabled, bool, 0644);
+
+/*
+ * By default, we don't allow duplicate ACPI video bus devices
+ * under the same VGA controller
+ */
+static bool allow_duplicates;
+module_param(allow_duplicates, bool, 0644);
+
+static int disable_backlight_sysfs_if = -1;
+module_param(disable_backlight_sysfs_if, int, 0444);
+
+static int register_count;
+static DEFINE_MUTEX(register_count_mutex);
+static struct mutex video_list_lock;
+static struct list_head video_bus_head;
+static int acpi_video_bus_add(struct acpi_device *device);
+static int acpi_video_bus_remove(struct acpi_device *device);
+static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
+void acpi_video_detect_exit(void);
+
+static const struct acpi_device_id video_device_ids[] = {
+       {ACPI_VIDEO_HID, 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, video_device_ids);
+
+static struct acpi_driver acpi_video_bus = {
+       .name = "video",
+       .class = ACPI_VIDEO_CLASS,
+       .ids = video_device_ids,
+       .ops = {
+               .add = acpi_video_bus_add,
+               .remove = acpi_video_bus_remove,
+               .notify = acpi_video_bus_notify,
+               },
+};
+
+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 differentiates the display type */
+       u32 display_type:4;     /* Describe the specific type in use */
+       u32 vendor_specific:4;  /* Chipset Vendor Specific */
+       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 {
+       struct acpi_device *device;
+       bool backlight_registered;
+       u8 dos_setting;
+       struct acpi_video_enumerated_device *attached_array;
+       u8 attached_count;
+       u8 child_count;
+       struct acpi_video_bus_cap cap;
+       struct acpi_video_bus_flags flags;
+       struct list_head video_device_list;
+       struct mutex device_list_lock;  /* protects video_device_list */
+       struct list_head entry;
+       struct input_dev *input;
+       char phys[32];  /* for input device */
+       struct notifier_block pm_nb;
+};
+
+struct acpi_video_device_flags {
+       u8 crt:1;
+       u8 lcd:1;
+       u8 tvout:1;
+       u8 dvi:1;
+       u8 bios:1;
+       u8 unknown:1;
+       u8 notify:1;
+       u8 reserved:1;
+};
+
+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 _BQC:1;              /* Get current brightness level */
+       u8 _BCQ:1;              /* Some buggy BIOS uses _BCQ instead of _BQC */
+       u8 _DDC:1;              /* Return the EDID for this device */
+};
+
+struct acpi_video_brightness_flags {
+       u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */
+       u8 _BCL_reversed:1;             /* _BCL package is in a reversed order */
+       u8 _BQC_use_index:1;            /* _BQC returns an index value */
+};
+
+struct acpi_video_device_brightness {
+       int curr;
+       int count;
+       int *levels;
+       struct acpi_video_brightness_flags flags;
+};
+
+struct acpi_video_device {
+       unsigned long device_id;
+       struct acpi_video_device_flags flags;
+       struct acpi_video_device_cap cap;
+       struct list_head entry;
+       struct delayed_work switch_brightness_work;
+       int switch_brightness_event;
+       struct acpi_video_bus *video;
+       struct acpi_device *dev;
+       struct acpi_video_device_brightness *brightness;
+       struct backlight_device *backlight;
+       struct thermal_cooling_device *cooling_dev;
+};
+
+static const 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_device_lcd_set_level(struct acpi_video_device *device,
+                       int level);
+static int acpi_video_device_lcd_get_level_current(
+                       struct acpi_video_device *device,
+                       unsigned long long *level, bool raw);
+static int acpi_video_get_next_level(struct acpi_video_device *device,
+                                    u32 level_current, u32 event);
+static void acpi_video_switch_brightness(struct work_struct *work);
+
+/* backlight device sysfs support */
+static int acpi_video_get_brightness(struct backlight_device *bd)
+{
+       unsigned long long cur_level;
+       int i;
+       struct acpi_video_device *vd = bl_get_data(bd);
+
+       if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
+               return -EINVAL;
+       for (i = 2; i < vd->brightness->count; i++) {
+               if (vd->brightness->levels[i] == cur_level)
+                       /*
+                        * The first two entries are special - see page 575
+                        * of the ACPI spec 3.0
+                        */
+                       return i - 2;
+       }
+       return 0;
+}
+
+static int acpi_video_set_brightness(struct backlight_device *bd)
+{
+       int request_level = bd->props.brightness + 2;
+       struct acpi_video_device *vd = bl_get_data(bd);
+
+       cancel_delayed_work(&vd->switch_brightness_work);
+       return acpi_video_device_lcd_set_level(vd,
+                               vd->brightness->levels[request_level]);
+}
+
+static const struct backlight_ops acpi_backlight_ops = {
+       .get_brightness = acpi_video_get_brightness,
+       .update_status  = acpi_video_set_brightness,
+};
+
+/* thermal cooling device callbacks */
+static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
+                              long *state)
+{
+       struct acpi_device *device = cooling_dev->devdata;
+       struct acpi_video_device *video = acpi_driver_data(device);
+
+       *state = video->brightness->count - 3;
+       return 0;
+}
+
+static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned
+                              long *state)
+{
+       struct acpi_device *device = cooling_dev->devdata;
+       struct acpi_video_device *video = acpi_driver_data(device);
+       unsigned long long level;
+       int offset;
+
+       if (acpi_video_device_lcd_get_level_current(video, &level, false))
+               return -EINVAL;
+       for (offset = 2; offset < video->brightness->count; offset++)
+               if (level == video->brightness->levels[offset]) {
+                       *state = video->brightness->count - offset - 1;
+                       return 0;
+               }
+
+       return -EINVAL;
+}
+
+static int
+video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
+{
+       struct acpi_device *device = cooling_dev->devdata;
+       struct acpi_video_device *video = acpi_driver_data(device);
+       int level;
+
+       if (state >= video->brightness->count - 2)
+               return -EINVAL;
+
+       state = video->brightness->count - state;
+       level = video->brightness->levels[state - 1];
+       return acpi_video_device_lcd_set_level(video, level);
+}
+
+static const struct thermal_cooling_device_ops video_cooling_ops = {
+       .get_max_state = video_get_max_state,
+       .get_cur_state = video_get_cur_state,
+       .set_cur_state = video_set_cur_state,
+};
+
+/*
+ * --------------------------------------------------------------------------
+ *                             Video Management
+ * --------------------------------------------------------------------------
+ */
+
+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;
+
+
+       *levels = NULL;
+
+       status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer);
+       if (!ACPI_SUCCESS(status))
+               return status;
+       obj = (union acpi_object *)buffer.pointer;
+       if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
+               printk(KERN_ERR PREFIX "Invalid _BCL data\n");
+               status = -EFAULT;
+               goto err;
+       }
+
+       *levels = obj;
+
+       return 0;
+
+err:
+       kfree(buffer.pointer);
+
+       return status;
+}
+
+static int
+acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
+{
+       int status;
+       int state;
+
+       status = acpi_execute_simple_method(device->dev->handle,
+                                           "_BCM", level);
+       if (ACPI_FAILURE(status)) {
+               ACPI_ERROR((AE_INFO, "Evaluating _BCM failed"));
+               return -EIO;
+       }
+
+       device->brightness->curr = level;
+       for (state = 2; state < device->brightness->count; state++)
+               if (level == device->brightness->levels[state]) {
+                       if (device->backlight)
+                               device->backlight->props.brightness = state - 2;
+                       return 0;
+               }
+
+       ACPI_ERROR((AE_INFO, "Current brightness invalid"));
+       return -EINVAL;
+}
+
+/*
+ * For some buggy _BQC methods, we need to add a constant value to
+ * the _BQC return value to get the actual current brightness level
+ */
+
+static int bqc_offset_aml_bug_workaround;
+static int video_set_bqc_offset(const struct dmi_system_id *d)
+{
+       bqc_offset_aml_bug_workaround = 9;
+       return 0;
+}
+
+static int video_disable_backlight_sysfs_if(
+       const struct dmi_system_id *d)
+{
+       if (disable_backlight_sysfs_if == -1)
+               disable_backlight_sysfs_if = 1;
+       return 0;
+}
+
+static struct dmi_system_id video_dmi_table[] = {
+       /*
+        * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
+        */
+       {
+        .callback = video_set_bqc_offset,
+        .ident = "Acer Aspire 5720",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
+               },
+       },
+       {
+        .callback = video_set_bqc_offset,
+        .ident = "Acer Aspire 5710Z",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710Z"),
+               },
+       },
+       {
+        .callback = video_set_bqc_offset,
+        .ident = "eMachines E510",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "EMACHINES"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "eMachines E510"),
+               },
+       },
+       {
+        .callback = video_set_bqc_offset,
+        .ident = "Acer Aspire 5315",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
+               },
+       },
+       {
+        .callback = video_set_bqc_offset,
+        .ident = "Acer Aspire 7720",
+        .matches = {
+               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
+               },
+       },
+
+       /*
+        * Some machines have a broken acpi-video interface for brightness
+        * control, but still need an acpi_video_device_lcd_set_level() call
+        * on resume to turn the backlight power on.  We Enable backlight
+        * control on these systems, but do not register a backlight sysfs
+        * as brightness control does not work.
+        */
+       {
+        /* https://bugs.freedesktop.org/show_bug.cgi?id=82634 */
+        .callback = video_disable_backlight_sysfs_if,
+        .ident = "Toshiba Portege R830",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE R830"),
+               },
+       },
+       {}
+};
+
+static unsigned long long
+acpi_video_bqc_value_to_level(struct acpi_video_device *device,
+                             unsigned long long bqc_value)
+{
+       unsigned long long level;
+
+       if (device->brightness->flags._BQC_use_index) {
+               /*
+                * _BQC returns an index that doesn't account for
+                * the first 2 items with special meaning, so we need
+                * to compensate for that by offsetting ourselves
+                */
+               if (device->brightness->flags._BCL_reversed)
+                       bqc_value = device->brightness->count - 3 - bqc_value;
+
+               level = device->brightness->levels[bqc_value + 2];
+       } else {
+               level = bqc_value;
+       }
+
+       level += bqc_offset_aml_bug_workaround;
+
+       return level;
+}
+
+static int
+acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
+                                       unsigned long long *level, bool raw)
+{
+       acpi_status status = AE_OK;
+       int i;
+
+       if (device->cap._BQC || device->cap._BCQ) {
+               char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
+
+               status = acpi_evaluate_integer(device->dev->handle, buf,
+                                               NULL, level);
+               if (ACPI_SUCCESS(status)) {
+                       if (raw) {
+                               /*
+                                * Caller has indicated he wants the raw
+                                * value returned by _BQC, so don't furtherly
+                                * mess with the value.
+                                */
+                               return 0;
+                       }
+
+                       *level = acpi_video_bqc_value_to_level(device, *level);
+
+                       for (i = 2; i < device->brightness->count; i++)
+                               if (device->brightness->levels[i] == *level) {
+                                       device->brightness->curr = *level;
+                                       return 0;
+                               }
+                       /*
+                        * BQC returned an invalid level.
+                        * Stop using it.
+                        */
+                       ACPI_WARNING((AE_INFO,
+                                     "%s returned an invalid level",
+                                     buf));
+                       device->cap._BQC = device->cap._BCQ = 0;
+               } else {
+                       /*
+                        * Fixme:
+                        * should we return an error or ignore this failure?
+                        * dev->brightness->curr is a cached value which stores
+                        * the correct current backlight level in most cases.
+                        * ACPI video backlight still works w/ buggy _BQC.
+                        * http://bugzilla.kernel.org/show_bug.cgi?id=12233
+                        */
+                       ACPI_WARNING((AE_INFO, "Evaluating %s failed", buf));
+                       device->cap._BQC = device->cap._BCQ = 0;
+               }
+       }
+
+       *level = device->brightness->curr;
+       return 0;
+}
+
+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 };
+
+
+       *edid = NULL;
+
+       if (!device)
+               return -ENODEV;
+       if (length == 128)
+               arg0.integer.value = 1;
+       else if (length == 256)
+               arg0.integer.value = 2;
+       else
+               return -EINVAL;
+
+       status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       obj = buffer.pointer;
+
+       if (obj && obj->type == ACPI_TYPE_BUFFER)
+               *edid = obj;
+       else {
+               printk(KERN_ERR PREFIX "Invalid _DDC data\n");
+               status = -EFAULT;
+               kfree(obj);
+       }
+
+       return status;
+}
+
+/* bus */
+
+/*
+ *  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 switch 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:
+ *             -EINVAL wrong arg.
+ */
+
+static int
+acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
+{
+       acpi_status status;
+
+       if (!video->cap._DOS)
+               return 0;
+
+       if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1)
+               return -EINVAL;
+       video->dos_setting = (lcd_flag << 2) | bios_flag;
+       status = acpi_execute_simple_method(video->device->handle, "_DOS",
+                                           (lcd_flag << 2) | bios_flag);
+       if (ACPI_FAILURE(status))
+               return -EIO;
+
+       return 0;
+}
+
+/*
+ * Simple comparison function used to sort backlight levels.
+ */
+
+static int
+acpi_video_cmp_level(const void *a, const void *b)
+{
+       return *(int *)a - *(int *)b;
+}
+
+/*
+ * Decides if _BQC/_BCQ for this system is usable
+ *
+ * We do this by changing the level first and then read out the current
+ * brightness level, if the value does not match, find out if it is using
+ * index. If not, clear the _BQC/_BCQ capability.
+ */
+static int acpi_video_bqc_quirk(struct acpi_video_device *device,
+                               int max_level, int current_level)
+{
+       struct acpi_video_device_brightness *br = device->brightness;
+       int result;
+       unsigned long long level;
+       int test_level;
+
+       /* don't mess with existing known broken systems */
+       if (bqc_offset_aml_bug_workaround)
+               return 0;
+
+       /*
+        * Some systems always report current brightness level as maximum
+        * through _BQC, we need to test another value for them.
+        */
+       test_level = current_level == max_level ? br->levels[3] : max_level;
+
+       result = acpi_video_device_lcd_set_level(device, test_level);
+       if (result)
+               return result;
+
+       result = acpi_video_device_lcd_get_level_current(device, &level, true);
+       if (result)
+               return result;
+
+       if (level != test_level) {
+               /* buggy _BQC found, need to find out if it uses index */
+               if (level < br->count) {
+                       if (br->flags._BCL_reversed)
+                               level = br->count - 3 - level;
+                       if (br->levels[level + 2] == test_level)
+                               br->flags._BQC_use_index = 1;
+               }
+
+               if (!br->flags._BQC_use_index)
+                       device->cap._BQC = device->cap._BCQ = 0;
+       }
+
+       return 0;
+}
+
+
+/*
+ *  Arg:
+ *     device  : video output device (LCD, CRT, ..)
+ *
+ *  Return Value:
+ *     Maximum brightness level
+ *
+ *  Allocate and initialize device->brightness.
+ */
+
+static int
+acpi_video_init_brightness(struct acpi_video_device *device)
+{
+       union acpi_object *obj = NULL;
+       int i, max_level = 0, count = 0, level_ac_battery = 0;
+       unsigned long long level, level_old;
+       union acpi_object *o;
+       struct acpi_video_device_brightness *br = NULL;
+       int result = -EINVAL;
+       u32 value;
+
+       if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
+                                               "LCD brightness level\n"));
+               goto out;
+       }
+
+       if (obj->package.count < 2)
+               goto out;
+
+       br = kzalloc(sizeof(*br), GFP_KERNEL);
+       if (!br) {
+               printk(KERN_ERR "can't allocate memory\n");
+               result = -ENOMEM;
+               goto out;
+       }
+
+       br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels),
+                               GFP_KERNEL);
+       if (!br->levels) {
+               result = -ENOMEM;
+               goto out_free;
+       }
+
+       for (i = 0; i < obj->package.count; i++) {
+               o = (union acpi_object *)&obj->package.elements[i];
+               if (o->type != ACPI_TYPE_INTEGER) {
+                       printk(KERN_ERR PREFIX "Invalid data\n");
+                       continue;
+               }
+               value = (u32) o->integer.value;
+               /* Skip duplicate entries */
+               if (count > 2 && br->levels[count - 1] == value)
+                       continue;
+
+               br->levels[count] = value;
+
+               if (br->levels[count] > max_level)
+                       max_level = br->levels[count];
+               count++;
+       }
+
+       /*
+        * some buggy BIOS don't export the levels
+        * when machine is on AC/Battery in _BCL package.
+        * In this case, the first two elements in _BCL packages
+        * are also supported brightness levels that OS should take care of.
+        */
+       for (i = 2; i < count; i++) {
+               if (br->levels[i] == br->levels[0])
+                       level_ac_battery++;
+               if (br->levels[i] == br->levels[1])
+                       level_ac_battery++;
+       }
+
+       if (level_ac_battery < 2) {
+               level_ac_battery = 2 - level_ac_battery;
+               br->flags._BCL_no_ac_battery_levels = 1;
+               for (i = (count - 1 + level_ac_battery); i >= 2; i--)
+                       br->levels[i] = br->levels[i - level_ac_battery];
+               count += level_ac_battery;
+       } else if (level_ac_battery > 2)
+               ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package"));
+
+       /* Check if the _BCL package is in a reversed order */
+       if (max_level == br->levels[2]) {
+               br->flags._BCL_reversed = 1;
+               sort(&br->levels[2], count - 2, sizeof(br->levels[2]),
+                       acpi_video_cmp_level, NULL);
+       } else if (max_level != br->levels[count - 1])
+               ACPI_ERROR((AE_INFO,
+                           "Found unordered _BCL package"));
+
+       br->count = count;
+       device->brightness = br;
+
+       /* _BQC uses INDEX while _BCL uses VALUE in some laptops */
+       br->curr = level = max_level;
+
+       if (!device->cap._BQC)
+               goto set_level;
+
+       result = acpi_video_device_lcd_get_level_current(device,
+                                                        &level_old, true);
+       if (result)
+               goto out_free_levels;
+
+       result = acpi_video_bqc_quirk(device, max_level, level_old);
+       if (result)
+               goto out_free_levels;
+       /*
+        * cap._BQC may get cleared due to _BQC is found to be broken
+        * in acpi_video_bqc_quirk, so check again here.
+        */
+       if (!device->cap._BQC)
+               goto set_level;
+
+       level = acpi_video_bqc_value_to_level(device, level_old);
+       /*
+        * On some buggy laptops, _BQC returns an uninitialized
+        * value when invoked for the first time, i.e.
+        * level_old is invalid (no matter whether it's a level
+        * or an index). Set the backlight to max_level in this case.
+        */
+       for (i = 2; i < br->count; i++)
+               if (level == br->levels[i])
+                       break;
+       if (i == br->count || !level)
+               level = max_level;
+
+set_level:
+       result = acpi_video_device_lcd_set_level(device, level);
+       if (result)
+               goto out_free_levels;
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                         "found %d brightness levels\n", count - 2));
+       kfree(obj);
+       return result;
+
+out_free_levels:
+       kfree(br->levels);
+out_free:
+       kfree(br);
+out:
+       device->brightness = NULL;
+       kfree(obj);
+       return result;
+}
+
+/*
+ *  Arg:
+ *     device  : video output device (LCD, CRT, ..)
+ *
+ *  Return Value:
+ *     None
+ *
+ *  Find out all required AML methods defined under the output
+ *  device.
+ */
+
+static void acpi_video_device_find_cap(struct acpi_video_device *device)
+{
+       if (acpi_has_method(device->dev->handle, "_ADR"))
+               device->cap._ADR = 1;
+       if (acpi_has_method(device->dev->handle, "_BCL"))
+               device->cap._BCL = 1;
+       if (acpi_has_method(device->dev->handle, "_BCM"))
+               device->cap._BCM = 1;
+       if (acpi_has_method(device->dev->handle, "_BQC")) {
+               device->cap._BQC = 1;
+       } else if (acpi_has_method(device->dev->handle, "_BCQ")) {
+               printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n");
+               device->cap._BCQ = 1;
+       }
+
+       if (acpi_has_method(device->dev->handle, "_DDC"))
+               device->cap._DDC = 1;
+}
+
+/*
+ *  Arg:
+ *     device  : video output device (VGA)
+ *
+ *  Return Value:
+ *     None
+ *
+ *  Find out all required AML methods defined under the video bus device.
+ */
+
+static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
+{
+       if (acpi_has_method(video->device->handle, "_DOS"))
+               video->cap._DOS = 1;
+       if (acpi_has_method(video->device->handle, "_DOD"))
+               video->cap._DOD = 1;
+       if (acpi_has_method(video->device->handle, "_ROM"))
+               video->cap._ROM = 1;
+       if (acpi_has_method(video->device->handle, "_GPD"))
+               video->cap._GPD = 1;
+       if (acpi_has_method(video->device->handle, "_SPD"))
+               video->cap._SPD = 1;
+       if (acpi_has_method(video->device->handle, "_VPO"))
+               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;
+       struct pci_dev *dev;
+
+       if (!video)
+               return -EINVAL;
+
+       dev = acpi_get_pci_dev(video->device->handle);
+       if (!dev)
+               return -ENODEV;
+       pci_dev_put(dev);
+
+       /*
+        * Since there is no HID, CID and so on for VGA driver, we have
+        * to check well known required nodes.
+        */
+
+       /* Does this device support video switching? */
+       if (video->cap._DOS || video->cap._DOD) {
+               if (!video->cap._DOS) {
+                       printk(KERN_WARNING FW_BUG
+                               "ACPI(%s) defines _DOD but not _DOS\n",
+                               acpi_device_bid(video->device));
+               }
+               video->flags.multihead = 1;
+               status = 0;
+       }
+
+       /* Does this device support retrieving a video ROM? */
+       if (video->cap._ROM) {
+               video->flags.rom = 1;
+               status = 0;
+       }
+
+       /* Does this device support configuring which video device to POST? */
+       if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
+               video->flags.post = 1;
+               status = 0;
+       }
+
+       return status;
+}
+
+/*
+ * --------------------------------------------------------------------------
+ *                               Driver Interface
+ * --------------------------------------------------------------------------
+ */
+
+/* device interface */
+static struct acpi_video_device_attrib *
+acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
+{
+       struct acpi_video_enumerated_device *ids;
+       int i;
+
+       for (i = 0; i < video->attached_count; i++) {
+               ids = &video->attached_array[i];
+               if ((ids->value.int_val & 0xffff) == device_id)
+                       return &ids->value.attrib;
+       }
+
+       return NULL;
+}
+
+static int
+acpi_video_get_device_type(struct acpi_video_bus *video,
+                          unsigned long device_id)
+{
+       struct acpi_video_enumerated_device *ids;
+       int i;
+
+       for (i = 0; i < video->attached_count; i++) {
+               ids = &video->attached_array[i];
+               if ((ids->value.int_val & 0xffff) == device_id)
+                       return ids->value.int_val;
+       }
+
+       return 0;
+}
+
+static int
+acpi_video_bus_get_one_device(struct acpi_device *device,
+                             struct acpi_video_bus *video)
+{
+       unsigned long long device_id;
+       int status, device_type;
+       struct acpi_video_device *data;
+       struct acpi_video_device_attrib *attribute;
+
+       status =
+           acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
+       /* Some device omits _ADR, we skip them instead of fail */
+       if (ACPI_FAILURE(status))
+               return 0;
+
+       data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
+       strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+       device->driver_data = data;
+
+       data->device_id = device_id;
+       data->video = video;
+       data->dev = device;
+       INIT_DELAYED_WORK(&data->switch_brightness_work,
+                         acpi_video_switch_brightness);
+
+       attribute = acpi_video_get_device_attr(video, device_id);
+
+       if (attribute && attribute->device_id_scheme) {
+               switch (attribute->display_type) {
+               case ACPI_VIDEO_DISPLAY_CRT:
+                       data->flags.crt = 1;
+                       break;
+               case ACPI_VIDEO_DISPLAY_TV:
+                       data->flags.tvout = 1;
+                       break;
+               case ACPI_VIDEO_DISPLAY_DVI:
+                       data->flags.dvi = 1;
+                       break;
+               case ACPI_VIDEO_DISPLAY_LCD:
+                       data->flags.lcd = 1;
+                       break;
+               default:
+                       data->flags.unknown = 1;
+                       break;
+               }
+               if (attribute->bios_can_detect)
+                       data->flags.bios = 1;
+       } else {
+               /* Check for legacy IDs */
+               device_type = acpi_video_get_device_type(video, device_id);
+               /* Ignore bits 16 and 18-20 */
+               switch (device_type & 0xffe2ffff) {
+               case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
+                       data->flags.crt = 1;
+                       break;
+               case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
+                       data->flags.lcd = 1;
+                       break;
+               case ACPI_VIDEO_DISPLAY_LEGACY_TV:
+                       data->flags.tvout = 1;
+                       break;
+               default:
+                       data->flags.unknown = 1;
+               }
+       }
+
+       acpi_video_device_bind(video, data);
+       acpi_video_device_find_cap(data);
+
+       mutex_lock(&video->device_list_lock);
+       list_add_tail(&data->entry, &video->video_device_list);
+       mutex_unlock(&video->device_list_lock);
+
+       return status;
+}
+
+/*
+ *  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 acpi_video_device *dev;
+
+       mutex_lock(&video->device_list_lock);
+
+       list_for_each_entry(dev, &video->video_device_list, entry)
+               acpi_video_device_bind(video, dev);
+
+       mutex_unlock(&video->device_list_lock);
+}
+
+/*
+ *  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)
+{
+       struct acpi_video_enumerated_device *ids;
+       int i;
+
+       for (i = 0; i < video->attached_count; i++) {
+               ids = &video->attached_array[i];
+               if (device->device_id == (ids->value.int_val & 0xffff)) {
+                       ids->bind_info = device;
+                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
+               }
+       }
+}
+
+static bool acpi_video_device_in_dod(struct acpi_video_device *device)
+{
+       struct acpi_video_bus *video = device->video;
+       int i;
+
+       /*
+        * If we have a broken _DOD or we have more than 8 output devices
+        * under the graphics controller node that we can't proper deal with
+        * in the operation region code currently, no need to test.
+        */
+       if (!video->attached_count || video->child_count > 8)
+               return true;
+
+       for (i = 0; i < video->attached_count; i++) {
+               if ((video->attached_array[i].value.int_val & 0xfff) ==
+                   (device->device_id & 0xfff))
+                       return true;
+       }
+
+       return false;
+}
+
+/*
+ *  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_list;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *dod = NULL;
+       union acpi_object *obj;
+
+       status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
+       if (!ACPI_SUCCESS(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
+               return status;
+       }
+
+       dod = buffer.pointer;
+       if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
+               ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
+               status = -EFAULT;
+               goto out;
+       }
+
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
+                         dod->package.count));
+
+       active_list = kcalloc(1 + dod->package.count,
+                             sizeof(struct acpi_video_enumerated_device),
+                             GFP_KERNEL);
+       if (!active_list) {
+               status = -ENOMEM;
+               goto out;
+       }
+
+       count = 0;
+       for (i = 0; i < dod->package.count; i++) {
+               obj = &dod->package.elements[i];
+
+               if (obj->type != ACPI_TYPE_INTEGER) {
+                       printk(KERN_ERR PREFIX
+                               "Invalid _DOD data in element %d\n", i);
+                       continue;
+               }
+
+               active_list[count].value.int_val = obj->integer.value;
+               active_list[count].bind_info = NULL;
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
+                                 (int)obj->integer.value));
+               count++;
+       }
+
+       kfree(video->attached_array);
+
+       video->attached_array = active_list;
+       video->attached_count = count;
+
+out:
+       kfree(buffer.pointer);
+       return status;
+}
+
+static int
+acpi_video_get_next_level(struct acpi_video_device *device,
+                         u32 level_current, u32 event)
+{
+       int min, max, min_above, max_below, i, l, delta = 255;
+       max = max_below = 0;
+       min = min_above = 255;
+       /* Find closest level to level_current */
+       for (i = 2; i < device->brightness->count; i++) {
+               l = device->brightness->levels[i];
+               if (abs(l - level_current) < abs(delta)) {
+                       delta = l - level_current;
+                       if (!delta)
+                               break;
+               }
+       }
+       /* Ajust level_current to closest available level */
+       level_current += delta;
+       for (i = 2; i < device->brightness->count; i++) {
+               l = device->brightness->levels[i];
+               if (l < min)
+                       min = l;
+               if (l > max)
+                       max = l;
+               if (l < min_above && l > level_current)
+                       min_above = l;
+               if (l > max_below && l < level_current)
+                       max_below = l;
+       }
+
+       switch (event) {
+       case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:
+               return (level_current < max) ? min_above : min;
+       case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:
+               return (level_current < max) ? min_above : max;
+       case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:
+               return (level_current > min) ? max_below : min;
+       case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:
+       case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:
+               return 0;
+       default:
+               return level_current;
+       }
+}
+
+static void
+acpi_video_switch_brightness(struct work_struct *work)
+{
+       struct acpi_video_device *device = container_of(to_delayed_work(work),
+                            struct acpi_video_device, switch_brightness_work);
+       unsigned long long level_current, level_next;
+       int event = device->switch_brightness_event;
+       int result = -EINVAL;
+
+       /* no warning message if acpi_backlight=vendor or a quirk is used */
+       if (!device->backlight)
+               return;
+
+       if (!device->brightness)
+               goto out;
+
+       result = acpi_video_device_lcd_get_level_current(device,
+                                                        &level_current,
+                                                        false);
+       if (result)
+               goto out;
+
+       level_next = acpi_video_get_next_level(device, level_current, event);
+
+       result = acpi_video_device_lcd_set_level(device, level_next);
+
+       if (!result)
+               backlight_force_update(device->backlight,
+                                      BACKLIGHT_UPDATE_HOTKEY);
+
+out:
+       if (result)
+               printk(KERN_ERR PREFIX "Failed to switch the brightness\n");
+}
+
+int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
+                       void **edid)
+{
+       struct acpi_video_bus *video;
+       struct acpi_video_device *video_device;
+       union acpi_object *buffer = NULL;
+       acpi_status status;
+       int i, length;
+
+       if (!device || !acpi_driver_data(device))
+               return -EINVAL;
+
+       video = acpi_driver_data(device);
+
+       for (i = 0; i < video->attached_count; i++) {
+               video_device = video->attached_array[i].bind_info;
+               length = 256;
+
+               if (!video_device)
+                       continue;
+
+               if (!video_device->cap._DDC)
+                       continue;
+
+               if (type) {
+                       switch (type) {
+                       case ACPI_VIDEO_DISPLAY_CRT:
+                               if (!video_device->flags.crt)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_TV:
+                               if (!video_device->flags.tvout)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_DVI:
+                               if (!video_device->flags.dvi)
+                                       continue;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LCD:
+                               if (!video_device->flags.lcd)
+                                       continue;
+                               break;
+                       }
+               } else if (video_device->device_id != device_id) {
+                       continue;
+               }
+
+               status = acpi_video_device_EDID(video_device, &buffer, length);
+
+               if (ACPI_FAILURE(status) || !buffer ||
+                   buffer->type != ACPI_TYPE_BUFFER) {
+                       length = 128;
+                       status = acpi_video_device_EDID(video_device, &buffer,
+                                                       length);
+                       if (ACPI_FAILURE(status) || !buffer ||
+                           buffer->type != ACPI_TYPE_BUFFER) {
+                               continue;
+                       }
+               }
+
+               *edid = buffer->buffer.pointer;
+               return length;
+       }
+
+       return -ENODEV;
+}
+EXPORT_SYMBOL(acpi_video_get_edid);
+
+static int
+acpi_video_bus_get_devices(struct acpi_video_bus *video,
+                          struct acpi_device *device)
+{
+       int status = 0;
+       struct acpi_device *dev;
+
+       /*
+        * There are systems where video module known to work fine regardless
+        * of broken _DOD and ignoring returned value here doesn't cause
+        * any issues later.
+        */
+       acpi_video_device_enumerate(video);
+
+       list_for_each_entry(dev, &device->children, node) {
+
+               status = acpi_video_bus_get_one_device(dev, video);
+               if (status) {
+                       dev_err(&dev->dev, "Can't attach device\n");
+                       break;
+               }
+               video->child_count++;
+       }
+       return status;
+}
+
+/* acpi_video interface */
+
+/*
+ * Win8 requires setting bit2 of _DOS to let firmware know it shouldn't
+ * preform any automatic brightness change on receiving a notification.
+ */
+static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
+{
+       return acpi_video_bus_DOS(video, 0,
+                                 acpi_osi_is_win8() ? 1 : 0);
+}
+
+static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
+{
+       return acpi_video_bus_DOS(video, 0,
+                                 acpi_osi_is_win8() ? 0 : 1);
+}
+
+static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
+{
+       struct acpi_video_bus *video = acpi_driver_data(device);
+       struct input_dev *input;
+       int keycode = 0;
+
+       if (!video || !video->input)
+               return;
+
+       input = video->input;
+
+       switch (event) {
+       case ACPI_VIDEO_NOTIFY_SWITCH:  /* User requested a switch,
+                                        * most likely via hotkey. */
+               keycode = KEY_SWITCHVIDEOMODE;
+               break;
+
+       case ACPI_VIDEO_NOTIFY_PROBE:   /* User plugged in or removed a video
+                                        * connector. */
+               acpi_video_device_enumerate(video);
+               acpi_video_device_rebind(video);
+               keycode = KEY_SWITCHVIDEOMODE;
+               break;
+
+       case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
+               keycode = KEY_SWITCHVIDEOMODE;
+               break;
+       case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
+               keycode = KEY_VIDEO_NEXT;
+               break;
+       case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
+               keycode = KEY_VIDEO_PREV;
+               break;
+
+       default:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Unsupported event [0x%x]\n", event));
+               break;
+       }
+
+       if (acpi_notifier_call_chain(device, event, 0))
+               /* Something vetoed the keypress. */
+               keycode = 0;
+
+       if (keycode) {
+               input_report_key(input, keycode, 1);
+               input_sync(input);
+               input_report_key(input, keycode, 0);
+               input_sync(input);
+       }
+
+       return;
+}
+
+static void brightness_switch_event(struct acpi_video_device *video_device,
+                                   u32 event)
+{
+       if (!brightness_switch_enabled)
+               return;
+
+       video_device->switch_brightness_event = event;
+       schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10);
+}
+
+static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct acpi_video_device *video_device = data;
+       struct acpi_device *device = NULL;
+       struct acpi_video_bus *bus;
+       struct input_dev *input;
+       int keycode = 0;
+
+       if (!video_device)
+               return;
+
+       device = video_device->dev;
+       bus = video_device->video;
+       input = bus->input;
+
+       switch (event) {
+       case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
+               brightness_switch_event(video_device, event);
+               keycode = KEY_BRIGHTNESS_CYCLE;
+               break;
+       case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
+               brightness_switch_event(video_device, event);
+               keycode = KEY_BRIGHTNESSUP;
+               break;
+       case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
+               brightness_switch_event(video_device, event);
+               keycode = KEY_BRIGHTNESSDOWN;
+               break;
+       case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */
+               brightness_switch_event(video_device, event);
+               keycode = KEY_BRIGHTNESS_ZERO;
+               break;
+       case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
+               brightness_switch_event(video_device, event);
+               keycode = KEY_DISPLAY_OFF;
+               break;
+       default:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Unsupported event [0x%x]\n", event));
+               break;
+       }
+
+       acpi_notifier_call_chain(device, event, 0);
+
+       if (keycode) {
+               input_report_key(input, keycode, 1);
+               input_sync(input);
+               input_report_key(input, keycode, 0);
+               input_sync(input);
+       }
+
+       return;
+}
+
+static int acpi_video_resume(struct notifier_block *nb,
+                               unsigned long val, void *ign)
+{
+       struct acpi_video_bus *video;
+       struct acpi_video_device *video_device;
+       int i;
+
+       switch (val) {
+       case PM_HIBERNATION_PREPARE:
+       case PM_SUSPEND_PREPARE:
+       case PM_RESTORE_PREPARE:
+               return NOTIFY_DONE;
+       }
+
+       video = container_of(nb, struct acpi_video_bus, pm_nb);
+
+       dev_info(&video->device->dev, "Restoring backlight state\n");
+
+       for (i = 0; i < video->attached_count; i++) {
+               video_device = video->attached_array[i].bind_info;
+               if (video_device && video_device->brightness)
+                       acpi_video_device_lcd_set_level(video_device,
+                                       video_device->brightness->curr);
+       }
+
+       return NOTIFY_OK;
+}
+
+static acpi_status
+acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
+                       void **return_value)
+{
+       struct acpi_device *device = context;
+       struct acpi_device *sibling;
+       int result;
+
+       if (handle == device->handle)
+               return AE_CTRL_TERMINATE;
+
+       result = acpi_bus_get_device(handle, &sibling);
+       if (result)
+               return AE_OK;
+
+       if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
+                       return AE_ALREADY_EXISTS;
+
+       return AE_OK;
+}
+
+static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
+{
+       struct backlight_properties props;
+       struct pci_dev *pdev;
+       acpi_handle acpi_parent;
+       struct device *parent = NULL;
+       int result;
+       static int count;
+       char *name;
+
+       /*
+        * Do not create backlight device for video output
+        * device that is not in the enumerated list.
+        */
+       if (!acpi_video_device_in_dod(device)) {
+               dev_dbg(&device->dev->dev, "not in _DOD list, ignore\n");
+               return;
+       }
+
+       result = acpi_video_init_brightness(device);
+       if (result)
+               return;
+
+       if (disable_backlight_sysfs_if > 0)
+               return;
+
+       name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
+       if (!name)
+               return;
+       count++;
+
+       acpi_get_parent(device->dev->handle, &acpi_parent);
+
+       pdev = acpi_get_pci_dev(acpi_parent);
+       if (pdev) {
+               parent = &pdev->dev;
+               pci_dev_put(pdev);
+       }
+
+       memset(&props, 0, sizeof(struct backlight_properties));
+       props.type = BACKLIGHT_FIRMWARE;
+       props.max_brightness = device->brightness->count - 3;
+       device->backlight = backlight_device_register(name,
+                                                     parent,
+                                                     device,
+                                                     &acpi_backlight_ops,
+                                                     &props);
+       kfree(name);
+       if (IS_ERR(device->backlight)) {
+               device->backlight = NULL;
+               return;
+       }
+
+       /*
+        * Save current brightness level in case we have to restore it
+        * before acpi_video_device_lcd_set_level() is called next time.
+        */
+       device->backlight->props.brightness =
+                       acpi_video_get_brightness(device->backlight);
+
+       device->cooling_dev = thermal_cooling_device_register("LCD",
+                               device->dev, &video_cooling_ops);
+       if (IS_ERR(device->cooling_dev)) {
+               /*
+                * Set cooling_dev to NULL so we don't crash trying to free it.
+                * Also, why the hell we are returning early and not attempt to
+                * register video output if cooling device registration failed?
+                * -- dtor
+                */
+               device->cooling_dev = NULL;
+               return;
+       }
+
+       dev_info(&device->dev->dev, "registered as cooling_device%d\n",
+                device->cooling_dev->id);
+       result = sysfs_create_link(&device->dev->dev.kobj,
+                       &device->cooling_dev->device.kobj,
+                       "thermal_cooling");
+       if (result)
+               printk(KERN_ERR PREFIX "Create sysfs link\n");
+       result = sysfs_create_link(&device->cooling_dev->device.kobj,
+                       &device->dev->dev.kobj, "device");
+       if (result)
+               printk(KERN_ERR PREFIX "Create sysfs link\n");
+}
+
+static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
+{
+       struct acpi_video_device *dev;
+       union acpi_object *levels;
+
+       mutex_lock(&video->device_list_lock);
+       list_for_each_entry(dev, &video->video_device_list, entry) {
+               if (!acpi_video_device_lcd_query_levels(dev, &levels))
+                       kfree(levels);
+       }
+       mutex_unlock(&video->device_list_lock);
+}
+
+static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
+{
+       struct acpi_video_device *dev;
+
+       if (video->backlight_registered)
+               return 0;
+
+       acpi_video_run_bcl_for_osi(video);
+
+       if (acpi_video_get_backlight_type() != acpi_backlight_video)
+               return 0;
+
+       mutex_lock(&video->device_list_lock);
+       list_for_each_entry(dev, &video->video_device_list, entry)
+               acpi_video_dev_register_backlight(dev);
+       mutex_unlock(&video->device_list_lock);
+
+       video->backlight_registered = true;
+
+       video->pm_nb.notifier_call = acpi_video_resume;
+       video->pm_nb.priority = 0;
+       return register_pm_notifier(&video->pm_nb);
+}
+
+static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device)
+{
+       if (device->backlight) {
+               backlight_device_unregister(device->backlight);
+               device->backlight = NULL;
+       }
+       if (device->brightness) {
+               kfree(device->brightness->levels);
+               kfree(device->brightness);
+               device->brightness = NULL;
+       }
+       if (device->cooling_dev) {
+               sysfs_remove_link(&device->dev->dev.kobj, "thermal_cooling");
+               sysfs_remove_link(&device->cooling_dev->device.kobj, "device");
+               thermal_cooling_device_unregister(device->cooling_dev);
+               device->cooling_dev = NULL;
+       }
+}
+
+static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video)
+{
+       struct acpi_video_device *dev;
+       int error;
+
+       if (!video->backlight_registered)
+               return 0;
+
+       error = unregister_pm_notifier(&video->pm_nb);
+
+       mutex_lock(&video->device_list_lock);
+       list_for_each_entry(dev, &video->video_device_list, entry)
+               acpi_video_dev_unregister_backlight(dev);
+       mutex_unlock(&video->device_list_lock);
+
+       video->backlight_registered = false;
+
+       return error;
+}
+
+static void acpi_video_dev_add_notify_handler(struct acpi_video_device *device)
+{
+       acpi_status status;
+       struct acpi_device *adev = device->dev;
+
+       status = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
+                                            acpi_video_device_notify, device);
+       if (ACPI_FAILURE(status))
+               dev_err(&adev->dev, "Error installing notify handler\n");
+       else
+               device->flags.notify = 1;
+}
+
+static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video)
+{
+       struct input_dev *input;
+       struct acpi_video_device *dev;
+       int error;
+
+       video->input = input = input_allocate_device();
+       if (!input) {
+               error = -ENOMEM;
+               goto out;
+       }
+
+       error = acpi_video_bus_start_devices(video);
+       if (error)
+               goto err_free_input;
+
+       snprintf(video->phys, sizeof(video->phys),
+                       "%s/video/input0", acpi_device_hid(video->device));
+
+       input->name = acpi_device_name(video->device);
+       input->phys = video->phys;
+       input->id.bustype = BUS_HOST;
+       input->id.product = 0x06;
+       input->dev.parent = &video->device->dev;
+       input->evbit[0] = BIT(EV_KEY);
+       set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
+       set_bit(KEY_VIDEO_NEXT, input->keybit);
+       set_bit(KEY_VIDEO_PREV, input->keybit);
+       set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);
+       set_bit(KEY_BRIGHTNESSUP, input->keybit);
+       set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
+       set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
+       set_bit(KEY_DISPLAY_OFF, input->keybit);
+
+       error = input_register_device(input);
+       if (error)
+               goto err_stop_dev;
+
+       mutex_lock(&video->device_list_lock);
+       list_for_each_entry(dev, &video->video_device_list, entry)
+               acpi_video_dev_add_notify_handler(dev);
+       mutex_unlock(&video->device_list_lock);
+
+       return 0;
+
+err_stop_dev:
+       acpi_video_bus_stop_devices(video);
+err_free_input:
+       input_free_device(input);
+       video->input = NULL;
+out:
+       return error;
+}
+
+static void acpi_video_dev_remove_notify_handler(struct acpi_video_device *dev)
+{
+       if (dev->flags.notify) {
+               acpi_remove_notify_handler(dev->dev->handle, ACPI_DEVICE_NOTIFY,
+                                          acpi_video_device_notify);
+               dev->flags.notify = 0;
+       }
+}
+
+static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
+{
+       struct acpi_video_device *dev;
+
+       mutex_lock(&video->device_list_lock);
+       list_for_each_entry(dev, &video->video_device_list, entry)
+               acpi_video_dev_remove_notify_handler(dev);
+       mutex_unlock(&video->device_list_lock);
+
+       acpi_video_bus_stop_devices(video);
+       input_unregister_device(video->input);
+       video->input = NULL;
+}
+
+static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
+{
+       struct acpi_video_device *dev, *next;
+
+       mutex_lock(&video->device_list_lock);
+       list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
+               list_del(&dev->entry);
+               kfree(dev);
+       }
+       mutex_unlock(&video->device_list_lock);
+
+       return 0;
+}
+
+static int instance;
+
+static int acpi_video_bus_add(struct acpi_device *device)
+{
+       struct acpi_video_bus *video;
+       int error;
+       acpi_status status;
+
+       status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
+                               device->parent->handle, 1,
+                               acpi_video_bus_match, NULL,
+                               device, NULL);
+       if (status == AE_ALREADY_EXISTS) {
+               printk(KERN_WARNING FW_BUG
+                       "Duplicate ACPI video bus devices for the"
+                       " same VGA controller, please try module "
+                       "parameter \"video.allow_duplicates=1\""
+                       "if the current driver doesn't work.\n");
+               if (!allow_duplicates)
+                       return -ENODEV;
+       }
+
+       video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
+       if (!video)
+               return -ENOMEM;
+
+       /* a hack to fix the duplicate name "VID" problem on T61 */
+       if (!strcmp(device->pnp.bus_id, "VID")) {
+               if (instance)
+                       device->pnp.bus_id[3] = '0' + instance;
+               instance++;
+       }
+       /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
+       if (!strcmp(device->pnp.bus_id, "VGA")) {
+               if (instance)
+                       device->pnp.bus_id[3] = '0' + instance;
+               instance++;
+       }
+
+       video->device = device;
+       strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
+       strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
+       device->driver_data = video;
+
+       acpi_video_bus_find_cap(video);
+       error = acpi_video_bus_check(video);
+       if (error)
+               goto err_free_video;
+
+       mutex_init(&video->device_list_lock);
+       INIT_LIST_HEAD(&video->video_device_list);
+
+       error = acpi_video_bus_get_devices(video, device);
+       if (error)
+               goto err_put_video;
+
+       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");
+       mutex_lock(&video_list_lock);
+       list_add_tail(&video->entry, &video_bus_head);
+       mutex_unlock(&video_list_lock);
+
+       acpi_video_bus_register_backlight(video);
+       acpi_video_bus_add_notify_handler(video);
+
+       return 0;
+
+err_put_video:
+       acpi_video_bus_put_devices(video);
+       kfree(video->attached_array);
+err_free_video:
+       kfree(video);
+       device->driver_data = NULL;
+
+       return error;
+}
+
+static int acpi_video_bus_remove(struct acpi_device *device)
+{
+       struct acpi_video_bus *video = NULL;
+
+
+       if (!device || !acpi_driver_data(device))
+               return -EINVAL;
+
+       video = acpi_driver_data(device);
+
+       acpi_video_bus_remove_notify_handler(video);
+       acpi_video_bus_unregister_backlight(video);
+       acpi_video_bus_put_devices(video);
+
+       mutex_lock(&video_list_lock);
+       list_del(&video->entry);
+       mutex_unlock(&video_list_lock);
+
+       kfree(video->attached_array);
+       kfree(video);
+
+       return 0;
+}
+
+static int __init is_i740(struct pci_dev *dev)
+{
+       if (dev->device == 0x00D1)
+               return 1;
+       if (dev->device == 0x7000)
+               return 1;
+       return 0;
+}
+
+static int __init intel_opregion_present(void)
+{
+       int opregion = 0;
+       struct pci_dev *dev = NULL;
+       u32 address;
+
+       for_each_pci_dev(dev) {
+               if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
+                       continue;
+               if (dev->vendor != PCI_VENDOR_ID_INTEL)
+                       continue;
+               /* We don't want to poke around undefined i740 registers */
+               if (is_i740(dev))
+                       continue;
+               pci_read_config_dword(dev, 0xfc, &address);
+               if (!address)
+                       continue;
+               opregion = 1;
+       }
+       return opregion;
+}
+
+int acpi_video_register(void)
+{
+       int ret = 0;
+
+       mutex_lock(&register_count_mutex);
+       if (register_count) {
+               /*
+                * if the function of acpi_video_register is already called,
+                * don't register the acpi_vide_bus again and return no error.
+                */
+               goto leave;
+       }
+
+       mutex_init(&video_list_lock);
+       INIT_LIST_HEAD(&video_bus_head);
+
+       dmi_check_system(video_dmi_table);
+
+       ret = acpi_bus_register_driver(&acpi_video_bus);
+       if (ret)
+               goto leave;
+
+       /*
+        * When the acpi_video_bus is loaded successfully, increase
+        * the counter reference.
+        */
+       register_count = 1;
+
+leave:
+       mutex_unlock(&register_count_mutex);
+       return ret;
+}
+EXPORT_SYMBOL(acpi_video_register);
+
+void acpi_video_unregister(void)
+{
+       mutex_lock(&register_count_mutex);
+       if (register_count) {
+               acpi_bus_unregister_driver(&acpi_video_bus);
+               register_count = 0;
+       }
+       mutex_unlock(&register_count_mutex);
+}
+EXPORT_SYMBOL(acpi_video_unregister);
+
+void acpi_video_unregister_backlight(void)
+{
+       struct acpi_video_bus *video;
+
+       mutex_lock(&register_count_mutex);
+       if (register_count) {
+               mutex_lock(&video_list_lock);
+               list_for_each_entry(video, &video_bus_head, entry)
+                       acpi_video_bus_unregister_backlight(video);
+               mutex_unlock(&video_list_lock);
+       }
+       mutex_unlock(&register_count_mutex);
+}
+
+/*
+ * This is kind of nasty. Hardware using Intel chipsets may require
+ * the video opregion code to be run first in order to initialise
+ * state before any ACPI video calls are made. To handle this we defer
+ * registration of the video class until the opregion code has run.
+ */
+
+static int __init acpi_video_init(void)
+{
+       /*
+        * Let the module load even if ACPI is disabled (e.g. due to
+        * a broken BIOS) so that i915.ko can still be loaded on such
+        * old systems without an AcpiOpRegion.
+        *
+        * acpi_video_register() will report -ENODEV later as well due
+        * to acpi_disabled when i915.ko tries to register itself afterwards.
+        */
+       if (acpi_disabled)
+               return 0;
+
+       if (intel_opregion_present())
+               return 0;
+
+       return acpi_video_register();
+}
+
+static void __exit acpi_video_exit(void)
+{
+       acpi_video_detect_exit();
+       acpi_video_unregister();
+
+       return;
+}
+
+module_init(acpi_video_init);
+module_exit(acpi_video_exit);
index 4169bb8..43685dd 100644 (file)
@@ -231,7 +231,9 @@ void acpi_db_open_debug_file(char *name);
 acpi_status acpi_db_load_acpi_table(char *filename);
 
 acpi_status
-acpi_db_get_table_from_file(char *filename, struct acpi_table_header **table);
+acpi_db_get_table_from_file(char *filename,
+                           struct acpi_table_header **table,
+                           u8 must_be_aml_table);
 
 /*
  * dbhistry - debugger HISTORY command
index 87b2752..ffdb956 100644 (file)
@@ -352,11 +352,21 @@ struct acpi_package_info3 {
        u16 reserved;
 };
 
+struct acpi_package_info4 {
+       u8 type;
+       u8 object_type1;
+       u8 count1;
+       u8 sub_object_types;
+       u8 pkg_count;
+       u16 reserved;
+};
+
 union acpi_predefined_info {
        struct acpi_name_info info;
        struct acpi_package_info ret_info;
        struct acpi_package_info2 ret_info2;
        struct acpi_package_info3 ret_info3;
+       struct acpi_package_info4 ret_info4;
 };
 
 /* Reset to default packing */
@@ -1165,4 +1175,9 @@ struct ah_uuid {
        char *string;
 };
 
+struct ah_table {
+       char *signature;
+       char *description;
+};
+
 #endif                         /* __ACLOCAL_H__ */
index 74a390c..0cdd2fc 100644 (file)
@@ -70,6 +70,9 @@
  *
  *****************************************************************************/
 
+extern const u8 acpi_gbl_short_op_index[];
+extern const u8 acpi_gbl_long_op_index[];
+
 /*
  * psxface - Parser external interfaces
  */
index a972d11..b9474b5 100644 (file)
  *      count = 0 (optional)
  *      (Used for _DLM)
  *
+ * ACPI_PTYPE2_VAR_VAR: Variable number of subpackages, each of either a
+ *      constant or variable length. The subpackages are preceded by a
+ *      constant number of objects.
+ *      (Used for _LPI, _RDI)
+ *
  * ACPI_PTYPE2_UUID_PAIR: Each subpackage is preceded by a UUID Buffer. The UUID
  *      defines the format of the package. Zero-length parent package is
  *      allowed.
@@ -123,7 +128,8 @@ enum acpi_return_package_types {
        ACPI_PTYPE2_MIN = 8,
        ACPI_PTYPE2_REV_FIXED = 9,
        ACPI_PTYPE2_FIX_VAR = 10,
-       ACPI_PTYPE2_UUID_PAIR = 11
+       ACPI_PTYPE2_VAR_VAR = 11,
+       ACPI_PTYPE2_UUID_PAIR = 12
 };
 
 /* Support macros for users of the predefined info table */
@@ -172,7 +178,7 @@ enum acpi_return_package_types {
  * These are the names that can actually be evaluated via acpi_evaluate_object.
  * Not present in this table are the following:
  *
- *      1) Predefined/Reserved names that are never evaluated via
+ *      1) Predefined/Reserved names that are not usually evaluated via
  *         acpi_evaluate_object:
  *              _Lxx and _Exx GPE methods
  *              _Qxx EC methods
@@ -361,6 +367,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
          METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (4 Int) */
        PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_INTEGER, 4, 0, 0, 0),
 
+       {{"_BTH", METHOD_1ARGS(ACPI_TYPE_INTEGER),      /* ACPI 6.0 */
+         METHOD_NO_RETURN_VALUE}},
+
        {{"_BTM", METHOD_1ARGS(ACPI_TYPE_INTEGER),
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
@@ -390,6 +399,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
        PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER, 0,
                     0, 0, 0),
 
+       {{"_CR3", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
        {{"_CRS", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
 
@@ -445,7 +457,7 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
        {{"_DOS", METHOD_1ARGS(ACPI_TYPE_INTEGER),
          METHOD_NO_RETURN_VALUE}},
 
-       {{"_DSD", METHOD_0ARGS,
+       {{"_DSD", METHOD_0ARGS, /* ACPI 6.0 */
          METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each: 1 Buf, 1 Pkg */
        PACKAGE_INFO(ACPI_PTYPE2_UUID_PAIR, ACPI_RTYPE_BUFFER, 1,
                     ACPI_RTYPE_PACKAGE, 1, 0),
@@ -604,6 +616,12 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
          METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int(rev), n Pkg (2 Int) */
        PACKAGE_INFO(ACPI_PTYPE2_REV_FIXED, ACPI_RTYPE_INTEGER, 2, 0, 0, 0),
 
+       {{"_LPI", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (3 Int, n Pkg (10 Int/Buf) */
+       PACKAGE_INFO(ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 3,
+                    ACPI_RTYPE_INTEGER | ACPI_RTYPE_BUFFER | ACPI_RTYPE_STRING,
+                    10, 0),
+
        {{"_MAT", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
 
@@ -624,6 +642,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
                       ACPI_TYPE_INTEGER),
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
+       {{"_MTL", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
        {{"_NTT", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
@@ -716,6 +737,10 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
          METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Refs) */
        PACKAGE_INFO(ACPI_PTYPE1_VAR, ACPI_RTYPE_REFERENCE, 0, 0, 0, 0),
 
+       {{"_PRR", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Fixed-length (1 Ref) */
+       PACKAGE_INFO(ACPI_PTYPE1_FIXED, ACPI_RTYPE_REFERENCE, 1, 0, 0, 0),
+
        {{"_PRS", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
 
@@ -796,6 +821,11 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
        {{"_PXM", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
+       {{"_RDI", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (1 Int, n Pkg (m Ref)) */
+       PACKAGE_INFO(ACPI_PTYPE2_VAR_VAR, ACPI_RTYPE_INTEGER, 1,
+                    ACPI_RTYPE_REFERENCE, 0, 0),
+
        {{"_REG", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
          METHOD_NO_RETURN_VALUE}},
 
@@ -808,6 +838,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
        {{"_ROM", METHOD_2ARGS(ACPI_TYPE_INTEGER, ACPI_TYPE_INTEGER),
          METHOD_RETURNS(ACPI_RTYPE_BUFFER)}},
 
+       {{"_RST", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_NO_RETURN_VALUE}},
+
        {{"_RTV", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
@@ -935,6 +968,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
        {{"_TDL", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
+       {{"_TFP", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
+
        {{"_TIP", METHOD_1ARGS(ACPI_TYPE_INTEGER),
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
@@ -959,6 +995,9 @@ const union acpi_predefined_info acpi_gbl_predefined_methods[] = {
          METHOD_RETURNS(ACPI_RTYPE_PACKAGE)}}, /* Variable-length (Pkgs) each 5 Int with count */
        PACKAGE_INFO(ACPI_PTYPE2_COUNT, ACPI_RTYPE_INTEGER, 5, 0, 0, 0),
 
+       {{"_TSN", METHOD_0ARGS, /* ACPI 6.0 */
+         METHOD_RETURNS(ACPI_RTYPE_REFERENCE)}},
+
        {{"_TSP", METHOD_0ARGS,
          METHOD_RETURNS(ACPI_RTYPE_INTEGER)}},
 
index 2b3c5bd..d49f5c7 100644 (file)
@@ -251,7 +251,7 @@ extern const u8 _acpi_ctype[];
 #define _ACPI_DI     0x04      /* '0'-'9' */
 #define _ACPI_LO     0x02      /* 'a'-'z' */
 #define _ACPI_PU     0x10      /* punctuation */
-#define _ACPI_SP     0x08      /* space */
+#define _ACPI_SP     0x08      /* space, tab, CR, LF, VT, FF */
 #define _ACPI_UP     0x01      /* 'A'-'Z' */
 #define _ACPI_XD     0x80      /* '0'-'9', 'A'-'F', 'a'-'f' */
 
index d72565a..85bb951 100644 (file)
@@ -116,6 +116,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
        walk_state =
            acpi_ds_create_walk_state(node->owner_id, NULL, NULL, NULL);
        if (!walk_state) {
+               acpi_ps_free_op(op);
                return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
@@ -125,6 +126,7 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
                                  obj_desc->method.aml_length, NULL, 0);
        if (ACPI_FAILURE(status)) {
                acpi_ds_delete_walk_state(walk_state);
+               acpi_ps_free_op(op);
                return_ACPI_STATUS(status);
        }
 
@@ -133,9 +135,6 @@ acpi_ds_auto_serialize_method(struct acpi_namespace_node *node,
        /* Parse the method, scan for creation of named objects */
 
        status = acpi_ps_parse_aml(walk_state);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
 
        acpi_ps_delete_parse_tree(op);
        return_ACPI_STATUS(status);
index c5214de..f785ea7 100644 (file)
@@ -123,7 +123,7 @@ acpi_hw_derive_pci_id(struct acpi_pci_id *pci_id,
                      acpi_handle root_pci_device, acpi_handle pci_region)
 {
        acpi_status status;
-       struct acpi_pci_device *list_head = NULL;
+       struct acpi_pci_device *list_head;
 
        ACPI_FUNCTION_TRACE(hw_derive_pci_id);
 
@@ -177,13 +177,13 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
        acpi_handle parent_device;
        acpi_status status;
        struct acpi_pci_device *list_element;
-       struct acpi_pci_device *list_head = NULL;
 
        /*
         * Ascend namespace branch until the root_pci_device is reached, building
         * a list of device nodes. Loop will exit when either the PCI device is
         * found, or the root of the namespace is reached.
         */
+       *return_list_head = NULL;
        current_device = pci_region;
        while (1) {
                status = acpi_get_parent(current_device, &parent_device);
@@ -198,7 +198,6 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
                /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */
 
                if (parent_device == root_pci_device) {
-                       *return_list_head = list_head;
                        return (AE_OK);
                }
 
@@ -213,9 +212,9 @@ acpi_hw_build_pci_list(acpi_handle root_pci_device,
 
                /* Put new element at the head of the list */
 
-               list_element->next = list_head;
+               list_element->next = *return_list_head;
                list_element->device = parent_device;
-               list_head = list_element;
+               *return_list_head = list_element;
 
                current_device = parent_device;
        }
index 8b79958..9bb2519 100644 (file)
@@ -316,6 +316,13 @@ acpi_ns_check_package(struct acpi_evaluate_info *info,
                    acpi_ns_check_package_list(info, package, elements, count);
                break;
 
+       case ACPI_PTYPE2_VAR_VAR:
+               /*
+                * Returns a variable list of packages, each with a variable list
+                * of objects.
+                */
+               break;
+
        case ACPI_PTYPE2_UUID_PAIR:
 
                /* The package must contain pairs of (UUID + type) */
@@ -487,6 +494,12 @@ acpi_ns_check_package_list(struct acpi_evaluate_info *info,
                        }
                        break;
 
+               case ACPI_PTYPE2_VAR_VAR:
+                       /*
+                        * Each subpackage has a fixed or variable number of elements
+                        */
+                       break;
+
                case ACPI_PTYPE2_FIXED:
 
                        /* Each subpackage has a fixed length */
index 151fcd9..77d8103 100644 (file)
@@ -497,10 +497,10 @@ acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
        case ACPI_PTYPE2_MIN:
        case ACPI_PTYPE2_REV_FIXED:
        case ACPI_PTYPE2_FIX_VAR:
-
                break;
 
        default:
+       case ACPI_PTYPE2_VAR_VAR:
        case ACPI_PTYPE1_FIXED:
        case ACPI_PTYPE1_OPTION:
                return;
index 20e1a35..5831090 100644 (file)
@@ -50,9 +50,6 @@
 #define _COMPONENT          ACPI_PARSER
 ACPI_MODULE_NAME("psopinfo")
 
-extern const u8 acpi_gbl_short_op_index[];
-extern const u8 acpi_gbl_long_op_index[];
-
 static const u8 acpi_gbl_argument_count[] =
     { 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 6 };
 
index 7e1168b..857af82 100644 (file)
@@ -198,11 +198,8 @@ acpi_ut_read_table(FILE * fp,
                             table_header.length, file_size);
 
 #ifdef ACPI_ASL_COMPILER
-                       status = fl_check_for_ascii(fp, NULL, FALSE);
-                       if (ACPI_SUCCESS(status)) {
-                               acpi_os_printf
-                                   ("File appears to be ASCII only, must be binary\n");
-                       }
+                       acpi_os_printf("File is corrupt or is ASCII text -- "
+                                      "it must be a binary file\n");
 #endif
                        return (AE_BAD_HEADER);
                }
@@ -315,7 +312,7 @@ acpi_ut_read_table_from_file(char *filename, struct acpi_table_header ** table)
        /* Get the entire file */
 
        fprintf(stderr,
-               "Loading Acpi table from file %10s - Length %.8u (%06X)\n",
+               "Reading ACPI table from file %10s - Length %.8u (0x%06X)\n",
                filename, file_size, file_size);
 
        status = acpi_ut_read_table(file, table, &table_length);
index aa44827..fda8b3d 100644 (file)
@@ -75,9 +75,9 @@ char acpi_ut_hex_to_ascii_char(u64 integer, u32 position)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ut_hex_char_to_value
+ * FUNCTION:    acpi_ut_ascii_char_to_hex
  *
- * PARAMETERS:  ascii_char            - Hex character in Ascii
+ * PARAMETERS:  hex_char                - Hex character in Ascii
  *
  * RETURN:      The binary value of the ascii/hex character
  *
index 306e785..98d5787 100644 (file)
@@ -107,9 +107,16 @@ acpi_exception(const char *module_name,
        va_list arg_list;
 
        ACPI_MSG_REDIRECT_BEGIN;
-       acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ",
-                      acpi_format_exception(status));
 
+       /* For AE_OK, just print the message */
+
+       if (ACPI_SUCCESS(status)) {
+               acpi_os_printf(ACPI_MSG_EXCEPTION);
+
+       } else {
+               acpi_os_printf(ACPI_MSG_EXCEPTION "%s, ",
+                              acpi_format_exception(status));
+       }
        va_start(arg_list, format);
        acpi_os_vprintf(format, arg_list);
        ACPI_MSG_SUFFIX;
index e82d097..2bfd53c 100644 (file)
@@ -729,10 +729,10 @@ static struct llist_head ghes_estatus_llist;
 static struct irq_work ghes_proc_irq_work;
 
 /*
- * NMI may be triggered on any CPU, so ghes_nmi_lock is used for
- * mutual exclusion.
+ * NMI may be triggered on any CPU, so ghes_in_nmi is used for
+ * having only one concurrent reader.
  */
-static DEFINE_RAW_SPINLOCK(ghes_nmi_lock);
+static atomic_t ghes_in_nmi = ATOMIC_INIT(0);
 
 static LIST_HEAD(ghes_nmi);
 
@@ -797,73 +797,75 @@ static void ghes_print_queued_estatus(void)
        }
 }
 
+/* Save estatus for further processing in IRQ context */
+static void __process_error(struct ghes *ghes)
+{
+#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
+       u32 len, node_len;
+       struct ghes_estatus_node *estatus_node;
+       struct acpi_hest_generic_status *estatus;
+
+       if (ghes_estatus_cached(ghes->estatus))
+               return;
+
+       len = cper_estatus_len(ghes->estatus);
+       node_len = GHES_ESTATUS_NODE_LEN(len);
+
+       estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool, node_len);
+       if (!estatus_node)
+               return;
+
+       estatus_node->ghes = ghes;
+       estatus_node->generic = ghes->generic;
+       estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
+       memcpy(estatus, ghes->estatus, len);
+       llist_add(&estatus_node->llnode, &ghes_estatus_llist);
+#endif
+}
+
+static void __ghes_panic(struct ghes *ghes)
+{
+       oops_begin();
+       ghes_print_queued_estatus();
+       __ghes_print_estatus(KERN_EMERG, ghes->generic, ghes->estatus);
+
+       /* reboot to log the error! */
+       if (panic_timeout == 0)
+               panic_timeout = ghes_panic_timeout;
+       panic("Fatal hardware error!");
+}
+
 static int ghes_notify_nmi(unsigned int cmd, struct pt_regs *regs)
 {
-       struct ghes *ghes, *ghes_global = NULL;
-       int sev, sev_global = -1;
-       int ret = NMI_DONE;
+       struct ghes *ghes;
+       int sev, ret = NMI_DONE;
+
+       if (!atomic_add_unless(&ghes_in_nmi, 1, 1))
+               return ret;
 
-       raw_spin_lock(&ghes_nmi_lock);
        list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
                if (ghes_read_estatus(ghes, 1)) {
                        ghes_clear_estatus(ghes);
                        continue;
                }
-               sev = ghes_severity(ghes->estatus->error_severity);
-               if (sev > sev_global) {
-                       sev_global = sev;
-                       ghes_global = ghes;
-               }
-               ret = NMI_HANDLED;
-       }
-
-       if (ret == NMI_DONE)
-               goto out;
 
-       if (sev_global >= GHES_SEV_PANIC) {
-               oops_begin();
-               ghes_print_queued_estatus();
-               __ghes_print_estatus(KERN_EMERG, ghes_global->generic,
-                                    ghes_global->estatus);
-               /* reboot to log the error! */
-               if (panic_timeout == 0)
-                       panic_timeout = ghes_panic_timeout;
-               panic("Fatal hardware error!");
-       }
+               sev = ghes_severity(ghes->estatus->error_severity);
+               if (sev >= GHES_SEV_PANIC)
+                       __ghes_panic(ghes);
 
-       list_for_each_entry_rcu(ghes, &ghes_nmi, list) {
-#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
-               u32 len, node_len;
-               struct ghes_estatus_node *estatus_node;
-               struct acpi_hest_generic_status *estatus;
-#endif
                if (!(ghes->flags & GHES_TO_CLEAR))
                        continue;
-#ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
-               if (ghes_estatus_cached(ghes->estatus))
-                       goto next;
-               /* Save estatus for further processing in IRQ context */
-               len = cper_estatus_len(ghes->estatus);
-               node_len = GHES_ESTATUS_NODE_LEN(len);
-               estatus_node = (void *)gen_pool_alloc(ghes_estatus_pool,
-                                                     node_len);
-               if (estatus_node) {
-                       estatus_node->ghes = ghes;
-                       estatus_node->generic = ghes->generic;
-                       estatus = GHES_ESTATUS_FROM_NODE(estatus_node);
-                       memcpy(estatus, ghes->estatus, len);
-                       llist_add(&estatus_node->llnode, &ghes_estatus_llist);
-               }
-next:
-#endif
+
+               __process_error(ghes);
                ghes_clear_estatus(ghes);
+
+               ret = NMI_HANDLED;
        }
+
 #ifdef CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG
        irq_work_queue(&ghes_proc_irq_work);
 #endif
-
-out:
-       raw_spin_unlock(&ghes_nmi_lock);
+       atomic_dec(&ghes_in_nmi);
        return ret;
 }
 
index 63d4367..b3628cc 100644 (file)
@@ -70,6 +70,7 @@ MODULE_AUTHOR("Alexey Starikovskiy <astarikovskiy@suse.de>");
 MODULE_DESCRIPTION("ACPI Battery Driver");
 MODULE_LICENSE("GPL");
 
+static async_cookie_t async_cookie;
 static int battery_bix_broken_package;
 static int battery_notification_delay_ms;
 static unsigned int cache_time = 1000;
@@ -338,14 +339,6 @@ static enum power_supply_property energy_battery_props[] = {
        POWER_SUPPLY_PROP_SERIAL_NUMBER,
 };
 
-#ifdef CONFIG_ACPI_PROCFS_POWER
-inline char *acpi_battery_units(struct acpi_battery *battery)
-{
-       return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ?
-               "mA" : "mW";
-}
-#endif
-
 /* --------------------------------------------------------------------------
                                Battery Management
    -------------------------------------------------------------------------- */
@@ -354,14 +347,14 @@ struct acpi_offsets {
        u8 mode;                /* int or string? */
 };
 
-static struct acpi_offsets state_offsets[] = {
+static const struct acpi_offsets state_offsets[] = {
        {offsetof(struct acpi_battery, state), 0},
        {offsetof(struct acpi_battery, rate_now), 0},
        {offsetof(struct acpi_battery, capacity_now), 0},
        {offsetof(struct acpi_battery, voltage_now), 0},
 };
 
-static struct acpi_offsets info_offsets[] = {
+static const struct acpi_offsets info_offsets[] = {
        {offsetof(struct acpi_battery, power_unit), 0},
        {offsetof(struct acpi_battery, design_capacity), 0},
        {offsetof(struct acpi_battery, full_charge_capacity), 0},
@@ -377,7 +370,7 @@ static struct acpi_offsets info_offsets[] = {
        {offsetof(struct acpi_battery, oem_info), 1},
 };
 
-static struct acpi_offsets extended_info_offsets[] = {
+static const struct acpi_offsets extended_info_offsets[] = {
        {offsetof(struct acpi_battery, revision), 0},
        {offsetof(struct acpi_battery, power_unit), 0},
        {offsetof(struct acpi_battery, design_capacity), 0},
@@ -402,7 +395,7 @@ static struct acpi_offsets extended_info_offsets[] = {
 
 static int extract_package(struct acpi_battery *battery,
                           union acpi_object *package,
-                          struct acpi_offsets *offsets, int num)
+                          const struct acpi_offsets *offsets, int num)
 {
        int i;
        union acpi_object *element;
@@ -792,6 +785,12 @@ static void acpi_battery_refresh(struct acpi_battery *battery)
 #ifdef CONFIG_ACPI_PROCFS_POWER
 static struct proc_dir_entry *acpi_battery_dir;
 
+static const char *acpi_battery_units(const struct acpi_battery *battery)
+{
+       return (battery->power_unit == ACPI_BATTERY_POWER_UNIT_MA) ?
+               "mA" : "mW";
+}
+
 static int acpi_battery_print_info(struct seq_file *seq, int result)
 {
        struct acpi_battery *battery = seq->private;
@@ -1125,19 +1124,21 @@ static int battery_notify(struct notifier_block *nb,
        return 0;
 }
 
-static int battery_bix_broken_package_quirk(const struct dmi_system_id *d)
+static int __init
+battery_bix_broken_package_quirk(const struct dmi_system_id *d)
 {
        battery_bix_broken_package = 1;
        return 0;
 }
 
-static int battery_notification_delay_quirk(const struct dmi_system_id *d)
+static int __init
+battery_notification_delay_quirk(const struct dmi_system_id *d)
 {
        battery_notification_delay_ms = 1000;
        return 0;
 }
 
-static struct dmi_system_id bat_dmi_table[] = {
+static const struct dmi_system_id bat_dmi_table[] __initconst = {
        {
                .callback = battery_bix_broken_package_quirk,
                .ident = "NEC LZ750/LS",
@@ -1292,33 +1293,34 @@ static struct acpi_driver acpi_battery_driver = {
 
 static void __init acpi_battery_init_async(void *unused, async_cookie_t cookie)
 {
-       if (acpi_disabled)
-               return;
+       int result;
 
        dmi_check_system(bat_dmi_table);
-       
+
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_battery_dir = acpi_lock_battery_dir();
        if (!acpi_battery_dir)
                return;
 #endif
-       if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {
+       result = acpi_bus_register_driver(&acpi_battery_driver);
 #ifdef CONFIG_ACPI_PROCFS_POWER
+       if (result < 0)
                acpi_unlock_battery_dir(acpi_battery_dir);
 #endif
-               return;
-       }
-       return;
 }
 
 static int __init acpi_battery_init(void)
 {
-       async_schedule(acpi_battery_init_async, NULL);
+       if (acpi_disabled)
+               return -ENODEV;
+
+       async_cookie = async_schedule(acpi_battery_init_async, NULL);
        return 0;
 }
 
 static void __exit acpi_battery_exit(void)
 {
+       async_synchronize_cookie(async_cookie);
        acpi_bus_unregister_driver(&acpi_battery_driver);
 #ifdef CONFIG_ACPI_PROCFS_POWER
        acpi_unlock_battery_dir(acpi_battery_dir);
index c412fdb..513e723 100644 (file)
@@ -470,6 +470,16 @@ static int __init acpi_bus_init_irq(void)
        return 0;
 }
 
+/**
+ * acpi_early_init - Initialize ACPICA and populate the ACPI namespace.
+ *
+ * The ACPI tables are accessible after this, but the handling of events has not
+ * been initialized and the global lock is not available yet, so AML should not
+ * be executed at this point.
+ *
+ * Doing this before switching the EFI runtime services to virtual mode allows
+ * the EfiBootServices memory to be freed slightly earlier on boot.
+ */
 void __init acpi_early_init(void)
 {
        acpi_status status;
@@ -533,26 +543,42 @@ void __init acpi_early_init(void)
                acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
        }
 #endif
+       return;
+
+ error0:
+       disable_acpi();
+}
+
+/**
+ * acpi_subsystem_init - Finalize the early initialization of ACPI.
+ *
+ * Switch over the platform to the ACPI mode (if possible), initialize the
+ * handling of ACPI events, install the interrupt and global lock handlers.
+ *
+ * Doing this too early is generally unsafe, but at the same time it needs to be
+ * done before all things that really depend on ACPI.  The right spot appears to
+ * be before finalizing the EFI initialization.
+ */
+void __init acpi_subsystem_init(void)
+{
+       acpi_status status;
+
+       if (acpi_disabled)
+               return;
 
        status = acpi_enable_subsystem(~ACPI_NO_ACPI_ENABLE);
        if (ACPI_FAILURE(status)) {
                printk(KERN_ERR PREFIX "Unable to enable ACPI\n");
-               goto error0;
+               disable_acpi();
+       } else {
+               /*
+                * If the system is using ACPI then we can be reasonably
+                * confident that any regulators are managed by the firmware
+                * so tell the regulator core it has everything it needs to
+                * know.
+                */
+               regulator_has_full_constraints();
        }
-
-       /*
-        * If the system is using ACPI then we can be reasonably
-        * confident that any regulators are managed by the firmware
-        * so tell the regulator core it has everything it needs to
-        * know.
-        */
-       regulator_has_full_constraints();
-
-       return;
-
-      error0:
-       disable_acpi();
-       return;
 }
 
 static int __init acpi_bus_init(void)
index 735db11..717afcd 100644 (file)
@@ -98,17 +98,16 @@ int acpi_device_get_power(struct acpi_device *device, int *state)
 
                /*
                 * The power resources settings may indicate a power state
-                * shallower than the actual power state of the device.
+                * shallower than the actual power state of the device, because
+                * the same power resources may be referenced by other devices.
                 *
-                * Moreover, on systems predating ACPI 4.0, if the device
-                * doesn't depend on any power resources and _PSC returns 3,
-                * that means "power off".  We need to maintain compatibility
-                * with those systems.
+                * For systems predating ACPI 4.0 we assume that D3hot is the
+                * deepest state that can be supported.
                 */
                if (psc > result && psc < ACPI_STATE_D3_COLD)
                        result = psc;
                else if (result == ACPI_STATE_UNKNOWN)
-                       result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_COLD : psc;
+                       result = psc > ACPI_STATE_D2 ? ACPI_STATE_D3_HOT : psc;
        }
 
        /*
@@ -153,8 +152,8 @@ static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state)
  */
 int acpi_device_set_power(struct acpi_device *device, int state)
 {
+       int target_state = state;
        int result = 0;
-       bool cut_power = false;
 
        if (!device || !device->flags.power_manageable
            || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD))
@@ -169,11 +168,21 @@ int acpi_device_set_power(struct acpi_device *device, int state)
                return 0;
        }
 
-       if (!device->power.states[state].flags.valid) {
+       if (state == ACPI_STATE_D3_COLD) {
+               /*
+                * For transitions to D3cold we need to execute _PS3 and then
+                * possibly drop references to the power resources in use.
+                */
+               state = ACPI_STATE_D3_HOT;
+               /* If _PR3 is not available, use D3hot as the target state. */
+               if (!device->power.states[ACPI_STATE_D3_COLD].flags.valid)
+                       target_state = state;
+       } else if (!device->power.states[state].flags.valid) {
                dev_warn(&device->dev, "Power state %s not supported\n",
                         acpi_power_state_string(state));
                return -ENODEV;
        }
+
        if (!device->power.flags.ignore_parent &&
            device->parent && (state < device->parent->power.state)) {
                dev_warn(&device->dev,
@@ -183,39 +192,38 @@ int acpi_device_set_power(struct acpi_device *device, int state)
                return -ENODEV;
        }
 
-       /* For D3cold we should first transition into D3hot. */
-       if (state == ACPI_STATE_D3_COLD
-           && device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible) {
-               state = ACPI_STATE_D3_HOT;
-               cut_power = true;
-       }
-
-       if (state < device->power.state && state != ACPI_STATE_D0
-           && device->power.state >= ACPI_STATE_D3_HOT) {
-               dev_warn(&device->dev,
-                        "Cannot transition to non-D0 state from D3\n");
-               return -ENODEV;
-       }
-
        /*
         * Transition Power
         * ----------------
-        * In accordance with the ACPI specification first apply power (via
-        * power resources) and then evaluate _PSx.
+        * In accordance with ACPI 6, _PSx is executed before manipulating power
+        * resources, unless the target state is D0, in which case _PS0 is
+        * supposed to be executed after turning the power resources on.
         */
-       if (device->power.flags.power_resources) {
-               result = acpi_power_transition(device, state);
+       if (state > ACPI_STATE_D0) {
+               /*
+                * According to ACPI 6, devices cannot go from lower-power
+                * (deeper) states to higher-power (shallower) states.
+                */
+               if (state < device->power.state) {
+                       dev_warn(&device->dev, "Cannot transition from %s to %s\n",
+                                acpi_power_state_string(device->power.state),
+                                acpi_power_state_string(state));
+                       return -ENODEV;
+               }
+
+               result = acpi_dev_pm_explicit_set(device, state);
                if (result)
                        goto end;
-       }
-       result = acpi_dev_pm_explicit_set(device, state);
-       if (result)
-               goto end;
 
-       if (cut_power) {
-               device->power.state = state;
-               state = ACPI_STATE_D3_COLD;
-               result = acpi_power_transition(device, state);
+               if (device->power.flags.power_resources)
+                       result = acpi_power_transition(device, target_state);
+       } else {
+               if (device->power.flags.power_resources) {
+                       result = acpi_power_transition(device, ACPI_STATE_D0);
+                       if (result)
+                               goto end;
+               }
+               result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0);
        }
 
  end:
@@ -264,13 +272,24 @@ int acpi_bus_init_power(struct acpi_device *device)
                return result;
 
        if (state < ACPI_STATE_D3_COLD && device->power.flags.power_resources) {
+               /* Reference count the power resources. */
                result = acpi_power_on_resources(device, state);
                if (result)
                        return result;
 
-               result = acpi_dev_pm_explicit_set(device, state);
-               if (result)
-                       return result;
+               if (state == ACPI_STATE_D0) {
+                       /*
+                        * If _PSC is not present and the state inferred from
+                        * power resources appears to be D0, it still may be
+                        * necessary to execute _PS0 at this point, because
+                        * another device using the same power resources may
+                        * have been put into D0 previously and that's why we
+                        * see D0 here.
+                        */
+                       result = acpi_dev_pm_explicit_set(device, state);
+                       if (result)
+                               return result;
+               }
        } else if (state == ACPI_STATE_UNKNOWN) {
                /*
                 * No power resources and missing _PSC?  Cross fingers and make
@@ -603,12 +622,12 @@ int acpi_pm_device_sleep_state(struct device *dev, int *d_min_p, int d_max_in)
        if (d_max_in < ACPI_STATE_D0 || d_max_in > ACPI_STATE_D3_COLD)
                return -EINVAL;
 
-       if (d_max_in > ACPI_STATE_D3_HOT) {
+       if (d_max_in > ACPI_STATE_D2) {
                enum pm_qos_flags_status stat;
 
                stat = dev_pm_qos_flags(dev, PM_QOS_FLAG_NO_POWER_OFF);
                if (stat == PM_QOS_FLAGS_ALL)
-                       d_max_in = ACPI_STATE_D3_HOT;
+                       d_max_in = ACPI_STATE_D2;
        }
 
        adev = ACPI_COMPANION(dev);
@@ -953,6 +972,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_prepare);
  */
 void acpi_subsys_complete(struct device *dev)
 {
+       pm_generic_complete(dev);
        /*
         * If the device had been runtime-suspended before the system went into
         * the sleep state it is going out of and it has never been resumed till
index 5e8fed4..9d4761d 100644 (file)
 #define ACPI_EC_FLAG_BURST     0x10    /* burst mode */
 #define ACPI_EC_FLAG_SCI       0x20    /* EC-SCI occurred */
 
+/*
+ * The SCI_EVT clearing timing is not defined by the ACPI specification.
+ * This leads to lots of practical timing issues for the host EC driver.
+ * The following variations are defined (from the target EC firmware's
+ * perspective):
+ * STATUS: After indicating SCI_EVT edge triggered IRQ to the host, the
+ *         target can clear SCI_EVT at any time so long as the host can see
+ *         the indication by reading the status register (EC_SC). So the
+ *         host should re-check SCI_EVT after the first time the SCI_EVT
+ *         indication is seen, which is the same time the query request
+ *         (QR_EC) is written to the command register (EC_CMD). SCI_EVT set
+ *         at any later time could indicate another event. Normally such
+ *         kind of EC firmware has implemented an event queue and will
+ *         return 0x00 to indicate "no outstanding event".
+ * QUERY: After seeing the query request (QR_EC) written to the command
+ *        register (EC_CMD) by the host and having prepared the responding
+ *        event value in the data register (EC_DATA), the target can safely
+ *        clear SCI_EVT because the target can confirm that the current
+ *        event is being handled by the host. The host then should check
+ *        SCI_EVT right after reading the event response from the data
+ *        register (EC_DATA).
+ * EVENT: After seeing the event response read from the data register
+ *        (EC_DATA) by the host, the target can clear SCI_EVT. As the
+ *        target requires time to notice the change in the data register
+ *        (EC_DATA), the host may be required to wait additional guarding
+ *        time before checking the SCI_EVT again. Such guarding may not be
+ *        necessary if the host is notified via another IRQ.
+ */
+#define ACPI_EC_EVT_TIMING_STATUS      0x00
+#define ACPI_EC_EVT_TIMING_QUERY       0x01
+#define ACPI_EC_EVT_TIMING_EVENT       0x02
+
 /* EC commands */
 enum ec_command {
        ACPI_EC_COMMAND_READ = 0x80,
@@ -70,13 +102,13 @@ enum ec_command {
 
 #define ACPI_EC_DELAY          500     /* Wait 500ms max. during EC ops */
 #define ACPI_EC_UDELAY_GLK     1000    /* Wait 1ms max. to get global lock */
-#define ACPI_EC_MSI_UDELAY     550     /* Wait 550us for MSI EC */
-#define ACPI_EC_UDELAY_POLL    1000    /* Wait 1ms for EC transaction polling */
+#define ACPI_EC_UDELAY_POLL    550     /* Wait 1ms for EC transaction polling */
 #define ACPI_EC_CLEAR_MAX      100     /* Maximum number of events to query
                                         * when trying to clear the EC */
 
 enum {
        EC_FLAGS_QUERY_PENDING,         /* Query is pending */
+       EC_FLAGS_QUERY_GUARDING,        /* Guard for SCI_EVT check */
        EC_FLAGS_HANDLERS_INSTALLED,    /* Handlers for GPE and
                                         * OpReg are installed */
        EC_FLAGS_STARTED,               /* Driver is started */
@@ -93,6 +125,16 @@ static unsigned int ec_delay __read_mostly = ACPI_EC_DELAY;
 module_param(ec_delay, uint, 0644);
 MODULE_PARM_DESC(ec_delay, "Timeout(ms) waited until an EC command completes");
 
+static bool ec_busy_polling __read_mostly;
+module_param(ec_busy_polling, bool, 0644);
+MODULE_PARM_DESC(ec_busy_polling, "Use busy polling to advance EC transaction");
+
+static unsigned int ec_polling_guard __read_mostly = ACPI_EC_UDELAY_POLL;
+module_param(ec_polling_guard, uint, 0644);
+MODULE_PARM_DESC(ec_polling_guard, "Guard time(us) between EC accesses in polling modes");
+
+static unsigned int ec_event_clearing __read_mostly = ACPI_EC_EVT_TIMING_QUERY;
+
 /*
  * If the number of false interrupts per one transaction exceeds
  * this threshold, will think there is a GPE storm happened and
@@ -121,7 +163,6 @@ struct transaction {
        u8 wlen;
        u8 rlen;
        u8 flags;
-       unsigned long timestamp;
 };
 
 static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
@@ -130,7 +171,6 @@ static void advance_transaction(struct acpi_ec *ec);
 struct acpi_ec *boot_ec, *first_ec;
 EXPORT_SYMBOL(first_ec);
 
-static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
 static int EC_FLAGS_VALIDATE_ECDT; /* ASUStec ECDTs need to be validated */
 static int EC_FLAGS_SKIP_DSDT_SCAN; /* Not all BIOS survive early DSDT scan */
 static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
@@ -218,7 +258,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
 {
        u8 x = inb(ec->data_addr);
 
-       ec->curr->timestamp = jiffies;
+       ec->timestamp = jiffies;
        ec_dbg_raw("EC_DATA(R) = 0x%2.2x", x);
        return x;
 }
@@ -227,14 +267,14 @@ static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
 {
        ec_dbg_raw("EC_SC(W) = 0x%2.2x", command);
        outb(command, ec->command_addr);
-       ec->curr->timestamp = jiffies;
+       ec->timestamp = jiffies;
 }
 
 static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
 {
        ec_dbg_raw("EC_DATA(W) = 0x%2.2x", data);
        outb(data, ec->data_addr);
-       ec->curr->timestamp = jiffies;
+       ec->timestamp = jiffies;
 }
 
 #ifdef DEBUG
@@ -267,7 +307,7 @@ static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec)
        acpi_event_status gpe_status = 0;
 
        (void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
-       return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false;
+       return (gpe_status & ACPI_EVENT_FLAG_STATUS_SET) ? true : false;
 }
 
 static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
@@ -379,19 +419,49 @@ static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
 static void acpi_ec_submit_query(struct acpi_ec *ec)
 {
        if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
-               ec_dbg_req("Event started");
+               ec_dbg_evt("Command(%s) submitted/blocked",
+                          acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
+               ec->nr_pending_queries++;
                schedule_work(&ec->work);
        }
 }
 
 static void acpi_ec_complete_query(struct acpi_ec *ec)
 {
-       if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
+       if (test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
                clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
-               ec_dbg_req("Event stopped");
+               ec_dbg_evt("Command(%s) unblocked",
+                          acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
        }
 }
 
+static bool acpi_ec_guard_event(struct acpi_ec *ec)
+{
+       if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
+           ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY ||
+           !test_bit(EC_FLAGS_QUERY_PENDING, &ec->flags) ||
+           (ec->curr && ec->curr->command == ACPI_EC_COMMAND_QUERY))
+               return false;
+
+       /*
+        * Postpone the query submission to allow the firmware to proceed,
+        * we shouldn't check SCI_EVT before the firmware reflagging it.
+        */
+       return true;
+}
+
+static int ec_transaction_polled(struct acpi_ec *ec)
+{
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&ec->lock, flags);
+       if (ec->curr && (ec->curr->flags & ACPI_EC_COMMAND_POLL))
+               ret = 1;
+       spin_unlock_irqrestore(&ec->lock, flags);
+       return ret;
+}
+
 static int ec_transaction_completed(struct acpi_ec *ec)
 {
        unsigned long flags;
@@ -404,6 +474,22 @@ static int ec_transaction_completed(struct acpi_ec *ec)
        return ret;
 }
 
+static inline void ec_transaction_transition(struct acpi_ec *ec, unsigned long flag)
+{
+       ec->curr->flags |= flag;
+       if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
+               if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS &&
+                   flag == ACPI_EC_COMMAND_POLL)
+                       acpi_ec_complete_query(ec);
+               if (ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY &&
+                   flag == ACPI_EC_COMMAND_COMPLETE)
+                       acpi_ec_complete_query(ec);
+               if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
+                   flag == ACPI_EC_COMMAND_COMPLETE)
+                       set_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
+       }
+}
+
 static void advance_transaction(struct acpi_ec *ec)
 {
        struct transaction *t;
@@ -420,6 +506,18 @@ static void advance_transaction(struct acpi_ec *ec)
        acpi_ec_clear_gpe(ec);
        status = acpi_ec_read_status(ec);
        t = ec->curr;
+       /*
+        * Another IRQ or a guarded polling mode advancement is detected,
+        * the next QR_EC submission is then allowed.
+        */
+       if (!t || !(t->flags & ACPI_EC_COMMAND_POLL)) {
+               if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT &&
+                   (!ec->nr_pending_queries ||
+                    test_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags))) {
+                       clear_bit(EC_FLAGS_QUERY_GUARDING, &ec->flags);
+                       acpi_ec_complete_query(ec);
+               }
+       }
        if (!t)
                goto err;
        if (t->flags & ACPI_EC_COMMAND_POLL) {
@@ -432,17 +530,17 @@ static void advance_transaction(struct acpi_ec *ec)
                        if ((status & ACPI_EC_FLAG_OBF) == 1) {
                                t->rdata[t->ri++] = acpi_ec_read_data(ec);
                                if (t->rlen == t->ri) {
-                                       t->flags |= ACPI_EC_COMMAND_COMPLETE;
+                                       ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
                                        if (t->command == ACPI_EC_COMMAND_QUERY)
-                                               ec_dbg_req("Command(%s) hardware completion",
-                                                          acpi_ec_cmd_string(t->command));
+                                               ec_dbg_evt("Command(%s) completed by hardware",
+                                                          acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
                                        wakeup = true;
                                }
                        } else
                                goto err;
                } else if (t->wlen == t->wi &&
                           (status & ACPI_EC_FLAG_IBF) == 0) {
-                       t->flags |= ACPI_EC_COMMAND_COMPLETE;
+                       ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
                        wakeup = true;
                }
                goto out;
@@ -450,17 +548,15 @@ static void advance_transaction(struct acpi_ec *ec)
                if (EC_FLAGS_QUERY_HANDSHAKE &&
                    !(status & ACPI_EC_FLAG_SCI) &&
                    (t->command == ACPI_EC_COMMAND_QUERY)) {
-                       t->flags |= ACPI_EC_COMMAND_POLL;
-                       acpi_ec_complete_query(ec);
+                       ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
                        t->rdata[t->ri++] = 0x00;
-                       t->flags |= ACPI_EC_COMMAND_COMPLETE;
-                       ec_dbg_req("Command(%s) software completion",
-                                  acpi_ec_cmd_string(t->command));
+                       ec_transaction_transition(ec, ACPI_EC_COMMAND_COMPLETE);
+                       ec_dbg_evt("Command(%s) completed by software",
+                                  acpi_ec_cmd_string(ACPI_EC_COMMAND_QUERY));
                        wakeup = true;
                } else if ((status & ACPI_EC_FLAG_IBF) == 0) {
                        acpi_ec_write_cmd(ec, t->command);
-                       t->flags |= ACPI_EC_COMMAND_POLL;
-                       acpi_ec_complete_query(ec);
+                       ec_transaction_transition(ec, ACPI_EC_COMMAND_POLL);
                } else
                        goto err;
                goto out;
@@ -490,8 +586,39 @@ static void start_transaction(struct acpi_ec *ec)
 {
        ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
        ec->curr->flags = 0;
-       ec->curr->timestamp = jiffies;
-       advance_transaction(ec);
+}
+
+static int ec_guard(struct acpi_ec *ec)
+{
+       unsigned long guard = usecs_to_jiffies(ec_polling_guard);
+       unsigned long timeout = ec->timestamp + guard;
+
+       do {
+               if (ec_busy_polling) {
+                       /* Perform busy polling */
+                       if (ec_transaction_completed(ec))
+                               return 0;
+                       udelay(jiffies_to_usecs(guard));
+               } else {
+                       /*
+                        * Perform wait polling
+                        *
+                        * For SCI_EVT clearing timing of "event",
+                        * performing guarding before re-checking the
+                        * SCI_EVT. Otherwise, such guarding is not needed
+                        * due to the old practices.
+                        */
+                       if (!ec_transaction_polled(ec) &&
+                           !acpi_ec_guard_event(ec))
+                               break;
+                       if (wait_event_timeout(ec->wait,
+                                              ec_transaction_completed(ec),
+                                              guard))
+                               return 0;
+               }
+               /* Guard the register accesses for the polling modes */
+       } while (time_before(jiffies, timeout));
+       return -ETIME;
 }
 
 static int ec_poll(struct acpi_ec *ec)
@@ -502,25 +629,11 @@ static int ec_poll(struct acpi_ec *ec)
        while (repeat--) {
                unsigned long delay = jiffies +
                        msecs_to_jiffies(ec_delay);
-               unsigned long usecs = ACPI_EC_UDELAY_POLL;
                do {
-                       /* don't sleep with disabled interrupts */
-                       if (EC_FLAGS_MSI || irqs_disabled()) {
-                               usecs = ACPI_EC_MSI_UDELAY;
-                               udelay(usecs);
-                               if (ec_transaction_completed(ec))
-                                       return 0;
-                       } else {
-                               if (wait_event_timeout(ec->wait,
-                                               ec_transaction_completed(ec),
-                                               usecs_to_jiffies(usecs)))
-                                       return 0;
-                       }
+                       if (!ec_guard(ec))
+                               return 0;
                        spin_lock_irqsave(&ec->lock, flags);
-                       if (time_after(jiffies,
-                                       ec->curr->timestamp +
-                                       usecs_to_jiffies(usecs)))
-                               advance_transaction(ec);
+                       advance_transaction(ec);
                        spin_unlock_irqrestore(&ec->lock, flags);
                } while (time_before(jiffies, delay));
                pr_debug("controller reset, restart transaction\n");
@@ -537,8 +650,6 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
        unsigned long tmp;
        int ret = 0;
 
-       if (EC_FLAGS_MSI)
-               udelay(ACPI_EC_MSI_UDELAY);
        /* start transaction */
        spin_lock_irqsave(&ec->lock, tmp);
        /* Enable GPE for command processing (IBF=0/OBF=1) */
@@ -552,7 +663,9 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
        ec_dbg_req("Command(%s) started", acpi_ec_cmd_string(t->command));
        start_transaction(ec);
        spin_unlock_irqrestore(&ec->lock, tmp);
+
        ret = ec_poll(ec);
+
        spin_lock_irqsave(&ec->lock, tmp);
        if (t->irq_count == ec_storm_threshold)
                acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
@@ -575,6 +688,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
                return -EINVAL;
        if (t->rdata)
                memset(t->rdata, 0, t->rlen);
+
        mutex_lock(&ec->mutex);
        if (ec->global_lock) {
                status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
@@ -586,8 +700,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
 
        status = acpi_ec_transaction_unlocked(ec, t);
 
-       if (test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
-               msleep(1);
        if (ec->global_lock)
                acpi_release_global_lock(glk);
 unlock:
@@ -923,11 +1035,54 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
        return result;
 }
 
-static void acpi_ec_gpe_poller(struct work_struct *work)
+static void acpi_ec_check_event(struct acpi_ec *ec)
 {
+       unsigned long flags;
+
+       if (ec_event_clearing == ACPI_EC_EVT_TIMING_EVENT) {
+               if (ec_guard(ec)) {
+                       spin_lock_irqsave(&ec->lock, flags);
+                       /*
+                        * Take care of the SCI_EVT unless no one else is
+                        * taking care of it.
+                        */
+                       if (!ec->curr)
+                               advance_transaction(ec);
+                       spin_unlock_irqrestore(&ec->lock, flags);
+               }
+       }
+}
+
+static void acpi_ec_event_handler(struct work_struct *work)
+{
+       unsigned long flags;
        struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
 
-       acpi_ec_query(ec, NULL);
+       ec_dbg_evt("Event started");
+
+       spin_lock_irqsave(&ec->lock, flags);
+       while (ec->nr_pending_queries) {
+               spin_unlock_irqrestore(&ec->lock, flags);
+               (void)acpi_ec_query(ec, NULL);
+               spin_lock_irqsave(&ec->lock, flags);
+               ec->nr_pending_queries--;
+               /*
+                * Before exit, make sure that this work item can be
+                * scheduled again. There might be QR_EC failures, leaving
+                * EC_FLAGS_QUERY_PENDING uncleared and preventing this work
+                * item from being scheduled again.
+                */
+               if (!ec->nr_pending_queries) {
+                       if (ec_event_clearing == ACPI_EC_EVT_TIMING_STATUS ||
+                           ec_event_clearing == ACPI_EC_EVT_TIMING_QUERY)
+                               acpi_ec_complete_query(ec);
+               }
+       }
+       spin_unlock_irqrestore(&ec->lock, flags);
+
+       ec_dbg_evt("Event stopped");
+
+       acpi_ec_check_event(ec);
 }
 
 static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
@@ -961,7 +1116,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
        if (function != ACPI_READ && function != ACPI_WRITE)
                return AE_BAD_PARAMETER;
 
-       if (EC_FLAGS_MSI || bits > 8)
+       if (ec_busy_polling || bits > 8)
                acpi_ec_burst_enable(ec);
 
        for (i = 0; i < bytes; ++i, ++address, ++value)
@@ -969,7 +1124,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
                        acpi_ec_read(ec, address, value) :
                        acpi_ec_write(ec, address, *value);
 
-       if (EC_FLAGS_MSI || bits > 8)
+       if (ec_busy_polling || bits > 8)
                acpi_ec_burst_disable(ec);
 
        switch (result) {
@@ -1002,7 +1157,8 @@ static struct acpi_ec *make_acpi_ec(void)
        init_waitqueue_head(&ec->wait);
        INIT_LIST_HEAD(&ec->list);
        spin_lock_init(&ec->lock);
-       INIT_WORK(&ec->work, acpi_ec_gpe_poller);
+       INIT_WORK(&ec->work, acpi_ec_event_handler);
+       ec->timestamp = jiffies;
        return ec;
 }
 
@@ -1237,30 +1393,13 @@ static int ec_validate_ecdt(const struct dmi_system_id *id)
        return 0;
 }
 
-/* MSI EC needs special treatment, enable it */
-static int ec_flag_msi(const struct dmi_system_id *id)
-{
-       pr_debug("Detected MSI hardware, enabling workarounds.\n");
-       EC_FLAGS_MSI = 1;
-       EC_FLAGS_VALIDATE_ECDT = 1;
-       return 0;
-}
-
-/*
- * Clevo M720 notebook actually works ok with IRQ mode, if we lifted
- * the GPE storm threshold back to 20
- */
-static int ec_enlarge_storm_threshold(const struct dmi_system_id *id)
-{
-       pr_debug("Setting the EC GPE storm threshold to 20\n");
-       ec_storm_threshold  = 20;
-       return 0;
-}
-
+#if 0
 /*
- * Acer EC firmware refuses to respond QR_EC when SCI_EVT is not set, for
- * which case, we complete the QR_EC without issuing it to the firmware.
- * https://bugzilla.kernel.org/show_bug.cgi?id=86211
+ * Some EC firmware variations refuses to respond QR_EC when SCI_EVT is not
+ * set, for which case, we complete the QR_EC without issuing it to the
+ * firmware.
+ * https://bugzilla.kernel.org/show_bug.cgi?id=82611
+ * https://bugzilla.kernel.org/show_bug.cgi?id=97381
  */
 static int ec_flag_query_handshake(const struct dmi_system_id *id)
 {
@@ -1268,6 +1407,7 @@ static int ec_flag_query_handshake(const struct dmi_system_id *id)
        EC_FLAGS_QUERY_HANDSHAKE = 1;
        return 0;
 }
+#endif
 
 /*
  * On some hardware it is necessary to clear events accumulated by the EC during
@@ -1290,6 +1430,7 @@ static int ec_clear_on_resume(const struct dmi_system_id *id)
 {
        pr_debug("Detected system needing EC poll on resume.\n");
        EC_FLAGS_CLEAR_ON_RESUME = 1;
+       ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
        return 0;
 }
 
@@ -1299,29 +1440,9 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
        DMI_MATCH(DMI_BOARD_NAME, "JFL92") }, NULL},
        {
-       ec_flag_msi, "MSI hardware", {
-       DMI_MATCH(DMI_BIOS_VENDOR, "Micro-Star")}, NULL},
-       {
-       ec_flag_msi, "MSI hardware", {
-       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star")}, NULL},
-       {
-       ec_flag_msi, "MSI hardware", {
-       DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-Star")}, NULL},
-       {
-       ec_flag_msi, "MSI hardware", {
-       DMI_MATCH(DMI_CHASSIS_VENDOR, "MICRO-STAR")}, NULL},
-       {
-       ec_flag_msi, "Quanta hardware", {
-       DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
-       DMI_MATCH(DMI_PRODUCT_NAME, "TW8/SW8/DW8"),}, NULL},
-       {
-       ec_flag_msi, "Quanta hardware", {
-       DMI_MATCH(DMI_SYS_VENDOR, "Quanta"),
-       DMI_MATCH(DMI_PRODUCT_NAME, "TW9/SW9"),}, NULL},
-       {
-       ec_flag_msi, "Clevo W350etq", {
-       DMI_MATCH(DMI_SYS_VENDOR, "CLEVO CO."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "W35_37ET"),}, NULL},
+       ec_validate_ecdt, "MSI MS-171F", {
+       DMI_MATCH(DMI_SYS_VENDOR, "Micro-Star"),
+       DMI_MATCH(DMI_PRODUCT_NAME, "MS-171F"),}, NULL},
        {
        ec_validate_ecdt, "ASUS hardware", {
        DMI_MATCH(DMI_BIOS_VENDOR, "ASUS") }, NULL},
@@ -1329,10 +1450,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        ec_validate_ecdt, "ASUS hardware", {
        DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer Inc.") }, NULL},
        {
-       ec_enlarge_storm_threshold, "CLEVO hardware", {
-       DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
-       DMI_MATCH(DMI_PRODUCT_NAME, "M720T/M730T"),}, NULL},
-       {
        ec_skip_dsdt_scan, "HP Folio 13", {
        DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
        DMI_MATCH(DMI_PRODUCT_NAME, "HP Folio 13"),}, NULL},
@@ -1343,9 +1460,6 @@ static struct dmi_system_id ec_dmi_table[] __initdata = {
        {
        ec_clear_on_resume, "Samsung hardware", {
        DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD.")}, NULL},
-       {
-       ec_flag_query_handshake, "Acer hardware", {
-       DMI_MATCH(DMI_SYS_VENDOR, "Acer"), }, NULL},
        {},
 };
 
@@ -1427,6 +1541,43 @@ error:
        return -ENODEV;
 }
 
+static int param_set_event_clearing(const char *val, struct kernel_param *kp)
+{
+       int result = 0;
+
+       if (!strncmp(val, "status", sizeof("status") - 1)) {
+               ec_event_clearing = ACPI_EC_EVT_TIMING_STATUS;
+               pr_info("Assuming SCI_EVT clearing on EC_SC accesses\n");
+       } else if (!strncmp(val, "query", sizeof("query") - 1)) {
+               ec_event_clearing = ACPI_EC_EVT_TIMING_QUERY;
+               pr_info("Assuming SCI_EVT clearing on QR_EC writes\n");
+       } else if (!strncmp(val, "event", sizeof("event") - 1)) {
+               ec_event_clearing = ACPI_EC_EVT_TIMING_EVENT;
+               pr_info("Assuming SCI_EVT clearing on event reads\n");
+       } else
+               result = -EINVAL;
+       return result;
+}
+
+static int param_get_event_clearing(char *buffer, struct kernel_param *kp)
+{
+       switch (ec_event_clearing) {
+       case ACPI_EC_EVT_TIMING_STATUS:
+               return sprintf(buffer, "status");
+       case ACPI_EC_EVT_TIMING_QUERY:
+               return sprintf(buffer, "query");
+       case ACPI_EC_EVT_TIMING_EVENT:
+               return sprintf(buffer, "event");
+       default:
+               return sprintf(buffer, "invalid");
+       }
+       return 0;
+}
+
+module_param_call(ec_event_clearing, param_set_event_clearing, param_get_event_clearing,
+                 NULL, 0644);
+MODULE_PARM_DESC(ec_event_clearing, "Assumed SCI_EVT clearing timing");
+
 static struct acpi_driver acpi_ec_driver = {
        .name = "ec",
        .class = ACPI_EC_CLASS,
index 7a36f02..bea0bba 100644 (file)
@@ -158,8 +158,9 @@ static int fan_get_state(struct acpi_device *device, unsigned long *state)
        if (result)
                return result;
 
-       *state = (acpi_state == ACPI_STATE_D3_COLD ? 0 :
-                (acpi_state == ACPI_STATE_D0 ? 1 : -1));
+       *state = acpi_state == ACPI_STATE_D3_COLD
+                       || acpi_state == ACPI_STATE_D3_HOT ?
+               0 : (acpi_state == ACPI_STATE_D0 ? 1 : -1);
        return 0;
 }
 
index aafe3ca..a322710 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/acpi.h>
 #include <acpi/hed.h>
 
-static struct acpi_device_id acpi_hed_ids[] = {
+static const struct acpi_device_id acpi_hed_ids[] = {
        {"PNP0C33", 0},
        {"", 0},
 };
index d93628c..787c629 100644 (file)
@@ -138,6 +138,8 @@ struct acpi_ec {
        struct transaction *curr;
        spinlock_t lock;
        struct work_struct work;
+       unsigned long timestamp;
+       unsigned long nr_pending_queries;
 };
 
 extern struct acpi_ec *first_ec;
@@ -181,13 +183,6 @@ static inline int suspend_nvs_save(void) { return 0; }
 static inline void suspend_nvs_restore(void) {}
 #endif
 
-/*--------------------------------------------------------------------------
-                                       Video
-  -------------------------------------------------------------------------- */
-#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
-bool acpi_osi_is_win8(void);
-#endif
-
 /*--------------------------------------------------------------------------
                                Device properties
   -------------------------------------------------------------------------- */
index 7ccba39..a5dc903 100644 (file)
@@ -175,11 +175,7 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
        if (!addr || !length)
                return;
 
-       /* Resources are never freed */
-       if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
-               request_region(addr, length, desc);
-       else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
-               request_mem_region(addr, length, desc);
+       acpi_reserve_region(addr, length, gas->space_id, 0, desc);
 }
 
 static void __init acpi_reserve_resources(void)
@@ -540,7 +536,7 @@ 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)
+                           char **new_val)
 {
        if (!init_val || !new_val)
                return AE_BAD_PARAMETER;
@@ -1684,6 +1680,12 @@ int acpi_resources_are_enforced(void)
 }
 EXPORT_SYMBOL(acpi_resources_are_enforced);
 
+bool acpi_osi_is_win8(void)
+{
+       return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
+}
+EXPORT_SYMBOL(acpi_osi_is_win8);
+
 /*
  * Deallocate the memory for a spinlock.
  */
index b1def41..03e4b6c 100644 (file)
@@ -44,7 +44,6 @@
 ACPI_MODULE_NAME("pci_irq");
 
 struct acpi_prt_entry {
-       struct list_head        list;
        struct acpi_pci_id      id;
        u8                      pin;
        acpi_handle             link;
index e0bcfb6..93eac53 100644 (file)
@@ -684,7 +684,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state)
                }
        }
 
-       *state = ACPI_STATE_D3_COLD;
+       *state = device->power.states[ACPI_STATE_D3_COLD].flags.valid ?
+               ACPI_STATE_D3_COLD : ACPI_STATE_D3_HOT;
        return 0;
 }
 
@@ -710,8 +711,6 @@ int acpi_power_transition(struct acpi_device *device, int state)
            || (device->power.state > ACPI_STATE_D3_COLD))
                return -ENODEV;
 
-       /* 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).  Then,
@@ -761,6 +760,25 @@ static void acpi_power_sysfs_remove(struct acpi_device *device)
        device_remove_file(&device->dev, &dev_attr_resource_in_use);
 }
 
+static void acpi_power_add_resource_to_list(struct acpi_power_resource *resource)
+{
+       mutex_lock(&power_resource_list_lock);
+
+       if (!list_empty(&acpi_power_resource_list)) {
+               struct acpi_power_resource *r;
+
+               list_for_each_entry(r, &acpi_power_resource_list, list_node)
+                       if (r->order > resource->order) {
+                               list_add_tail(&resource->list_node, &r->list_node);
+                               goto out;
+                       }
+       }
+       list_add_tail(&resource->list_node, &acpi_power_resource_list);
+
+ out:
+       mutex_unlock(&power_resource_list_lock);
+}
+
 int acpi_add_power_resource(acpi_handle handle)
 {
        struct acpi_power_resource *resource;
@@ -811,9 +829,7 @@ int acpi_add_power_resource(acpi_handle handle)
        if (!device_create_file(&device->dev, &dev_attr_resource_in_use))
                device->remove = acpi_power_sysfs_remove;
 
-       mutex_lock(&power_resource_list_lock);
-       list_add(&resource->list_node, &acpi_power_resource_list);
-       mutex_unlock(&power_resource_list_lock);
+       acpi_power_add_resource_to_list(resource);
        acpi_device_add_finalize(device);
        return 0;
 
@@ -844,7 +860,22 @@ void acpi_resume_power_resources(void)
                    && resource->ref_count) {
                        dev_info(&resource->device.dev, "Turning ON\n");
                        __acpi_power_on(resource);
-               } else if (state == ACPI_POWER_RESOURCE_STATE_ON
+               }
+
+               mutex_unlock(&resource->resource_lock);
+       }
+       list_for_each_entry_reverse(resource, &acpi_power_resource_list, list_node) {
+               int result, state;
+
+               mutex_lock(&resource->resource_lock);
+
+               result = acpi_power_get_state(resource->device.handle, &state);
+               if (result) {
+                       mutex_unlock(&resource->resource_lock);
+                       continue;
+               }
+
+               if (state == ACPI_POWER_RESOURCE_STATE_ON
                    && !resource->ref_count) {
                        dev_info(&resource->device.dev, "Turning OFF\n");
                        __acpi_power_off(resource);
index b1ec78b..33a38d6 100644 (file)
@@ -184,7 +184,7 @@ phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
        phys_cpuid_t phys_id;
 
        phys_id = map_mat_entry(handle, type, acpi_id);
-       if (phys_id == PHYS_CPUID_INVALID)
+       if (invalid_phys_cpuid(phys_id))
                phys_id = map_madt_entry(type, acpi_id);
 
        return phys_id;
@@ -196,7 +196,7 @@ int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
        int i;
 #endif
 
-       if (phys_id == PHYS_CPUID_INVALID) {
+       if (invalid_phys_cpuid(phys_id)) {
                /*
                 * On UP processor, there is no _MAT or MADT table.
                 * So above phys_id is always set to PHYS_CPUID_INVALID.
@@ -215,12 +215,12 @@ int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
                 * Ignores phys_id and always returns 0 for the processor
                 * handle with acpi id 0 if nr_cpu_ids is 1.
                 * This should be the case if SMP tables are not found.
-                * Return -1 for other CPU's handle.
+                * Return -EINVAL for other CPU's handle.
                 */
                if (nr_cpu_ids <= 1 && acpi_id == 0)
                        return acpi_id;
                else
-                       return -1;
+                       return -EINVAL;
        }
 
 #ifdef CONFIG_SMP
@@ -233,7 +233,7 @@ int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
        if (phys_id == 0)
                return phys_id;
 #endif
-       return -1;
+       return -ENODEV;
 }
 
 int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
index 39e0c8e..d540f42 100644 (file)
@@ -94,7 +94,7 @@ static int set_max_cstate(const struct dmi_system_id *id)
        return 0;
 }
 
-static struct dmi_system_id processor_power_dmi_table[] = {
+static const struct dmi_system_id processor_power_dmi_table[] = {
        { set_max_cstate, "Clevo 5600D", {
          DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"),
          DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")},
index e5dd808..7cfbda4 100644 (file)
@@ -52,10 +52,7 @@ static bool __init processor_physically_present(acpi_handle handle)
        type = (acpi_type == ACPI_TYPE_DEVICE) ? 1 : 0;
        cpuid = acpi_get_cpuid(handle, type, acpi_id);
 
-       if (cpuid == -1)
-               return false;
-
-       return true;
+       return !invalid_logical_cpuid(cpuid);
 }
 
 static void acpi_set_pdc_bits(u32 *buf)
index 8244f01..fcb7807 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/device.h>
 #include <linux/export.h>
 #include <linux/ioport.h>
+#include <linux/list.h>
 #include <linux/slab.h>
 
 #ifdef CONFIG_X86
@@ -621,3 +622,162 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
        return (type & types) ? 0 : 1;
 }
 EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
+
+struct reserved_region {
+       struct list_head node;
+       u64 start;
+       u64 end;
+};
+
+static LIST_HEAD(reserved_io_regions);
+static LIST_HEAD(reserved_mem_regions);
+
+static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
+                        char *desc)
+{
+       unsigned int length = end - start + 1;
+       struct resource *res;
+
+       res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
+               request_region(start, length, desc) :
+               request_mem_region(start, length, desc);
+       if (!res)
+               return -EIO;
+
+       res->flags &= ~flags;
+       return 0;
+}
+
+static int add_region_before(u64 start, u64 end, u8 space_id,
+                            unsigned long flags, char *desc,
+                            struct list_head *head)
+{
+       struct reserved_region *reg;
+       int error;
+
+       reg = kmalloc(sizeof(*reg), GFP_KERNEL);
+       if (!reg)
+               return -ENOMEM;
+
+       error = request_range(start, end, space_id, flags, desc);
+       if (error)
+               return error;
+
+       reg->start = start;
+       reg->end = end;
+       list_add_tail(&reg->node, head);
+       return 0;
+}
+
+/**
+ * acpi_reserve_region - Reserve an I/O or memory region as a system resource.
+ * @start: Starting address of the region.
+ * @length: Length of the region.
+ * @space_id: Identifier of address space to reserve the region from.
+ * @flags: Resource flags to clear for the region after requesting it.
+ * @desc: Region description (for messages).
+ *
+ * Reserve an I/O or memory region as a system resource to prevent others from
+ * using it.  If the new region overlaps with one of the regions (in the given
+ * address space) already reserved by this routine, only the non-overlapping
+ * parts of it will be reserved.
+ *
+ * Returned is either 0 (success) or a negative error code indicating a resource
+ * reservation problem.  It is the code of the first encountered error, but the
+ * routine doesn't abort until it has attempted to request all of the parts of
+ * the new region that don't overlap with other regions reserved previously.
+ *
+ * The resources requested by this routine are never released.
+ */
+int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
+                       unsigned long flags, char *desc)
+{
+       struct list_head *regions;
+       struct reserved_region *reg;
+       u64 end = start + length - 1;
+       int ret = 0, error = 0;
+
+       if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+               regions = &reserved_io_regions;
+       else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               regions = &reserved_mem_regions;
+       else
+               return -EINVAL;
+
+       if (list_empty(regions))
+               return add_region_before(start, end, space_id, flags, desc, regions);
+
+       list_for_each_entry(reg, regions, node)
+               if (reg->start == end + 1) {
+                       /* The new region can be prepended to this one. */
+                       ret = request_range(start, end, space_id, flags, desc);
+                       if (!ret)
+                               reg->start = start;
+
+                       return ret;
+               } else if (reg->start > end) {
+                       /* No overlap.  Add the new region here and get out. */
+                       return add_region_before(start, end, space_id, flags,
+                                                desc, &reg->node);
+               } else if (reg->end == start - 1) {
+                       goto combine;
+               } else if (reg->end >= start) {
+                       goto overlap;
+               }
+
+       /* The new region goes after the last existing one. */
+       return add_region_before(start, end, space_id, flags, desc, regions);
+
+ overlap:
+       /*
+        * The new region overlaps an existing one.
+        *
+        * The head part of the new region immediately preceding the existing
+        * overlapping one can be combined with it right away.
+        */
+       if (reg->start > start) {
+               error = request_range(start, reg->start - 1, space_id, flags, desc);
+               if (error)
+                       ret = error;
+               else
+                       reg->start = start;
+       }
+
+ combine:
+       /*
+        * The new region is adjacent to an existing one.  If it extends beyond
+        * that region all the way to the next one, it is possible to combine
+        * all three of them.
+        */
+       while (reg->end < end) {
+               struct reserved_region *next = NULL;
+               u64 a = reg->end + 1, b = end;
+
+               if (!list_is_last(&reg->node, regions)) {
+                       next = list_next_entry(reg, node);
+                       if (next->start <= end)
+                               b = next->start - 1;
+               }
+               error = request_range(a, b, space_id, flags, desc);
+               if (!error) {
+                       if (next && next->start == b + 1) {
+                               reg->end = next->end;
+                               list_del(&next->node);
+                               kfree(next);
+                       } else {
+                               reg->end = end;
+                               break;
+                       }
+               } else if (next) {
+                       if (!ret)
+                               ret = error;
+
+                       reg = next;
+               } else {
+                       break;
+               }
+       }
+
+       return ret ? ret : error;
+}
+EXPORT_SYMBOL_GPL(acpi_reserve_region);
index 67509b2..2649a06 100644 (file)
@@ -1769,15 +1769,9 @@ static void acpi_bus_init_power_state(struct acpi_device *device, int state)
        if (acpi_has_method(device->handle, pathname))
                ps->flags.explicit_set = 1;
 
-       /*
-        * State is valid if there are means to put the device into it.
-        * D3hot is only valid if _PR3 present.
-        */
-       if (!list_empty(&ps->resources)
-           || (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) {
+       /* State is valid if there are means to put the device into it. */
+       if (!list_empty(&ps->resources) || ps->flags.explicit_set)
                ps->flags.valid = 1;
-               ps->flags.os_accessible = 1;
-       }
 
        ps->power = -1;         /* Unknown - driver assigned */
        ps->latency = -1;       /* Unknown - driver assigned */
@@ -1813,21 +1807,13 @@ static void acpi_bus_get_power_flags(struct acpi_device *device)
                acpi_bus_init_power_state(device, i);
 
        INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources);
+       if (!list_empty(&device->power.states[ACPI_STATE_D3_HOT].resources))
+               device->power.states[ACPI_STATE_D3_COLD].flags.valid = 1;
 
-       /* Set defaults for D0 and D3 states (always valid) */
+       /* Set defaults for D0 and D3hot 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_COLD].flags.valid = 1;
-       device->power.states[ACPI_STATE_D3_COLD].power = 0;
-
-       /* Set D3cold's explicit_set flag if _PS3 exists. */
-       if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set)
-               device->power.states[ACPI_STATE_D3_COLD].flags.explicit_set = 1;
-
-       /* Presence of _PS3 or _PRx means we can put the device into D3 cold */
-       if (device->power.states[ACPI_STATE_D3_HOT].flags.explicit_set ||
-                       device->power.flags.power_resources)
-               device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1;
+       device->power.states[ACPI_STATE_D3_HOT].flags.valid = 1;
 
        if (acpi_bus_init_power(device))
                device->flags.power_manageable = 0;
@@ -1950,6 +1936,62 @@ bool acpi_dock_match(acpi_handle handle)
        return acpi_has_method(handle, "_DCK");
 }
 
+static acpi_status
+acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
+                         void **return_value)
+{
+       long *cap = context;
+
+       if (acpi_has_method(handle, "_BCM") &&
+           acpi_has_method(handle, "_BCL")) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
+                                 "support\n"));
+               *cap |= ACPI_VIDEO_BACKLIGHT;
+               if (!acpi_has_method(handle, "_BQC"))
+                       printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
+                               "cannot determine initial brightness\n");
+               /* We have backlight support, no need to scan further */
+               return AE_CTRL_TERMINATE;
+       }
+       return 0;
+}
+
+/* Returns true if the ACPI object is a video device which can be
+ * handled by video.ko.
+ * The device will get a Linux specific CID added in scan.c to
+ * identify the device as an ACPI graphics device
+ * Be aware that the graphics device may not be physically present
+ * Use acpi_video_get_capabilities() to detect general ACPI video
+ * capabilities of present cards
+ */
+long acpi_is_video_device(acpi_handle handle)
+{
+       long video_caps = 0;
+
+       /* Is this device able to support video switching ? */
+       if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
+               video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
+
+       /* Is this device able to retrieve a video ROM ? */
+       if (acpi_has_method(handle, "_ROM"))
+               video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
+
+       /* Is this device able to configure which video head to be POSTed ? */
+       if (acpi_has_method(handle, "_VPO") &&
+           acpi_has_method(handle, "_GPD") &&
+           acpi_has_method(handle, "_SPD"))
+               video_caps |= ACPI_VIDEO_DEVICE_POSTING;
+
+       /* Only check for backlight functionality if one of the above hit. */
+       if (video_caps)
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+                                   ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
+                                   &video_caps, NULL);
+
+       return video_caps;
+}
+EXPORT_SYMBOL(acpi_is_video_device);
+
 const char *acpi_device_hid(struct acpi_device *device)
 {
        struct acpi_hardware_id *hid;
index cd49a39..67c548a 100644 (file)
@@ -712,3 +712,18 @@ bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
        return false;
 }
 EXPORT_SYMBOL(acpi_check_dsm);
+
+/*
+ * acpi_backlight= handling, this is done here rather then in video_detect.c
+ * because __setup cannot be used in modules.
+ */
+char acpi_video_backlight_string[16];
+EXPORT_SYMBOL(acpi_video_backlight_string);
+
+static int __init acpi_backlight(char *str)
+{
+       strlcpy(acpi_video_backlight_string, str,
+               sizeof(acpi_video_backlight_string));
+       return 1;
+}
+__setup("acpi_backlight=", acpi_backlight);
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
deleted file mode 100644 (file)
index cc79d3f..0000000
+++ /dev/null
@@ -1,2231 +0,0 @@
-/*
- *  video.c - ACPI Video Driver
- *
- *  Copyright (C) 2004 Luming Yu <luming.yu@intel.com>
- *  Copyright (C) 2004 Bruno Ducrot <ducrot@poupinou.org>
- *  Copyright (C) 2006 Thomas Tuttle <linux-kernel@ttuttle.net>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  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/mutex.h>
-#include <linux/input.h>
-#include <linux/backlight.h>
-#include <linux/thermal.h>
-#include <linux/sort.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-#include <linux/slab.h>
-#include <linux/dmi.h>
-#include <linux/suspend.h>
-#include <linux/acpi.h>
-#include <acpi/video.h>
-#include <asm/uaccess.h>
-
-#include "internal.h"
-
-#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     0x85
-#define        ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS        0x86
-#define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS       0x87
-#define ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS      0x88
-#define ACPI_VIDEO_NOTIFY_DISPLAY_OFF          0x89
-
-#define MAX_NAME_LEN   20
-
-#define _COMPONENT             ACPI_VIDEO_COMPONENT
-ACPI_MODULE_NAME("video");
-
-MODULE_AUTHOR("Bruno Ducrot");
-MODULE_DESCRIPTION("ACPI Video Driver");
-MODULE_LICENSE("GPL");
-
-static bool brightness_switch_enabled = 1;
-module_param(brightness_switch_enabled, bool, 0644);
-
-/*
- * By default, we don't allow duplicate ACPI video bus devices
- * under the same VGA controller
- */
-static bool allow_duplicates;
-module_param(allow_duplicates, bool, 0644);
-
-/*
- * For Windows 8 systems: used to decide if video module
- * should skip registering backlight interface of its own.
- */
-enum {
-       NATIVE_BACKLIGHT_NOT_SET = -1,
-       NATIVE_BACKLIGHT_OFF,
-       NATIVE_BACKLIGHT_ON,
-};
-
-static int use_native_backlight_param = NATIVE_BACKLIGHT_NOT_SET;
-module_param_named(use_native_backlight, use_native_backlight_param, int, 0444);
-static int use_native_backlight_dmi = NATIVE_BACKLIGHT_NOT_SET;
-
-static int register_count;
-static struct mutex video_list_lock;
-static struct list_head video_bus_head;
-static int acpi_video_bus_add(struct acpi_device *device);
-static int acpi_video_bus_remove(struct acpi_device *device);
-static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
-
-static const struct acpi_device_id video_device_ids[] = {
-       {ACPI_VIDEO_HID, 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, video_device_ids);
-
-static struct acpi_driver acpi_video_bus = {
-       .name = "video",
-       .class = ACPI_VIDEO_CLASS,
-       .ids = video_device_ids,
-       .ops = {
-               .add = acpi_video_bus_add,
-               .remove = acpi_video_bus_remove,
-               .notify = acpi_video_bus_notify,
-               },
-};
-
-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 differentiates the display type */
-       u32 display_type:4;     /* Describe the specific type in use */
-       u32 vendor_specific:4;  /* Chipset Vendor Specific */
-       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 {
-       struct acpi_device *device;
-       bool backlight_registered;
-       bool backlight_notifier_registered;
-       u8 dos_setting;
-       struct acpi_video_enumerated_device *attached_array;
-       u8 attached_count;
-       u8 child_count;
-       struct acpi_video_bus_cap cap;
-       struct acpi_video_bus_flags flags;
-       struct list_head video_device_list;
-       struct mutex device_list_lock;  /* protects video_device_list */
-       struct list_head entry;
-       struct input_dev *input;
-       char phys[32];  /* for input device */
-       struct notifier_block pm_nb;
-       struct notifier_block backlight_nb;
-};
-
-struct acpi_video_device_flags {
-       u8 crt:1;
-       u8 lcd:1;
-       u8 tvout:1;
-       u8 dvi:1;
-       u8 bios:1;
-       u8 unknown:1;
-       u8 notify:1;
-       u8 reserved:1;
-};
-
-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 _BQC:1;              /* Get current brightness level */
-       u8 _BCQ:1;              /* Some buggy BIOS uses _BCQ instead of _BQC */
-       u8 _DDC:1;              /* Return the EDID for this device */
-};
-
-struct acpi_video_brightness_flags {
-       u8 _BCL_no_ac_battery_levels:1; /* no AC/Battery levels in _BCL */
-       u8 _BCL_reversed:1;             /* _BCL package is in a reversed order */
-       u8 _BQC_use_index:1;            /* _BQC returns an index value */
-};
-
-struct acpi_video_device_brightness {
-       int curr;
-       int count;
-       int *levels;
-       struct acpi_video_brightness_flags flags;
-};
-
-struct acpi_video_device {
-       unsigned long device_id;
-       struct acpi_video_device_flags flags;
-       struct acpi_video_device_cap cap;
-       struct list_head entry;
-       struct delayed_work switch_brightness_work;
-       int switch_brightness_event;
-       struct acpi_video_bus *video;
-       struct acpi_device *dev;
-       struct acpi_video_device_brightness *brightness;
-       struct backlight_device *backlight;
-       struct thermal_cooling_device *cooling_dev;
-};
-
-static const 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_device_lcd_set_level(struct acpi_video_device *device,
-                       int level);
-static int acpi_video_device_lcd_get_level_current(
-                       struct acpi_video_device *device,
-                       unsigned long long *level, bool raw);
-static int acpi_video_get_next_level(struct acpi_video_device *device,
-                                    u32 level_current, u32 event);
-static void acpi_video_switch_brightness(struct work_struct *work);
-
-static bool acpi_video_use_native_backlight(void)
-{
-       if (use_native_backlight_param != NATIVE_BACKLIGHT_NOT_SET)
-               return use_native_backlight_param;
-       else if (use_native_backlight_dmi != NATIVE_BACKLIGHT_NOT_SET)
-               return use_native_backlight_dmi;
-       return acpi_osi_is_win8();
-}
-
-bool acpi_video_verify_backlight_support(void)
-{
-       if (acpi_video_use_native_backlight() &&
-           backlight_device_registered(BACKLIGHT_RAW))
-               return false;
-       return acpi_video_backlight_support();
-}
-EXPORT_SYMBOL_GPL(acpi_video_verify_backlight_support);
-
-/* backlight device sysfs support */
-static int acpi_video_get_brightness(struct backlight_device *bd)
-{
-       unsigned long long cur_level;
-       int i;
-       struct acpi_video_device *vd = bl_get_data(bd);
-
-       if (acpi_video_device_lcd_get_level_current(vd, &cur_level, false))
-               return -EINVAL;
-       for (i = 2; i < vd->brightness->count; i++) {
-               if (vd->brightness->levels[i] == cur_level)
-                       /*
-                        * The first two entries are special - see page 575
-                        * of the ACPI spec 3.0
-                        */
-                       return i - 2;
-       }
-       return 0;
-}
-
-static int acpi_video_set_brightness(struct backlight_device *bd)
-{
-       int request_level = bd->props.brightness + 2;
-       struct acpi_video_device *vd = bl_get_data(bd);
-
-       cancel_delayed_work(&vd->switch_brightness_work);
-       return acpi_video_device_lcd_set_level(vd,
-                               vd->brightness->levels[request_level]);
-}
-
-static const struct backlight_ops acpi_backlight_ops = {
-       .get_brightness = acpi_video_get_brightness,
-       .update_status  = acpi_video_set_brightness,
-};
-
-/* thermal cooling device callbacks */
-static int video_get_max_state(struct thermal_cooling_device *cooling_dev, unsigned
-                              long *state)
-{
-       struct acpi_device *device = cooling_dev->devdata;
-       struct acpi_video_device *video = acpi_driver_data(device);
-
-       *state = video->brightness->count - 3;
-       return 0;
-}
-
-static int video_get_cur_state(struct thermal_cooling_device *cooling_dev, unsigned
-                              long *state)
-{
-       struct acpi_device *device = cooling_dev->devdata;
-       struct acpi_video_device *video = acpi_driver_data(device);
-       unsigned long long level;
-       int offset;
-
-       if (acpi_video_device_lcd_get_level_current(video, &level, false))
-               return -EINVAL;
-       for (offset = 2; offset < video->brightness->count; offset++)
-               if (level == video->brightness->levels[offset]) {
-                       *state = video->brightness->count - offset - 1;
-                       return 0;
-               }
-
-       return -EINVAL;
-}
-
-static int
-video_set_cur_state(struct thermal_cooling_device *cooling_dev, unsigned long state)
-{
-       struct acpi_device *device = cooling_dev->devdata;
-       struct acpi_video_device *video = acpi_driver_data(device);
-       int level;
-
-       if (state >= video->brightness->count - 2)
-               return -EINVAL;
-
-       state = video->brightness->count - state;
-       level = video->brightness->levels[state - 1];
-       return acpi_video_device_lcd_set_level(video, level);
-}
-
-static const struct thermal_cooling_device_ops video_cooling_ops = {
-       .get_max_state = video_get_max_state,
-       .get_cur_state = video_get_cur_state,
-       .set_cur_state = video_set_cur_state,
-};
-
-/*
- * --------------------------------------------------------------------------
- *                             Video Management
- * --------------------------------------------------------------------------
- */
-
-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;
-
-
-       *levels = NULL;
-
-       status = acpi_evaluate_object(device->dev->handle, "_BCL", NULL, &buffer);
-       if (!ACPI_SUCCESS(status))
-               return status;
-       obj = (union acpi_object *)buffer.pointer;
-       if (!obj || (obj->type != ACPI_TYPE_PACKAGE)) {
-               printk(KERN_ERR PREFIX "Invalid _BCL data\n");
-               status = -EFAULT;
-               goto err;
-       }
-
-       *levels = obj;
-
-       return 0;
-
-err:
-       kfree(buffer.pointer);
-
-       return status;
-}
-
-static int
-acpi_video_device_lcd_set_level(struct acpi_video_device *device, int level)
-{
-       int status;
-       int state;
-
-       status = acpi_execute_simple_method(device->dev->handle,
-                                           "_BCM", level);
-       if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO, "Evaluating _BCM failed"));
-               return -EIO;
-       }
-
-       device->brightness->curr = level;
-       for (state = 2; state < device->brightness->count; state++)
-               if (level == device->brightness->levels[state]) {
-                       if (device->backlight)
-                               device->backlight->props.brightness = state - 2;
-                       return 0;
-               }
-
-       ACPI_ERROR((AE_INFO, "Current brightness invalid"));
-       return -EINVAL;
-}
-
-/*
- * For some buggy _BQC methods, we need to add a constant value to
- * the _BQC return value to get the actual current brightness level
- */
-
-static int bqc_offset_aml_bug_workaround;
-static int __init video_set_bqc_offset(const struct dmi_system_id *d)
-{
-       bqc_offset_aml_bug_workaround = 9;
-       return 0;
-}
-
-static int __init video_disable_native_backlight(const struct dmi_system_id *d)
-{
-       use_native_backlight_dmi = NATIVE_BACKLIGHT_OFF;
-       return 0;
-}
-
-static int __init video_enable_native_backlight(const struct dmi_system_id *d)
-{
-       use_native_backlight_dmi = NATIVE_BACKLIGHT_ON;
-       return 0;
-}
-
-static struct dmi_system_id video_dmi_table[] __initdata = {
-       /*
-        * Broken _BQC workaround http://bugzilla.kernel.org/show_bug.cgi?id=13121
-        */
-       {
-        .callback = video_set_bqc_offset,
-        .ident = "Acer Aspire 5720",
-        .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5720"),
-               },
-       },
-       {
-        .callback = video_set_bqc_offset,
-        .ident = "Acer Aspire 5710Z",
-        .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5710Z"),
-               },
-       },
-       {
-        .callback = video_set_bqc_offset,
-        .ident = "eMachines E510",
-        .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "EMACHINES"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "eMachines E510"),
-               },
-       },
-       {
-        .callback = video_set_bqc_offset,
-        .ident = "Acer Aspire 5315",
-        .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
-               },
-       },
-       {
-        .callback = video_set_bqc_offset,
-        .ident = "Acer Aspire 7720",
-        .matches = {
-               DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720"),
-               },
-       },
-
-       /*
-        * These models have a working acpi_video backlight control, and using
-        * native backlight causes a regression where backlight does not work
-        * when userspace is not handling brightness key events. Disable
-        * native_backlight on these to fix this:
-        * https://bugzilla.kernel.org/show_bug.cgi?id=81691
-        */
-       {
-        .callback = video_disable_native_backlight,
-        .ident = "ThinkPad T420",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
-               },
-       },
-       {
-        .callback = video_disable_native_backlight,
-        .ident = "ThinkPad T520",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
-               },
-       },
-       {
-        .callback = video_disable_native_backlight,
-        .ident = "ThinkPad X201s",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
-               },
-       },
-
-       /* The native backlight controls do not work on some older machines */
-       {
-        /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
-        .callback = video_disable_native_backlight,
-        .ident = "HP ENVY 15 Notebook",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
-               },
-       },
-
-       {
-        .callback = video_disable_native_backlight,
-        .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
-               },
-       },
-       {
-        .callback = video_disable_native_backlight,
-        .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"),
-               },
-       },
-       {
-        /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
-        .callback = video_disable_native_backlight,
-        .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "3570R/370R/470R/450R/510R/4450RV"),
-               },
-       },
-       {
-        /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
-        .callback = video_disable_native_backlight,
-        .ident = "SAMSUNG 730U3E/740U3E",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
-               },
-       },
-       {
-        /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
-        .callback = video_disable_native_backlight,
-        .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "900X3C/900X3D/900X3E/900X4C/900X4D"),
-               },
-       },
-
-       {
-        /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
-        .callback = video_disable_native_backlight,
-        .ident = "Dell XPS15 L521X",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
-               DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
-               },
-       },
-
-       /* Non win8 machines which need native backlight nevertheless */
-       {
-        /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
-        .callback = video_enable_native_backlight,
-        .ident = "Lenovo Ideapad Z570",
-        .matches = {
-               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
-               DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
-               },
-       },
-       {}
-};
-
-static unsigned long long
-acpi_video_bqc_value_to_level(struct acpi_video_device *device,
-                             unsigned long long bqc_value)
-{
-       unsigned long long level;
-
-       if (device->brightness->flags._BQC_use_index) {
-               /*
-                * _BQC returns an index that doesn't account for
-                * the first 2 items with special meaning, so we need
-                * to compensate for that by offsetting ourselves
-                */
-               if (device->brightness->flags._BCL_reversed)
-                       bqc_value = device->brightness->count - 3 - bqc_value;
-
-               level = device->brightness->levels[bqc_value + 2];
-       } else {
-               level = bqc_value;
-       }
-
-       level += bqc_offset_aml_bug_workaround;
-
-       return level;
-}
-
-static int
-acpi_video_device_lcd_get_level_current(struct acpi_video_device *device,
-                                       unsigned long long *level, bool raw)
-{
-       acpi_status status = AE_OK;
-       int i;
-
-       if (device->cap._BQC || device->cap._BCQ) {
-               char *buf = device->cap._BQC ? "_BQC" : "_BCQ";
-
-               status = acpi_evaluate_integer(device->dev->handle, buf,
-                                               NULL, level);
-               if (ACPI_SUCCESS(status)) {
-                       if (raw) {
-                               /*
-                                * Caller has indicated he wants the raw
-                                * value returned by _BQC, so don't furtherly
-                                * mess with the value.
-                                */
-                               return 0;
-                       }
-
-                       *level = acpi_video_bqc_value_to_level(device, *level);
-
-                       for (i = 2; i < device->brightness->count; i++)
-                               if (device->brightness->levels[i] == *level) {
-                                       device->brightness->curr = *level;
-                                       return 0;
-                               }
-                       /*
-                        * BQC returned an invalid level.
-                        * Stop using it.
-                        */
-                       ACPI_WARNING((AE_INFO,
-                                     "%s returned an invalid level",
-                                     buf));
-                       device->cap._BQC = device->cap._BCQ = 0;
-               } else {
-                       /*
-                        * Fixme:
-                        * should we return an error or ignore this failure?
-                        * dev->brightness->curr is a cached value which stores
-                        * the correct current backlight level in most cases.
-                        * ACPI video backlight still works w/ buggy _BQC.
-                        * http://bugzilla.kernel.org/show_bug.cgi?id=12233
-                        */
-                       ACPI_WARNING((AE_INFO, "Evaluating %s failed", buf));
-                       device->cap._BQC = device->cap._BCQ = 0;
-               }
-       }
-
-       *level = device->brightness->curr;
-       return 0;
-}
-
-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 };
-
-
-       *edid = NULL;
-
-       if (!device)
-               return -ENODEV;
-       if (length == 128)
-               arg0.integer.value = 1;
-       else if (length == 256)
-               arg0.integer.value = 2;
-       else
-               return -EINVAL;
-
-       status = acpi_evaluate_object(device->dev->handle, "_DDC", &args, &buffer);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       obj = buffer.pointer;
-
-       if (obj && obj->type == ACPI_TYPE_BUFFER)
-               *edid = obj;
-       else {
-               printk(KERN_ERR PREFIX "Invalid _DDC data\n");
-               status = -EFAULT;
-               kfree(obj);
-       }
-
-       return status;
-}
-
-/* bus */
-
-/*
- *  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 switch 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:
- *             -EINVAL wrong arg.
- */
-
-static int
-acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
-{
-       acpi_status status;
-
-       if (!video->cap._DOS)
-               return 0;
-
-       if (bios_flag < 0 || bios_flag > 3 || lcd_flag < 0 || lcd_flag > 1)
-               return -EINVAL;
-       video->dos_setting = (lcd_flag << 2) | bios_flag;
-       status = acpi_execute_simple_method(video->device->handle, "_DOS",
-                                           (lcd_flag << 2) | bios_flag);
-       if (ACPI_FAILURE(status))
-               return -EIO;
-
-       return 0;
-}
-
-/*
- * Simple comparison function used to sort backlight levels.
- */
-
-static int
-acpi_video_cmp_level(const void *a, const void *b)
-{
-       return *(int *)a - *(int *)b;
-}
-
-/*
- * Decides if _BQC/_BCQ for this system is usable
- *
- * We do this by changing the level first and then read out the current
- * brightness level, if the value does not match, find out if it is using
- * index. If not, clear the _BQC/_BCQ capability.
- */
-static int acpi_video_bqc_quirk(struct acpi_video_device *device,
-                               int max_level, int current_level)
-{
-       struct acpi_video_device_brightness *br = device->brightness;
-       int result;
-       unsigned long long level;
-       int test_level;
-
-       /* don't mess with existing known broken systems */
-       if (bqc_offset_aml_bug_workaround)
-               return 0;
-
-       /*
-        * Some systems always report current brightness level as maximum
-        * through _BQC, we need to test another value for them.
-        */
-       test_level = current_level == max_level ? br->levels[3] : max_level;
-
-       result = acpi_video_device_lcd_set_level(device, test_level);
-       if (result)
-               return result;
-
-       result = acpi_video_device_lcd_get_level_current(device, &level, true);
-       if (result)
-               return result;
-
-       if (level != test_level) {
-               /* buggy _BQC found, need to find out if it uses index */
-               if (level < br->count) {
-                       if (br->flags._BCL_reversed)
-                               level = br->count - 3 - level;
-                       if (br->levels[level + 2] == test_level)
-                               br->flags._BQC_use_index = 1;
-               }
-
-               if (!br->flags._BQC_use_index)
-                       device->cap._BQC = device->cap._BCQ = 0;
-       }
-
-       return 0;
-}
-
-
-/*
- *  Arg:
- *     device  : video output device (LCD, CRT, ..)
- *
- *  Return Value:
- *     Maximum brightness level
- *
- *  Allocate and initialize device->brightness.
- */
-
-static int
-acpi_video_init_brightness(struct acpi_video_device *device)
-{
-       union acpi_object *obj = NULL;
-       int i, max_level = 0, count = 0, level_ac_battery = 0;
-       unsigned long long level, level_old;
-       union acpi_object *o;
-       struct acpi_video_device_brightness *br = NULL;
-       int result = -EINVAL;
-       u32 value;
-
-       if (!ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available "
-                                               "LCD brightness level\n"));
-               goto out;
-       }
-
-       if (obj->package.count < 2)
-               goto out;
-
-       br = kzalloc(sizeof(*br), GFP_KERNEL);
-       if (!br) {
-               printk(KERN_ERR "can't allocate memory\n");
-               result = -ENOMEM;
-               goto out;
-       }
-
-       br->levels = kmalloc((obj->package.count + 2) * sizeof *(br->levels),
-                               GFP_KERNEL);
-       if (!br->levels) {
-               result = -ENOMEM;
-               goto out_free;
-       }
-
-       for (i = 0; i < obj->package.count; i++) {
-               o = (union acpi_object *)&obj->package.elements[i];
-               if (o->type != ACPI_TYPE_INTEGER) {
-                       printk(KERN_ERR PREFIX "Invalid data\n");
-                       continue;
-               }
-               value = (u32) o->integer.value;
-               /* Skip duplicate entries */
-               if (count > 2 && br->levels[count - 1] == value)
-                       continue;
-
-               br->levels[count] = value;
-
-               if (br->levels[count] > max_level)
-                       max_level = br->levels[count];
-               count++;
-       }
-
-       /*
-        * some buggy BIOS don't export the levels
-        * when machine is on AC/Battery in _BCL package.
-        * In this case, the first two elements in _BCL packages
-        * are also supported brightness levels that OS should take care of.
-        */
-       for (i = 2; i < count; i++) {
-               if (br->levels[i] == br->levels[0])
-                       level_ac_battery++;
-               if (br->levels[i] == br->levels[1])
-                       level_ac_battery++;
-       }
-
-       if (level_ac_battery < 2) {
-               level_ac_battery = 2 - level_ac_battery;
-               br->flags._BCL_no_ac_battery_levels = 1;
-               for (i = (count - 1 + level_ac_battery); i >= 2; i--)
-                       br->levels[i] = br->levels[i - level_ac_battery];
-               count += level_ac_battery;
-       } else if (level_ac_battery > 2)
-               ACPI_ERROR((AE_INFO, "Too many duplicates in _BCL package"));
-
-       /* Check if the _BCL package is in a reversed order */
-       if (max_level == br->levels[2]) {
-               br->flags._BCL_reversed = 1;
-               sort(&br->levels[2], count - 2, sizeof(br->levels[2]),
-                       acpi_video_cmp_level, NULL);
-       } else if (max_level != br->levels[count - 1])
-               ACPI_ERROR((AE_INFO,
-                           "Found unordered _BCL package"));
-
-       br->count = count;
-       device->brightness = br;
-
-       /* _BQC uses INDEX while _BCL uses VALUE in some laptops */
-       br->curr = level = max_level;
-
-       if (!device->cap._BQC)
-               goto set_level;
-
-       result = acpi_video_device_lcd_get_level_current(device,
-                                                        &level_old, true);
-       if (result)
-               goto out_free_levels;
-
-       result = acpi_video_bqc_quirk(device, max_level, level_old);
-       if (result)
-               goto out_free_levels;
-       /*
-        * cap._BQC may get cleared due to _BQC is found to be broken
-        * in acpi_video_bqc_quirk, so check again here.
-        */
-       if (!device->cap._BQC)
-               goto set_level;
-
-       level = acpi_video_bqc_value_to_level(device, level_old);
-       /*
-        * On some buggy laptops, _BQC returns an uninitialized
-        * value when invoked for the first time, i.e.
-        * level_old is invalid (no matter whether it's a level
-        * or an index). Set the backlight to max_level in this case.
-        */
-       for (i = 2; i < br->count; i++)
-               if (level == br->levels[i])
-                       break;
-       if (i == br->count || !level)
-               level = max_level;
-
-set_level:
-       result = acpi_video_device_lcd_set_level(device, level);
-       if (result)
-               goto out_free_levels;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "found %d brightness levels\n", count - 2));
-       kfree(obj);
-       return result;
-
-out_free_levels:
-       kfree(br->levels);
-out_free:
-       kfree(br);
-out:
-       device->brightness = NULL;
-       kfree(obj);
-       return result;
-}
-
-/*
- *  Arg:
- *     device  : video output device (LCD, CRT, ..)
- *
- *  Return Value:
- *     None
- *
- *  Find out all required AML methods defined under the output
- *  device.
- */
-
-static void acpi_video_device_find_cap(struct acpi_video_device *device)
-{
-       if (acpi_has_method(device->dev->handle, "_ADR"))
-               device->cap._ADR = 1;
-       if (acpi_has_method(device->dev->handle, "_BCL"))
-               device->cap._BCL = 1;
-       if (acpi_has_method(device->dev->handle, "_BCM"))
-               device->cap._BCM = 1;
-       if (acpi_has_method(device->dev->handle, "_BQC")) {
-               device->cap._BQC = 1;
-       } else if (acpi_has_method(device->dev->handle, "_BCQ")) {
-               printk(KERN_WARNING FW_BUG "_BCQ is used instead of _BQC\n");
-               device->cap._BCQ = 1;
-       }
-
-       if (acpi_has_method(device->dev->handle, "_DDC"))
-               device->cap._DDC = 1;
-}
-
-/*
- *  Arg:
- *     device  : video output device (VGA)
- *
- *  Return Value:
- *     None
- *
- *  Find out all required AML methods defined under the video bus device.
- */
-
-static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
-{
-       if (acpi_has_method(video->device->handle, "_DOS"))
-               video->cap._DOS = 1;
-       if (acpi_has_method(video->device->handle, "_DOD"))
-               video->cap._DOD = 1;
-       if (acpi_has_method(video->device->handle, "_ROM"))
-               video->cap._ROM = 1;
-       if (acpi_has_method(video->device->handle, "_GPD"))
-               video->cap._GPD = 1;
-       if (acpi_has_method(video->device->handle, "_SPD"))
-               video->cap._SPD = 1;
-       if (acpi_has_method(video->device->handle, "_VPO"))
-               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;
-       struct pci_dev *dev;
-
-       if (!video)
-               return -EINVAL;
-
-       dev = acpi_get_pci_dev(video->device->handle);
-       if (!dev)
-               return -ENODEV;
-       pci_dev_put(dev);
-
-       /*
-        * Since there is no HID, CID and so on for VGA driver, we have
-        * to check well known required nodes.
-        */
-
-       /* Does this device support video switching? */
-       if (video->cap._DOS || video->cap._DOD) {
-               if (!video->cap._DOS) {
-                       printk(KERN_WARNING FW_BUG
-                               "ACPI(%s) defines _DOD but not _DOS\n",
-                               acpi_device_bid(video->device));
-               }
-               video->flags.multihead = 1;
-               status = 0;
-       }
-
-       /* Does this device support retrieving a video ROM? */
-       if (video->cap._ROM) {
-               video->flags.rom = 1;
-               status = 0;
-       }
-
-       /* Does this device support configuring which video device to POST? */
-       if (video->cap._GPD && video->cap._SPD && video->cap._VPO) {
-               video->flags.post = 1;
-               status = 0;
-       }
-
-       return status;
-}
-
-/*
- * --------------------------------------------------------------------------
- *                               Driver Interface
- * --------------------------------------------------------------------------
- */
-
-/* device interface */
-static struct acpi_video_device_attrib *
-acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
-{
-       struct acpi_video_enumerated_device *ids;
-       int i;
-
-       for (i = 0; i < video->attached_count; i++) {
-               ids = &video->attached_array[i];
-               if ((ids->value.int_val & 0xffff) == device_id)
-                       return &ids->value.attrib;
-       }
-
-       return NULL;
-}
-
-static int
-acpi_video_get_device_type(struct acpi_video_bus *video,
-                          unsigned long device_id)
-{
-       struct acpi_video_enumerated_device *ids;
-       int i;
-
-       for (i = 0; i < video->attached_count; i++) {
-               ids = &video->attached_array[i];
-               if ((ids->value.int_val & 0xffff) == device_id)
-                       return ids->value.int_val;
-       }
-
-       return 0;
-}
-
-static int
-acpi_video_bus_get_one_device(struct acpi_device *device,
-                             struct acpi_video_bus *video)
-{
-       unsigned long long device_id;
-       int status, device_type;
-       struct acpi_video_device *data;
-       struct acpi_video_device_attrib *attribute;
-
-       status =
-           acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
-       /* Some device omits _ADR, we skip them instead of fail */
-       if (ACPI_FAILURE(status))
-               return 0;
-
-       data = kzalloc(sizeof(struct acpi_video_device), GFP_KERNEL);
-       if (!data)
-               return -ENOMEM;
-
-       strcpy(acpi_device_name(device), ACPI_VIDEO_DEVICE_NAME);
-       strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
-       device->driver_data = data;
-
-       data->device_id = device_id;
-       data->video = video;
-       data->dev = device;
-       INIT_DELAYED_WORK(&data->switch_brightness_work,
-                         acpi_video_switch_brightness);
-
-       attribute = acpi_video_get_device_attr(video, device_id);
-
-       if (attribute && attribute->device_id_scheme) {
-               switch (attribute->display_type) {
-               case ACPI_VIDEO_DISPLAY_CRT:
-                       data->flags.crt = 1;
-                       break;
-               case ACPI_VIDEO_DISPLAY_TV:
-                       data->flags.tvout = 1;
-                       break;
-               case ACPI_VIDEO_DISPLAY_DVI:
-                       data->flags.dvi = 1;
-                       break;
-               case ACPI_VIDEO_DISPLAY_LCD:
-                       data->flags.lcd = 1;
-                       break;
-               default:
-                       data->flags.unknown = 1;
-                       break;
-               }
-               if (attribute->bios_can_detect)
-                       data->flags.bios = 1;
-       } else {
-               /* Check for legacy IDs */
-               device_type = acpi_video_get_device_type(video, device_id);
-               /* Ignore bits 16 and 18-20 */
-               switch (device_type & 0xffe2ffff) {
-               case ACPI_VIDEO_DISPLAY_LEGACY_MONITOR:
-                       data->flags.crt = 1;
-                       break;
-               case ACPI_VIDEO_DISPLAY_LEGACY_PANEL:
-                       data->flags.lcd = 1;
-                       break;
-               case ACPI_VIDEO_DISPLAY_LEGACY_TV:
-                       data->flags.tvout = 1;
-                       break;
-               default:
-                       data->flags.unknown = 1;
-               }
-       }
-
-       acpi_video_device_bind(video, data);
-       acpi_video_device_find_cap(data);
-
-       mutex_lock(&video->device_list_lock);
-       list_add_tail(&data->entry, &video->video_device_list);
-       mutex_unlock(&video->device_list_lock);
-
-       return status;
-}
-
-/*
- *  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 acpi_video_device *dev;
-
-       mutex_lock(&video->device_list_lock);
-
-       list_for_each_entry(dev, &video->video_device_list, entry)
-               acpi_video_device_bind(video, dev);
-
-       mutex_unlock(&video->device_list_lock);
-}
-
-/*
- *  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)
-{
-       struct acpi_video_enumerated_device *ids;
-       int i;
-
-       for (i = 0; i < video->attached_count; i++) {
-               ids = &video->attached_array[i];
-               if (device->device_id == (ids->value.int_val & 0xffff)) {
-                       ids->bind_info = device;
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "device_bind %d\n", i));
-               }
-       }
-}
-
-static bool acpi_video_device_in_dod(struct acpi_video_device *device)
-{
-       struct acpi_video_bus *video = device->video;
-       int i;
-
-       /*
-        * If we have a broken _DOD or we have more than 8 output devices
-        * under the graphics controller node that we can't proper deal with
-        * in the operation region code currently, no need to test.
-        */
-       if (!video->attached_count || video->child_count > 8)
-               return true;
-
-       for (i = 0; i < video->attached_count; i++) {
-               if ((video->attached_array[i].value.int_val & 0xfff) ==
-                   (device->device_id & 0xfff))
-                       return true;
-       }
-
-       return false;
-}
-
-/*
- *  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_list;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *dod = NULL;
-       union acpi_object *obj;
-
-       status = acpi_evaluate_object(video->device->handle, "_DOD", NULL, &buffer);
-       if (!ACPI_SUCCESS(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Evaluating _DOD"));
-               return status;
-       }
-
-       dod = buffer.pointer;
-       if (!dod || (dod->type != ACPI_TYPE_PACKAGE)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Invalid _DOD data"));
-               status = -EFAULT;
-               goto out;
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d video heads in _DOD\n",
-                         dod->package.count));
-
-       active_list = kcalloc(1 + dod->package.count,
-                             sizeof(struct acpi_video_enumerated_device),
-                             GFP_KERNEL);
-       if (!active_list) {
-               status = -ENOMEM;
-               goto out;
-       }
-
-       count = 0;
-       for (i = 0; i < dod->package.count; i++) {
-               obj = &dod->package.elements[i];
-
-               if (obj->type != ACPI_TYPE_INTEGER) {
-                       printk(KERN_ERR PREFIX
-                               "Invalid _DOD data in element %d\n", i);
-                       continue;
-               }
-
-               active_list[count].value.int_val = obj->integer.value;
-               active_list[count].bind_info = NULL;
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "dod element[%d] = %d\n", i,
-                                 (int)obj->integer.value));
-               count++;
-       }
-
-       kfree(video->attached_array);
-
-       video->attached_array = active_list;
-       video->attached_count = count;
-
-out:
-       kfree(buffer.pointer);
-       return status;
-}
-
-static int
-acpi_video_get_next_level(struct acpi_video_device *device,
-                         u32 level_current, u32 event)
-{
-       int min, max, min_above, max_below, i, l, delta = 255;
-       max = max_below = 0;
-       min = min_above = 255;
-       /* Find closest level to level_current */
-       for (i = 2; i < device->brightness->count; i++) {
-               l = device->brightness->levels[i];
-               if (abs(l - level_current) < abs(delta)) {
-                       delta = l - level_current;
-                       if (!delta)
-                               break;
-               }
-       }
-       /* Ajust level_current to closest available level */
-       level_current += delta;
-       for (i = 2; i < device->brightness->count; i++) {
-               l = device->brightness->levels[i];
-               if (l < min)
-                       min = l;
-               if (l > max)
-                       max = l;
-               if (l < min_above && l > level_current)
-                       min_above = l;
-               if (l > max_below && l < level_current)
-                       max_below = l;
-       }
-
-       switch (event) {
-       case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:
-               return (level_current < max) ? min_above : min;
-       case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:
-               return (level_current < max) ? min_above : max;
-       case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:
-               return (level_current > min) ? max_below : min;
-       case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS:
-       case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:
-               return 0;
-       default:
-               return level_current;
-       }
-}
-
-static void
-acpi_video_switch_brightness(struct work_struct *work)
-{
-       struct acpi_video_device *device = container_of(to_delayed_work(work),
-                            struct acpi_video_device, switch_brightness_work);
-       unsigned long long level_current, level_next;
-       int event = device->switch_brightness_event;
-       int result = -EINVAL;
-
-       /* no warning message if acpi_backlight=vendor or a quirk is used */
-       if (!acpi_video_verify_backlight_support())
-               return;
-
-       if (!device->brightness)
-               goto out;
-
-       result = acpi_video_device_lcd_get_level_current(device,
-                                                        &level_current,
-                                                        false);
-       if (result)
-               goto out;
-
-       level_next = acpi_video_get_next_level(device, level_current, event);
-
-       result = acpi_video_device_lcd_set_level(device, level_next);
-
-       if (!result)
-               backlight_force_update(device->backlight,
-                                      BACKLIGHT_UPDATE_HOTKEY);
-
-out:
-       if (result)
-               printk(KERN_ERR PREFIX "Failed to switch the brightness\n");
-}
-
-int acpi_video_get_edid(struct acpi_device *device, int type, int device_id,
-                       void **edid)
-{
-       struct acpi_video_bus *video;
-       struct acpi_video_device *video_device;
-       union acpi_object *buffer = NULL;
-       acpi_status status;
-       int i, length;
-
-       if (!device || !acpi_driver_data(device))
-               return -EINVAL;
-
-       video = acpi_driver_data(device);
-
-       for (i = 0; i < video->attached_count; i++) {
-               video_device = video->attached_array[i].bind_info;
-               length = 256;
-
-               if (!video_device)
-                       continue;
-
-               if (!video_device->cap._DDC)
-                       continue;
-
-               if (type) {
-                       switch (type) {
-                       case ACPI_VIDEO_DISPLAY_CRT:
-                               if (!video_device->flags.crt)
-                                       continue;
-                               break;
-                       case ACPI_VIDEO_DISPLAY_TV:
-                               if (!video_device->flags.tvout)
-                                       continue;
-                               break;
-                       case ACPI_VIDEO_DISPLAY_DVI:
-                               if (!video_device->flags.dvi)
-                                       continue;
-                               break;
-                       case ACPI_VIDEO_DISPLAY_LCD:
-                               if (!video_device->flags.lcd)
-                                       continue;
-                               break;
-                       }
-               } else if (video_device->device_id != device_id) {
-                       continue;
-               }
-
-               status = acpi_video_device_EDID(video_device, &buffer, length);
-
-               if (ACPI_FAILURE(status) || !buffer ||
-                   buffer->type != ACPI_TYPE_BUFFER) {
-                       length = 128;
-                       status = acpi_video_device_EDID(video_device, &buffer,
-                                                       length);
-                       if (ACPI_FAILURE(status) || !buffer ||
-                           buffer->type != ACPI_TYPE_BUFFER) {
-                               continue;
-                       }
-               }
-
-               *edid = buffer->buffer.pointer;
-               return length;
-       }
-
-       return -ENODEV;
-}
-EXPORT_SYMBOL(acpi_video_get_edid);
-
-static int
-acpi_video_bus_get_devices(struct acpi_video_bus *video,
-                          struct acpi_device *device)
-{
-       int status = 0;
-       struct acpi_device *dev;
-
-       /*
-        * There are systems where video module known to work fine regardless
-        * of broken _DOD and ignoring returned value here doesn't cause
-        * any issues later.
-        */
-       acpi_video_device_enumerate(video);
-
-       list_for_each_entry(dev, &device->children, node) {
-
-               status = acpi_video_bus_get_one_device(dev, video);
-               if (status) {
-                       dev_err(&dev->dev, "Can't attach device\n");
-                       break;
-               }
-               video->child_count++;
-       }
-       return status;
-}
-
-/* acpi_video interface */
-
-/*
- * Win8 requires setting bit2 of _DOS to let firmware know it shouldn't
- * preform any automatic brightness change on receiving a notification.
- */
-static int acpi_video_bus_start_devices(struct acpi_video_bus *video)
-{
-       return acpi_video_bus_DOS(video, 0,
-                                 acpi_osi_is_win8() ? 1 : 0);
-}
-
-static int acpi_video_bus_stop_devices(struct acpi_video_bus *video)
-{
-       return acpi_video_bus_DOS(video, 0,
-                                 acpi_osi_is_win8() ? 0 : 1);
-}
-
-static void acpi_video_bus_notify(struct acpi_device *device, u32 event)
-{
-       struct acpi_video_bus *video = acpi_driver_data(device);
-       struct input_dev *input;
-       int keycode = 0;
-
-       if (!video || !video->input)
-               return;
-
-       input = video->input;
-
-       switch (event) {
-       case ACPI_VIDEO_NOTIFY_SWITCH:  /* User requested a switch,
-                                        * most likely via hotkey. */
-               keycode = KEY_SWITCHVIDEOMODE;
-               break;
-
-       case ACPI_VIDEO_NOTIFY_PROBE:   /* User plugged in or removed a video
-                                        * connector. */
-               acpi_video_device_enumerate(video);
-               acpi_video_device_rebind(video);
-               keycode = KEY_SWITCHVIDEOMODE;
-               break;
-
-       case ACPI_VIDEO_NOTIFY_CYCLE:   /* Cycle Display output hotkey pressed. */
-               keycode = KEY_SWITCHVIDEOMODE;
-               break;
-       case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:     /* Next Display output hotkey pressed. */
-               keycode = KEY_VIDEO_NEXT;
-               break;
-       case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:     /* previous Display output hotkey pressed. */
-               keycode = KEY_VIDEO_PREV;
-               break;
-
-       default:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Unsupported event [0x%x]\n", event));
-               break;
-       }
-
-       if (acpi_notifier_call_chain(device, event, 0))
-               /* Something vetoed the keypress. */
-               keycode = 0;
-
-       if (keycode) {
-               input_report_key(input, keycode, 1);
-               input_sync(input);
-               input_report_key(input, keycode, 0);
-               input_sync(input);
-       }
-
-       return;
-}
-
-static void brightness_switch_event(struct acpi_video_device *video_device,
-                                   u32 event)
-{
-       if (!brightness_switch_enabled)
-               return;
-
-       video_device->switch_brightness_event = event;
-       schedule_delayed_work(&video_device->switch_brightness_work, HZ / 10);
-}
-
-static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
-{
-       struct acpi_video_device *video_device = data;
-       struct acpi_device *device = NULL;
-       struct acpi_video_bus *bus;
-       struct input_dev *input;
-       int keycode = 0;
-
-       if (!video_device)
-               return;
-
-       device = video_device->dev;
-       bus = video_device->video;
-       input = bus->input;
-
-       switch (event) {
-       case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS:        /* Cycle brightness */
-               brightness_switch_event(video_device, event);
-               keycode = KEY_BRIGHTNESS_CYCLE;
-               break;
-       case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS:  /* Increase brightness */
-               brightness_switch_event(video_device, event);
-               keycode = KEY_BRIGHTNESSUP;
-               break;
-       case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS:  /* Decrease brightness */
-               brightness_switch_event(video_device, event);
-               keycode = KEY_BRIGHTNESSDOWN;
-               break;
-       case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightness */
-               brightness_switch_event(video_device, event);
-               keycode = KEY_BRIGHTNESS_ZERO;
-               break;
-       case ACPI_VIDEO_NOTIFY_DISPLAY_OFF:     /* display device off */
-               brightness_switch_event(video_device, event);
-               keycode = KEY_DISPLAY_OFF;
-               break;
-       default:
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Unsupported event [0x%x]\n", event));
-               break;
-       }
-
-       acpi_notifier_call_chain(device, event, 0);
-
-       if (keycode) {
-               input_report_key(input, keycode, 1);
-               input_sync(input);
-               input_report_key(input, keycode, 0);
-               input_sync(input);
-       }
-
-       return;
-}
-
-static int acpi_video_resume(struct notifier_block *nb,
-                               unsigned long val, void *ign)
-{
-       struct acpi_video_bus *video;
-       struct acpi_video_device *video_device;
-       int i;
-
-       switch (val) {
-       case PM_HIBERNATION_PREPARE:
-       case PM_SUSPEND_PREPARE:
-       case PM_RESTORE_PREPARE:
-               return NOTIFY_DONE;
-       }
-
-       video = container_of(nb, struct acpi_video_bus, pm_nb);
-
-       dev_info(&video->device->dev, "Restoring backlight state\n");
-
-       for (i = 0; i < video->attached_count; i++) {
-               video_device = video->attached_array[i].bind_info;
-               if (video_device && video_device->backlight)
-                       acpi_video_set_brightness(video_device->backlight);
-       }
-
-       return NOTIFY_OK;
-}
-
-static acpi_status
-acpi_video_bus_match(acpi_handle handle, u32 level, void *context,
-                       void **return_value)
-{
-       struct acpi_device *device = context;
-       struct acpi_device *sibling;
-       int result;
-
-       if (handle == device->handle)
-               return AE_CTRL_TERMINATE;
-
-       result = acpi_bus_get_device(handle, &sibling);
-       if (result)
-               return AE_OK;
-
-       if (!strcmp(acpi_device_name(sibling), ACPI_VIDEO_BUS_NAME))
-                       return AE_ALREADY_EXISTS;
-
-       return AE_OK;
-}
-
-static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
-{
-       struct backlight_properties props;
-       struct pci_dev *pdev;
-       acpi_handle acpi_parent;
-       struct device *parent = NULL;
-       int result;
-       static int count;
-       char *name;
-
-       /*
-        * Do not create backlight device for video output
-        * device that is not in the enumerated list.
-        */
-       if (!acpi_video_device_in_dod(device)) {
-               dev_dbg(&device->dev->dev, "not in _DOD list, ignore\n");
-               return;
-       }
-
-       result = acpi_video_init_brightness(device);
-       if (result)
-               return;
-       name = kasprintf(GFP_KERNEL, "acpi_video%d", count);
-       if (!name)
-               return;
-       count++;
-
-       acpi_get_parent(device->dev->handle, &acpi_parent);
-
-       pdev = acpi_get_pci_dev(acpi_parent);
-       if (pdev) {
-               parent = &pdev->dev;
-               pci_dev_put(pdev);
-       }
-
-       memset(&props, 0, sizeof(struct backlight_properties));
-       props.type = BACKLIGHT_FIRMWARE;
-       props.max_brightness = device->brightness->count - 3;
-       device->backlight = backlight_device_register(name,
-                                                     parent,
-                                                     device,
-                                                     &acpi_backlight_ops,
-                                                     &props);
-       kfree(name);
-       if (IS_ERR(device->backlight))
-               return;
-
-       /*
-        * Save current brightness level in case we have to restore it
-        * before acpi_video_device_lcd_set_level() is called next time.
-        */
-       device->backlight->props.brightness =
-                       acpi_video_get_brightness(device->backlight);
-
-       device->cooling_dev = thermal_cooling_device_register("LCD",
-                               device->dev, &video_cooling_ops);
-       if (IS_ERR(device->cooling_dev)) {
-               /*
-                * Set cooling_dev to NULL so we don't crash trying to free it.
-                * Also, why the hell we are returning early and not attempt to
-                * register video output if cooling device registration failed?
-                * -- dtor
-                */
-               device->cooling_dev = NULL;
-               return;
-       }
-
-       dev_info(&device->dev->dev, "registered as cooling_device%d\n",
-                device->cooling_dev->id);
-       result = sysfs_create_link(&device->dev->dev.kobj,
-                       &device->cooling_dev->device.kobj,
-                       "thermal_cooling");
-       if (result)
-               printk(KERN_ERR PREFIX "Create sysfs link\n");
-       result = sysfs_create_link(&device->cooling_dev->device.kobj,
-                       &device->dev->dev.kobj, "device");
-       if (result)
-               printk(KERN_ERR PREFIX "Create sysfs link\n");
-}
-
-static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
-{
-       struct acpi_video_device *dev;
-       union acpi_object *levels;
-
-       mutex_lock(&video->device_list_lock);
-       list_for_each_entry(dev, &video->video_device_list, entry) {
-               if (!acpi_video_device_lcd_query_levels(dev, &levels))
-                       kfree(levels);
-       }
-       mutex_unlock(&video->device_list_lock);
-}
-
-static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
-{
-       struct acpi_video_device *dev;
-
-       if (video->backlight_registered)
-               return 0;
-
-       acpi_video_run_bcl_for_osi(video);
-
-       if (!acpi_video_verify_backlight_support())
-               return 0;
-
-       mutex_lock(&video->device_list_lock);
-       list_for_each_entry(dev, &video->video_device_list, entry)
-               acpi_video_dev_register_backlight(dev);
-       mutex_unlock(&video->device_list_lock);
-
-       video->backlight_registered = true;
-
-       video->pm_nb.notifier_call = acpi_video_resume;
-       video->pm_nb.priority = 0;
-       return register_pm_notifier(&video->pm_nb);
-}
-
-static void acpi_video_dev_unregister_backlight(struct acpi_video_device *device)
-{
-       if (device->backlight) {
-               backlight_device_unregister(device->backlight);
-               device->backlight = NULL;
-       }
-       if (device->brightness) {
-               kfree(device->brightness->levels);
-               kfree(device->brightness);
-               device->brightness = NULL;
-       }
-       if (device->cooling_dev) {
-               sysfs_remove_link(&device->dev->dev.kobj, "thermal_cooling");
-               sysfs_remove_link(&device->cooling_dev->device.kobj, "device");
-               thermal_cooling_device_unregister(device->cooling_dev);
-               device->cooling_dev = NULL;
-       }
-}
-
-static int acpi_video_bus_unregister_backlight(struct acpi_video_bus *video)
-{
-       struct acpi_video_device *dev;
-       int error;
-
-       if (!video->backlight_registered)
-               return 0;
-
-       error = unregister_pm_notifier(&video->pm_nb);
-
-       mutex_lock(&video->device_list_lock);
-       list_for_each_entry(dev, &video->video_device_list, entry)
-               acpi_video_dev_unregister_backlight(dev);
-       mutex_unlock(&video->device_list_lock);
-
-       video->backlight_registered = false;
-
-       return error;
-}
-
-static void acpi_video_dev_add_notify_handler(struct acpi_video_device *device)
-{
-       acpi_status status;
-       struct acpi_device *adev = device->dev;
-
-       status = acpi_install_notify_handler(adev->handle, ACPI_DEVICE_NOTIFY,
-                                            acpi_video_device_notify, device);
-       if (ACPI_FAILURE(status))
-               dev_err(&adev->dev, "Error installing notify handler\n");
-       else
-               device->flags.notify = 1;
-}
-
-static int acpi_video_bus_add_notify_handler(struct acpi_video_bus *video)
-{
-       struct input_dev *input;
-       struct acpi_video_device *dev;
-       int error;
-
-       video->input = input = input_allocate_device();
-       if (!input) {
-               error = -ENOMEM;
-               goto out;
-       }
-
-       error = acpi_video_bus_start_devices(video);
-       if (error)
-               goto err_free_input;
-
-       snprintf(video->phys, sizeof(video->phys),
-                       "%s/video/input0", acpi_device_hid(video->device));
-
-       input->name = acpi_device_name(video->device);
-       input->phys = video->phys;
-       input->id.bustype = BUS_HOST;
-       input->id.product = 0x06;
-       input->dev.parent = &video->device->dev;
-       input->evbit[0] = BIT(EV_KEY);
-       set_bit(KEY_SWITCHVIDEOMODE, input->keybit);
-       set_bit(KEY_VIDEO_NEXT, input->keybit);
-       set_bit(KEY_VIDEO_PREV, input->keybit);
-       set_bit(KEY_BRIGHTNESS_CYCLE, input->keybit);
-       set_bit(KEY_BRIGHTNESSUP, input->keybit);
-       set_bit(KEY_BRIGHTNESSDOWN, input->keybit);
-       set_bit(KEY_BRIGHTNESS_ZERO, input->keybit);
-       set_bit(KEY_DISPLAY_OFF, input->keybit);
-
-       error = input_register_device(input);
-       if (error)
-               goto err_stop_dev;
-
-       mutex_lock(&video->device_list_lock);
-       list_for_each_entry(dev, &video->video_device_list, entry)
-               acpi_video_dev_add_notify_handler(dev);
-       mutex_unlock(&video->device_list_lock);
-
-       return 0;
-
-err_stop_dev:
-       acpi_video_bus_stop_devices(video);
-err_free_input:
-       input_free_device(input);
-       video->input = NULL;
-out:
-       return error;
-}
-
-static void acpi_video_dev_remove_notify_handler(struct acpi_video_device *dev)
-{
-       if (dev->flags.notify) {
-               acpi_remove_notify_handler(dev->dev->handle, ACPI_DEVICE_NOTIFY,
-                                          acpi_video_device_notify);
-               dev->flags.notify = 0;
-       }
-}
-
-static void acpi_video_bus_remove_notify_handler(struct acpi_video_bus *video)
-{
-       struct acpi_video_device *dev;
-
-       mutex_lock(&video->device_list_lock);
-       list_for_each_entry(dev, &video->video_device_list, entry)
-               acpi_video_dev_remove_notify_handler(dev);
-       mutex_unlock(&video->device_list_lock);
-
-       acpi_video_bus_stop_devices(video);
-       input_unregister_device(video->input);
-       video->input = NULL;
-}
-
-static int acpi_video_backlight_notify(struct notifier_block *nb,
-                                       unsigned long val, void *bd)
-{
-       struct backlight_device *backlight = bd;
-       struct acpi_video_bus *video;
-
-       /* acpi_video_verify_backlight_support only cares about raw devices */
-       if (backlight->props.type != BACKLIGHT_RAW)
-               return NOTIFY_DONE;
-
-       video = container_of(nb, struct acpi_video_bus, backlight_nb);
-
-       switch (val) {
-       case BACKLIGHT_REGISTERED:
-               if (!acpi_video_verify_backlight_support())
-                       acpi_video_bus_unregister_backlight(video);
-               break;
-       case BACKLIGHT_UNREGISTERED:
-               acpi_video_bus_register_backlight(video);
-               break;
-       }
-
-       return NOTIFY_OK;
-}
-
-static int acpi_video_bus_add_backlight_notify_handler(
-                                               struct acpi_video_bus *video)
-{
-       int error;
-
-       video->backlight_nb.notifier_call = acpi_video_backlight_notify;
-       video->backlight_nb.priority = 0;
-       error = backlight_register_notifier(&video->backlight_nb);
-       if (error == 0)
-               video->backlight_notifier_registered = true;
-
-       return error;
-}
-
-static int acpi_video_bus_remove_backlight_notify_handler(
-                                               struct acpi_video_bus *video)
-{
-       if (!video->backlight_notifier_registered)
-               return 0;
-
-       video->backlight_notifier_registered = false;
-
-       return backlight_unregister_notifier(&video->backlight_nb);
-}
-
-static int acpi_video_bus_put_devices(struct acpi_video_bus *video)
-{
-       struct acpi_video_device *dev, *next;
-
-       mutex_lock(&video->device_list_lock);
-       list_for_each_entry_safe(dev, next, &video->video_device_list, entry) {
-               list_del(&dev->entry);
-               kfree(dev);
-       }
-       mutex_unlock(&video->device_list_lock);
-
-       return 0;
-}
-
-static int instance;
-
-static int acpi_video_bus_add(struct acpi_device *device)
-{
-       struct acpi_video_bus *video;
-       int error;
-       acpi_status status;
-
-       status = acpi_walk_namespace(ACPI_TYPE_DEVICE,
-                               device->parent->handle, 1,
-                               acpi_video_bus_match, NULL,
-                               device, NULL);
-       if (status == AE_ALREADY_EXISTS) {
-               printk(KERN_WARNING FW_BUG
-                       "Duplicate ACPI video bus devices for the"
-                       " same VGA controller, please try module "
-                       "parameter \"video.allow_duplicates=1\""
-                       "if the current driver doesn't work.\n");
-               if (!allow_duplicates)
-                       return -ENODEV;
-       }
-
-       video = kzalloc(sizeof(struct acpi_video_bus), GFP_KERNEL);
-       if (!video)
-               return -ENOMEM;
-
-       /* a hack to fix the duplicate name "VID" problem on T61 */
-       if (!strcmp(device->pnp.bus_id, "VID")) {
-               if (instance)
-                       device->pnp.bus_id[3] = '0' + instance;
-               instance++;
-       }
-       /* a hack to fix the duplicate name "VGA" problem on Pa 3553 */
-       if (!strcmp(device->pnp.bus_id, "VGA")) {
-               if (instance)
-                       device->pnp.bus_id[3] = '0' + instance;
-               instance++;
-       }
-
-       video->device = device;
-       strcpy(acpi_device_name(device), ACPI_VIDEO_BUS_NAME);
-       strcpy(acpi_device_class(device), ACPI_VIDEO_CLASS);
-       device->driver_data = video;
-
-       acpi_video_bus_find_cap(video);
-       error = acpi_video_bus_check(video);
-       if (error)
-               goto err_free_video;
-
-       mutex_init(&video->device_list_lock);
-       INIT_LIST_HEAD(&video->video_device_list);
-
-       error = acpi_video_bus_get_devices(video, device);
-       if (error)
-               goto err_put_video;
-
-       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");
-       mutex_lock(&video_list_lock);
-       list_add_tail(&video->entry, &video_bus_head);
-       mutex_unlock(&video_list_lock);
-
-       acpi_video_bus_register_backlight(video);
-       acpi_video_bus_add_notify_handler(video);
-       acpi_video_bus_add_backlight_notify_handler(video);
-
-       return 0;
-
-err_put_video:
-       acpi_video_bus_put_devices(video);
-       kfree(video->attached_array);
-err_free_video:
-       kfree(video);
-       device->driver_data = NULL;
-
-       return error;
-}
-
-static int acpi_video_bus_remove(struct acpi_device *device)
-{
-       struct acpi_video_bus *video = NULL;
-
-
-       if (!device || !acpi_driver_data(device))
-               return -EINVAL;
-
-       video = acpi_driver_data(device);
-
-       acpi_video_bus_remove_backlight_notify_handler(video);
-       acpi_video_bus_remove_notify_handler(video);
-       acpi_video_bus_unregister_backlight(video);
-       acpi_video_bus_put_devices(video);
-
-       mutex_lock(&video_list_lock);
-       list_del(&video->entry);
-       mutex_unlock(&video_list_lock);
-
-       kfree(video->attached_array);
-       kfree(video);
-
-       return 0;
-}
-
-static int __init is_i740(struct pci_dev *dev)
-{
-       if (dev->device == 0x00D1)
-               return 1;
-       if (dev->device == 0x7000)
-               return 1;
-       return 0;
-}
-
-static int __init intel_opregion_present(void)
-{
-       int opregion = 0;
-       struct pci_dev *dev = NULL;
-       u32 address;
-
-       for_each_pci_dev(dev) {
-               if ((dev->class >> 8) != PCI_CLASS_DISPLAY_VGA)
-                       continue;
-               if (dev->vendor != PCI_VENDOR_ID_INTEL)
-                       continue;
-               /* We don't want to poke around undefined i740 registers */
-               if (is_i740(dev))
-                       continue;
-               pci_read_config_dword(dev, 0xfc, &address);
-               if (!address)
-                       continue;
-               opregion = 1;
-       }
-       return opregion;
-}
-
-int acpi_video_register(void)
-{
-       int ret;
-
-       if (register_count) {
-               /*
-                * if the function of acpi_video_register is already called,
-                * don't register the acpi_vide_bus again and return no error.
-                */
-               return 0;
-       }
-
-       mutex_init(&video_list_lock);
-       INIT_LIST_HEAD(&video_bus_head);
-
-       ret = acpi_bus_register_driver(&acpi_video_bus);
-       if (ret)
-               return ret;
-
-       /*
-        * When the acpi_video_bus is loaded successfully, increase
-        * the counter reference.
-        */
-       register_count = 1;
-
-       return 0;
-}
-EXPORT_SYMBOL(acpi_video_register);
-
-void acpi_video_unregister(void)
-{
-       if (!register_count) {
-               /*
-                * If the acpi video bus is already unloaded, don't
-                * unload it again and return directly.
-                */
-               return;
-       }
-       acpi_bus_unregister_driver(&acpi_video_bus);
-
-       register_count = 0;
-
-       return;
-}
-EXPORT_SYMBOL(acpi_video_unregister);
-
-void acpi_video_unregister_backlight(void)
-{
-       struct acpi_video_bus *video;
-
-       if (!register_count)
-               return;
-
-       mutex_lock(&video_list_lock);
-       list_for_each_entry(video, &video_bus_head, entry)
-               acpi_video_bus_unregister_backlight(video);
-       mutex_unlock(&video_list_lock);
-}
-EXPORT_SYMBOL(acpi_video_unregister_backlight);
-
-/*
- * This is kind of nasty. Hardware using Intel chipsets may require
- * the video opregion code to be run first in order to initialise
- * state before any ACPI video calls are made. To handle this we defer
- * registration of the video class until the opregion code has run.
- */
-
-static int __init acpi_video_init(void)
-{
-       /*
-        * Let the module load even if ACPI is disabled (e.g. due to
-        * a broken BIOS) so that i915.ko can still be loaded on such
-        * old systems without an AcpiOpRegion.
-        *
-        * acpi_video_register() will report -ENODEV later as well due
-        * to acpi_disabled when i915.ko tries to register itself afterwards.
-        */
-       if (acpi_disabled)
-               return 0;
-
-       dmi_check_system(video_dmi_table);
-
-       if (intel_opregion_present())
-               return 0;
-
-       return acpi_video_register();
-}
-
-static void __exit acpi_video_exit(void)
-{
-       acpi_video_unregister();
-
-       return;
-}
-
-module_init(acpi_video_init);
-module_exit(acpi_video_exit);
index c42feb2..815f75e 100644 (file)
 /*
+ *  Copyright (C) 2015       Red Hat Inc.
+ *                           Hans de Goede <hdegoede@redhat.com>
  *  Copyright (C) 2008       SuSE Linux Products GmbH
  *                           Thomas Renninger <trenn@suse.de>
  *
  *  May be copied or modified under the terms of the GNU General Public License
  *
  * video_detect.c:
- * Provides acpi_is_video_device() for early scanning of ACPI devices in scan.c
- * There a Linux specific (Spec does not provide a HID for video devices) is
- * assigned
- *
  * After PCI devices are glued with ACPI devices
  * acpi_get_pci_dev() can be called to identify ACPI graphics
  * devices for which a real graphics card is plugged in
  *
- * Now acpi_video_get_capabilities() can be called to check which
- * capabilities the graphics cards plugged in support. The check for general
- * video capabilities will be triggered by the first caller of
- * acpi_video_get_capabilities(NULL); which will happen when the first
- * backlight switching supporting driver calls:
- * acpi_video_backlight_support();
- *
  * Depending on whether ACPI graphics extensions (cmp. ACPI spec Appendix B)
  * are available, video.ko should be used to handle the device.
  *
  * Otherwise vendor specific drivers like thinkpad_acpi, asus-laptop,
  * sony_acpi,... can take care about backlight brightness.
  *
- * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
- * this file will not be compiled, acpi_video_get_capabilities() and
- * acpi_video_backlight_support() will always return 0 and vendor specific
- * drivers always can handle backlight.
+ * Backlight drivers can use acpi_video_get_backlight_type() to determine
+ * which driver should handle the backlight.
  *
+ * If CONFIG_ACPI_VIDEO is neither set as "compiled in" (y) nor as a module (m)
+ * this file will not be compiled and acpi_video_get_backlight_type() will
+ * always return acpi_backlight_vendor.
  */
 
 #include <linux/export.h>
 #include <linux/acpi.h>
+#include <linux/backlight.h>
 #include <linux/dmi.h>
+#include <linux/module.h>
 #include <linux/pci.h>
-
-#include "internal.h"
+#include <linux/types.h>
+#include <acpi/video.h>
 
 ACPI_MODULE_NAME("video");
 #define _COMPONENT             ACPI_VIDEO_COMPONENT
 
-static long acpi_video_support;
-static bool acpi_video_caps_checked;
+void acpi_video_unregister_backlight(void);
 
-static acpi_status
-acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
-                         void **return_value)
-{
-       long *cap = context;
+static bool backlight_notifier_registered;
+static struct notifier_block backlight_nb;
 
-       if (acpi_has_method(handle, "_BCM") &&
-           acpi_has_method(handle, "_BCL")) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight "
-                                 "support\n"));
-               *cap |= ACPI_VIDEO_BACKLIGHT;
-               if (!acpi_has_method(handle, "_BQC"))
-                       printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, "
-                               "cannot determine initial brightness\n");
-               /* We have backlight support, no need to scan further */
-               return AE_CTRL_TERMINATE;
-       }
-       return 0;
-}
+static enum acpi_backlight_type acpi_backlight_cmdline = acpi_backlight_undef;
+static enum acpi_backlight_type acpi_backlight_dmi = acpi_backlight_undef;
 
-/* Returns true if the ACPI object is a video device which can be
- * handled by video.ko.
- * The device will get a Linux specific CID added in scan.c to
- * identify the device as an ACPI graphics device
- * Be aware that the graphics device may not be physically present
- * Use acpi_video_get_capabilities() to detect general ACPI video
- * capabilities of present cards
- */
-long acpi_is_video_device(acpi_handle handle)
+static void acpi_video_parse_cmdline(void)
 {
-       long video_caps = 0;
-
-       /* Is this device able to support video switching ? */
-       if (acpi_has_method(handle, "_DOD") || acpi_has_method(handle, "_DOS"))
-               video_caps |= ACPI_VIDEO_OUTPUT_SWITCHING;
-
-       /* Is this device able to retrieve a video ROM ? */
-       if (acpi_has_method(handle, "_ROM"))
-               video_caps |= ACPI_VIDEO_ROM_AVAILABLE;
-
-       /* Is this device able to configure which video head to be POSTed ? */
-       if (acpi_has_method(handle, "_VPO") &&
-           acpi_has_method(handle, "_GPD") &&
-           acpi_has_method(handle, "_SPD"))
-               video_caps |= ACPI_VIDEO_DEVICE_POSTING;
-
-       /* Only check for backlight functionality if one of the above hit. */
-       if (video_caps)
-               acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
-                                   ACPI_UINT32_MAX, acpi_backlight_cap_match, NULL,
-                                   &video_caps, NULL);
-
-       return video_caps;
+       if (!strcmp("vendor", acpi_video_backlight_string))
+               acpi_backlight_cmdline = acpi_backlight_vendor;
+       if (!strcmp("video", acpi_video_backlight_string))
+               acpi_backlight_cmdline = acpi_backlight_video;
+       if (!strcmp("native", acpi_video_backlight_string))
+               acpi_backlight_cmdline = acpi_backlight_native;
+       if (!strcmp("none", acpi_video_backlight_string))
+               acpi_backlight_cmdline = acpi_backlight_none;
 }
-EXPORT_SYMBOL(acpi_is_video_device);
 
 static acpi_status
 find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
@@ -109,7 +64,7 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
        struct pci_dev *dev;
        struct acpi_device *acpi_dev;
 
-       const struct acpi_device_id video_ids[] = {
+       static const struct acpi_device_id video_ids[] = {
                {ACPI_VIDEO_HID, 0},
                {"", 0},
        };
@@ -130,11 +85,23 @@ find_video(acpi_handle handle, u32 lvl, void *context, void **rv)
  * buggy */
 static int video_detect_force_vendor(const struct dmi_system_id *d)
 {
-       acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
+       acpi_backlight_dmi = acpi_backlight_vendor;
+       return 0;
+}
+
+static int video_detect_force_video(const struct dmi_system_id *d)
+{
+       acpi_backlight_dmi = acpi_backlight_video;
        return 0;
 }
 
-static struct dmi_system_id video_detect_dmi_table[] = {
+static int video_detect_force_native(const struct dmi_system_id *d)
+{
+       acpi_backlight_dmi = acpi_backlight_native;
+       return 0;
+}
+
+static const struct dmi_system_id video_detect_dmi_table[] = {
        /* On Samsung X360, the BIOS will set a flag (VDRV) if generic
         * ACPI backlight device is used. This flag will definitively break
         * the backlight interface (even the vendor interface) untill next
@@ -174,137 +141,209 @@ static struct dmi_system_id video_detect_dmi_table[] = {
                DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 5737"),
                },
        },
+
+       /*
+        * These models have a working acpi_video backlight control, and using
+        * native backlight causes a regression where backlight does not work
+        * when userspace is not handling brightness key events. Disable
+        * native_backlight on these to fix this:
+        * https://bugzilla.kernel.org/show_bug.cgi?id=81691
+        */
+       {
+        .callback = video_detect_force_video,
+        .ident = "ThinkPad T420",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T420"),
+               },
+       },
+       {
+        .callback = video_detect_force_video,
+        .ident = "ThinkPad T520",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad T520"),
+               },
+       },
+       {
+        .callback = video_detect_force_video,
+        .ident = "ThinkPad X201s",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_VERSION, "ThinkPad X201s"),
+               },
+       },
+
+       /* The native backlight controls do not work on some older machines */
+       {
+        /* https://bugs.freedesktop.org/show_bug.cgi?id=81515 */
+        .callback = video_detect_force_video,
+        .ident = "HP ENVY 15 Notebook",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY 15 Notebook PC"),
+               },
+       },
+       {
+        .callback = video_detect_force_video,
+        .ident = "SAMSUNG 870Z5E/880Z5E/680Z5E",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "870Z5E/880Z5E/680Z5E"),
+               },
+       },
+       {
+        .callback = video_detect_force_video,
+        .ident = "SAMSUNG 370R4E/370R4V/370R5E/3570RE/370R5V",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME,
+                         "370R4E/370R4V/370R5E/3570RE/370R5V"),
+               },
+       },
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
+        .callback = video_detect_force_video,
+        .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME,
+                         "3570R/370R/470R/450R/510R/4450RV"),
+               },
+       },
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
+        .callback = video_detect_force_video,
+        .ident = "SAMSUNG 730U3E/740U3E",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
+               },
+       },
+       {
+        /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
+        .callback = video_detect_force_video,
+        .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+               DMI_MATCH(DMI_PRODUCT_NAME,
+                         "900X3C/900X3D/900X3E/900X4C/900X4D"),
+               },
+       },
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
+        .callback = video_detect_force_video,
+        .ident = "Dell XPS15 L521X",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "XPS L521X"),
+               },
+       },
+
+       /* Non win8 machines which need native backlight nevertheless */
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1187004 */
+        .callback = video_detect_force_native,
+        .ident = "Lenovo Ideapad Z570",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+               DMI_MATCH(DMI_PRODUCT_NAME, "102434U"),
+               },
+       },
+       {
+        /* https://bugzilla.redhat.com/show_bug.cgi?id=1217249 */
+        .callback = video_detect_force_native,
+        .ident = "Apple MacBook Pro 12,1",
+        .matches = {
+               DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+               DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro12,1"),
+               },
+       },
        { },
 };
 
+static int acpi_video_backlight_notify(struct notifier_block *nb,
+                                      unsigned long val, void *bd)
+{
+       struct backlight_device *backlight = bd;
+
+       /* A raw bl registering may change video -> native */
+       if (backlight->props.type == BACKLIGHT_RAW &&
+           val == BACKLIGHT_REGISTERED &&
+           acpi_video_get_backlight_type() != acpi_backlight_video)
+               acpi_video_unregister_backlight();
+
+       return NOTIFY_OK;
+}
+
 /*
- * Returns the video capabilities of a specific ACPI graphics device
+ * Determine which type of backlight interface to use on this system,
+ * First check cmdline, then dmi quirks, then do autodetect.
  *
- * if NULL is passed as argument all ACPI devices are enumerated and
- * all graphics capabilities of physically present devices are
- * summarized and returned. This is cached and done only once.
+ * The autodetect order is:
+ * 1) Is the acpi-video backlight interface supported ->
+ *  no, use a vendor interface
+ * 2) Is this a win8 "ready" BIOS and do we have a native interface ->
+ *  yes, use a native interface
+ * 3) Else use the acpi-video interface
+ *
+ * Arguably the native on win8 check should be done first, but that would
+ * be a behavior change, which may causes issues.
  */
-long acpi_video_get_capabilities(acpi_handle graphics_handle)
+enum acpi_backlight_type acpi_video_get_backlight_type(void)
 {
-       long caps = 0;
-       struct acpi_device *tmp_dev;
-       acpi_status status;
-
-       if (acpi_video_caps_checked && graphics_handle == NULL)
-               return acpi_video_support;
-
-       if (!graphics_handle) {
-               /* Only do the global walk through all graphics devices once */
-               acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
-                                   ACPI_UINT32_MAX, find_video, NULL,
-                                   &caps, NULL);
-               /* There might be boot param flags set already... */
-               acpi_video_support |= caps;
-               acpi_video_caps_checked = 1;
-               /* Add blacklists here. Be careful to use the right *DMI* bits
-                * to still be able to override logic via boot params, e.g.:
-                *
-                *   if (dmi_name_in_vendors("XY")) {
-                *      acpi_video_support |=
-                *              ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
-                *}
-                */
+       static DEFINE_MUTEX(init_mutex);
+       static bool init_done;
+       static long video_caps;
 
+       /* Parse cmdline, dmi and acpi only once */
+       mutex_lock(&init_mutex);
+       if (!init_done) {
+               acpi_video_parse_cmdline();
                dmi_check_system(video_detect_dmi_table);
-       } else {
-               status = acpi_bus_get_device(graphics_handle, &tmp_dev);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_EXCEPTION((AE_INFO, status, "Invalid device"));
-                       return 0;
-               }
-               acpi_walk_namespace(ACPI_TYPE_DEVICE, graphics_handle,
+               acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
                                    ACPI_UINT32_MAX, find_video, NULL,
-                                   &caps, NULL);
+                                   &video_caps, NULL);
+               backlight_nb.notifier_call = acpi_video_backlight_notify;
+               backlight_nb.priority = 0;
+               if (backlight_register_notifier(&backlight_nb) == 0)
+                       backlight_notifier_registered = true;
+               init_done = true;
        }
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "We have 0x%lX video support %s %s\n",
-                         graphics_handle ? caps : acpi_video_support,
-                         graphics_handle ? "on device " : "in general",
-                         graphics_handle ? acpi_device_bid(tmp_dev) : ""));
-       return caps;
-}
-EXPORT_SYMBOL(acpi_video_get_capabilities);
+       mutex_unlock(&init_mutex);
 
-static void acpi_video_caps_check(void)
-{
-       /*
-        * We must check whether the ACPI graphics device is physically plugged
-        * in. Therefore this must be called after binding PCI and ACPI devices
-        */
-       if (!acpi_video_caps_checked)
-               acpi_video_get_capabilities(NULL);
-}
+       if (acpi_backlight_cmdline != acpi_backlight_undef)
+               return acpi_backlight_cmdline;
 
-bool acpi_osi_is_win8(void)
-{
-       return acpi_gbl_osi_data >= ACPI_OSI_WIN_8;
-}
-EXPORT_SYMBOL(acpi_osi_is_win8);
+       if (acpi_backlight_dmi != acpi_backlight_undef)
+               return acpi_backlight_dmi;
 
-/* Promote the vendor interface instead of the generic video module.
- * This function allow DMI blacklists to be implemented by externals
- * platform drivers instead of putting a big blacklist in video_detect.c
- * After calling this function you will probably want to call
- * acpi_video_unregister() to make sure the video module is not loaded
- */
-void acpi_video_dmi_promote_vendor(void)
-{
-       acpi_video_caps_check();
-       acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
-}
-EXPORT_SYMBOL(acpi_video_dmi_promote_vendor);
-
-/* To be called when a driver who previously promoted the vendor
- * interface */
-void acpi_video_dmi_demote_vendor(void)
-{
-       acpi_video_caps_check();
-       acpi_video_support &= ~ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
-}
-EXPORT_SYMBOL(acpi_video_dmi_demote_vendor);
-
-/* Returns true if video.ko can do backlight switching */
-int acpi_video_backlight_support(void)
-{
-       acpi_video_caps_check();
-
-       /* First check for boot param -> highest prio */
-       if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR)
-               return 0;
-       else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO)
-               return 1;
+       if (!(video_caps & ACPI_VIDEO_BACKLIGHT))
+               return acpi_backlight_vendor;
 
-       /* Then check for DMI blacklist -> second highest prio */
-       if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VENDOR)
-               return 0;
-       else if (acpi_video_support & ACPI_VIDEO_BACKLIGHT_DMI_VIDEO)
-               return 1;
+       if (acpi_osi_is_win8() && backlight_device_registered(BACKLIGHT_RAW))
+               return acpi_backlight_native;
 
-       /* Then go the default way */
-       return acpi_video_support & ACPI_VIDEO_BACKLIGHT;
+       return acpi_backlight_video;
 }
-EXPORT_SYMBOL(acpi_video_backlight_support);
+EXPORT_SYMBOL(acpi_video_get_backlight_type);
 
 /*
- * Use acpi_backlight=vendor/video to force that backlight switching
- * is processed by vendor specific acpi drivers or video.ko driver.
+ * Set the preferred backlight interface type based on DMI info.
+ * This function allows DMI blacklists to be implemented by external
+ * platform drivers instead of putting a big blacklist in video_detect.c
  */
-static int __init acpi_backlight(char *str)
+void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
 {
-       if (str == NULL || *str == '\0')
-               return 1;
-       else {
-               if (!strcmp("vendor", str))
-                       acpi_video_support |=
-                               ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR;
-               if (!strcmp("video", str))
-                       acpi_video_support |=
-                               ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO;
-       }
-       return 1;
+       acpi_backlight_dmi = type;
+       /* Remove acpi-video backlight interface if it is no longer desired */
+       if (acpi_video_get_backlight_type() != acpi_backlight_video)
+               acpi_video_unregister_backlight();
+}
+EXPORT_SYMBOL(acpi_video_set_dmi_backlight_type);
+
+void __exit acpi_video_detect_exit(void)
+{
+       if (backlight_notifier_registered)
+               backlight_unregister_notifier(&backlight_nb);
 }
-__setup("acpi_backlight=", acpi_backlight);
index 71e87ab..4813374 100644 (file)
@@ -396,16 +396,6 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state)
        return -EINVAL;
 }
 
-/*
- * If the vendor backlight interface is not in use and ACPI backlight interface
- * is broken, do not bother processing backlight change requests from firmware.
- */
-static bool should_ignore_backlight_request(void)
-{
-       return acpi_video_backlight_support() &&
-              !acpi_video_verify_backlight_support();
-}
-
 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -414,7 +404,7 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 
        DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
 
-       if (should_ignore_backlight_request()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_native) {
                DRM_DEBUG_KMS("opregion backlight request ignored\n");
                return 0;
        }
index 6f6f175..314a625 100644 (file)
@@ -420,7 +420,7 @@ static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
                [PCI_D0] = ACPI_STATE_D0,
                [PCI_D1] = ACPI_STATE_D1,
                [PCI_D2] = ACPI_STATE_D2,
-               [PCI_D3hot] = ACPI_STATE_D3_COLD,
+               [PCI_D3hot] = ACPI_STATE_D3_HOT,
                [PCI_D3cold] = ACPI_STATE_D3_COLD,
        };
        int error = -EINVAL;
index f9f205c..909133c 100644 (file)
@@ -71,9 +71,10 @@ config ASUS_LAPTOP
        depends on ACPI
        select LEDS_CLASS
        select NEW_LEDS
-       select BACKLIGHT_CLASS_DEVICE
+       depends on BACKLIGHT_CLASS_DEVICE
        depends on INPUT
        depends on RFKILL || RFKILL = n
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        select INPUT_SPARSEKMAP
        select INPUT_POLLDEV
        ---help---
@@ -95,6 +96,7 @@ config DELL_LAPTOP
        depends on X86
        depends on DCDBAS
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on RFKILL || RFKILL = n
        depends on SERIO_I8042
        select POWER_SUPPLY
@@ -109,6 +111,7 @@ config DELL_WMI
        tristate "Dell WMI extras"
        depends on ACPI_WMI
        depends on INPUT
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        select INPUT_SPARSEKMAP
        ---help---
          Say Y here if you want to support WMI-based hotkeys on Dell laptops.
@@ -144,6 +147,7 @@ config FUJITSU_LAPTOP
        depends on ACPI
        depends on INPUT
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on LEDS_CLASS || LEDS_CLASS=n
        ---help---
          This is a driver for laptops built by Fujitsu:
@@ -247,6 +251,7 @@ config MSI_LAPTOP
        tristate "MSI Laptop Extras"
        depends on ACPI
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on RFKILL
        depends on INPUT && SERIO_I8042
        select INPUT_SPARSEKMAP
@@ -280,6 +285,7 @@ config COMPAL_LAPTOP
        tristate "Compal (and others) Laptop Extras"
        depends on ACPI
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on RFKILL
        depends on HWMON
        depends on POWER_SUPPLY
@@ -296,7 +302,8 @@ config COMPAL_LAPTOP
 config SONY_LAPTOP
        tristate "Sony Laptop Extras"
        depends on ACPI
-       select BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
+       depends on BACKLIGHT_CLASS_DEVICE
        depends on INPUT
        depends on RFKILL
          ---help---
@@ -321,6 +328,7 @@ config IDEAPAD_LAPTOP
        depends on RFKILL && INPUT
        depends on SERIO_I8042
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        select INPUT_SPARSEKMAP
        help
          This is a driver for Lenovo IdeaPad netbooks contains drivers for
@@ -331,8 +339,8 @@ config THINKPAD_ACPI
        depends on ACPI
        depends on INPUT
        depends on RFKILL || RFKILL = n
-       select BACKLIGHT_LCD_SUPPORT
-       select BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
+       depends on BACKLIGHT_CLASS_DEVICE
        select HWMON
        select NVRAM
        select NEW_LEDS
@@ -500,8 +508,9 @@ config EEEPC_LAPTOP
        depends on ACPI
        depends on INPUT
        depends on RFKILL || RFKILL = n
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on HOTPLUG_PCI
-       select BACKLIGHT_CLASS_DEVICE
+       depends on BACKLIGHT_CLASS_DEVICE
        select HWMON
        select LEDS_CLASS
        select NEW_LEDS
@@ -587,6 +596,7 @@ config MSI_WMI
        depends on ACPI_WMI
        depends on INPUT
        depends on BACKLIGHT_CLASS_DEVICE
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        select INPUT_SPARSEKMAP
        help
         Say Y here if you want to support WMI-based hotkeys on MSI laptops.
@@ -824,6 +834,7 @@ config MXM_WMI
 config INTEL_OAKTRAIL
        tristate "Intel Oaktrail Platform Extras"
        depends on ACPI
+       depends on ACPI_VIDEO || ACPI_VIDEO = n
        depends on RFKILL && BACKLIGHT_CLASS_DEVICE && ACPI
        ---help---
          Intel Oaktrail platform need this driver to provide interfaces to
index 3ac29a1..f6b280d 100644 (file)
@@ -2246,14 +2246,10 @@ static int __init acer_wmi_init(void)
        set_quirks();
 
        if (dmi_check_system(video_vendor_dmi_table))
-               acpi_video_dmi_promote_vendor();
-       if (acpi_video_backlight_support()) {
+               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
+
+       if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                interface->capability &= ~ACER_CAP_BRIGHTNESS;
-               pr_info("Brightness must be controlled by acpi video driver\n");
-       } else {
-               pr_info("Disabling ACPI video driver\n");
-               acpi_video_unregister_backlight();
-       }
 
        if (wmi_has_guid(WMID_GUID3)) {
                if (ec_raw_mode) {
index 6808715..0dec3f5 100644 (file)
@@ -550,8 +550,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
         * backlight control and supports more levels than other options.
         * Disable the other backlight choices.
         */
-       acpi_video_dmi_promote_vendor();
-       acpi_video_unregister();
+       acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
        apple_bl_unregister();
 
        gmux_data->power_state = VGA_SWITCHEROO_ON;
@@ -645,7 +644,6 @@ static void gmux_remove(struct pnp_dev *pnp)
        apple_gmux_data = NULL;
        kfree(gmux_data);
 
-       acpi_video_dmi_demote_vendor();
        acpi_video_register();
        apple_bl_register();
 }
index 46b2746..58d29c4 100644 (file)
@@ -54,6 +54,7 @@
 #include <linux/slab.h>
 #include <linux/dmi.h>
 #include <linux/acpi.h>
+#include <acpi/video.h>
 
 #define ASUS_LAPTOP_VERSION    "0.42"
 
@@ -1884,12 +1885,11 @@ static int asus_acpi_add(struct acpi_device *device)
        if (result)
                goto fail_platform;
 
-       if (!acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                result = asus_backlight_init(asus);
                if (result)
                        goto fail_backlight;
-       } else
-               pr_info("Backlight controlled by ACPI video driver\n");
+       }
 
        result = asus_input_init(asus);
        if (result)
index 7543a56..6f8558f 100644 (file)
@@ -1364,7 +1364,7 @@ static void asus_wmi_notify(u32 value, void *context)
                code = ASUS_WMI_BRN_DOWN;
 
        if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) {
-               if (!acpi_video_backlight_support()) {
+               if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                        asus_wmi_backlight_notify(asus, orig_code);
                        goto exit;
                }
@@ -1772,17 +1772,16 @@ static int asus_wmi_add(struct platform_device *pdev)
           stop this from showing up */
        chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
        if (chassis_type && !strcmp(chassis_type, "3"))
-               acpi_video_dmi_promote_vendor();
+               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
+
        if (asus->driver->quirks->wmi_backlight_power)
-               acpi_video_dmi_promote_vendor();
-       if (!acpi_video_backlight_support()) {
-               pr_info("Disabling ACPI video driver\n");
-               acpi_video_unregister();
+               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
+
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                err = asus_wmi_backlight_init(asus);
                if (err && err != -ENODEV)
                        goto fail_backlight;
-       } else
-               pr_info("Backlight controlled by ACPI video driver\n");
+       }
 
        status = wmi_install_notify_handler(asus->driver->event_guid,
                                            asus_wmi_notify, asus);
index b4e9447..f2706d2 100644 (file)
@@ -82,7 +82,7 @@
 #include <linux/hwmon-sysfs.h>
 #include <linux/power_supply.h>
 #include <linux/fb.h>
-
+#include <acpi/video.h>
 
 /* ======= */
 /* Defines */
@@ -959,7 +959,7 @@ static int __init compal_init(void)
                return -ENODEV;
        }
 
-       if (!acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
                props.type = BACKLIGHT_PLATFORM;
index d688d80..01d0810 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
+#include <acpi/video.h>
 #include "../../firmware/dcdbas.h"
 
 #define BRIGHTNESS_TOKEN 0x7d
@@ -1920,13 +1921,8 @@ static int __init dell_init(void)
                debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
                                    &dell_debugfs_fops);
 
-#ifdef CONFIG_ACPI
-       /* In the event of an ACPI backlight being available, don't
-        * register the platform controller.
-        */
-       if (acpi_video_backlight_support())
+       if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                return 0;
-#endif
 
        get_buffer();
        buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN);
index 6512a06..f2d77fe 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/acpi.h>
 #include <linux/string.h>
 #include <linux/dmi.h>
+#include <acpi/video.h>
 
 MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
 MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
@@ -397,7 +398,7 @@ static int __init dell_wmi_init(void)
        }
 
        dmi_walk(find_hk_type, NULL);
-       acpi_video = acpi_video_backlight_support();
+       acpi_video = acpi_video_get_backlight_type() != acpi_backlight_vendor;
 
        err = dell_wmi_input_setup();
        if (err)
index 844c209..8cdf315 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/pci_hotplug.h>
 #include <linux/leds.h>
 #include <linux/dmi.h>
+#include <acpi/video.h>
 
 #define EEEPC_LAPTOP_VERSION   "0.1"
 #define EEEPC_LAPTOP_NAME      "Eee PC Hotkey Driver"
@@ -1433,12 +1434,10 @@ static int eeepc_acpi_add(struct acpi_device *device)
        if (result)
                goto fail_platform;
 
-       if (!acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                result = eeepc_backlight_init(eeepc);
                if (result)
                        goto fail_backlight;
-       } else {
-               pr_info("Backlight controlled by ACPI video driver\n");
        }
 
        result = eeepc_input_init(eeepc);
index 2a9afa2..1c62caf 100644 (file)
@@ -72,6 +72,7 @@
 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
 #include <linux/leds.h>
 #endif
+#include <acpi/video.h>
 
 #define FUJITSU_DRIVER_VERSION "0.6.0"
 
@@ -1099,7 +1100,7 @@ static int __init fujitsu_init(void)
 
        /* Register backlight stuff */
 
-       if (!acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                struct backlight_properties props;
 
                memset(&props, 0, sizeof(struct backlight_properties));
@@ -1137,8 +1138,7 @@ static int __init fujitsu_init(void)
        }
 
        /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */
-
-       if (!acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
                        fujitsu->bl_device->props.power = FB_BLANK_POWERDOWN;
                else
index b496db8..bea0228 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/i8042.h>
 #include <linux/dmi.h>
 #include <linux/device.h>
+#include <acpi/video.h>
 
 #define IDEAPAD_RFKILL_DEV_NUM (3)
 
@@ -903,7 +904,7 @@ static int ideapad_acpi_add(struct platform_device *pdev)
        ideapad_sync_rfk_state(priv);
        ideapad_sync_touchpad_state(priv);
 
-       if (!acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                ret = ideapad_backlight_init(priv);
                if (ret && ret != -ENODEV)
                        goto backlight_failed;
index 8037c8b..6aa33c4 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/platform_device.h>
 #include <linux/dmi.h>
 #include <linux/rfkill.h>
+#include <acpi/video.h>
 
 #define DRIVER_NAME    "intel_oaktrail"
 #define DRIVER_VERSION "0.4ac1"
@@ -343,13 +344,11 @@ static int __init oaktrail_init(void)
                goto err_device_add;
        }
 
-       if (!acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                ret = oaktrail_backlight_init();
                if (ret)
                        goto err_backlight;
-
-       } else
-               pr_info("Backlight controlled by ACPI video driver\n");
+       }
 
        ret = oaktrail_rfkill_init();
        if (ret) {
index 0859877..4231770 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/i8042.h>
 #include <linux/input.h>
 #include <linux/input/sparse-keymap.h>
+#include <acpi/video.h>
 
 #define MSI_DRIVER_VERSION "0.5"
 
@@ -1069,9 +1070,8 @@ static int __init msi_init(void)
 
        /* Register backlight stuff */
 
-       if (!quirks->old_ec_model || acpi_video_backlight_support()) {
-               pr_info("Brightness ignored, must be controlled by ACPI video driver\n");
-       } else {
+       if (quirks->old_ec_model ||
+           acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                struct backlight_properties props;
                memset(&props, 0, sizeof(struct backlight_properties));
                props.type = BACKLIGHT_PLATFORM;
index 6d2bac0..978e6d6 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/backlight.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <acpi/video.h>
 
 MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
 MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver");
@@ -320,7 +321,8 @@ static int __init msi_wmi_init(void)
                break;
        }
 
-       if (wmi_has_guid(MSIWMI_BIOS_GUID) && !acpi_video_backlight_support()) {
+       if (wmi_has_guid(MSIWMI_BIOS_GUID) &&
+           acpi_video_get_backlight_type() == acpi_backlight_vendor) {
                err = msi_wmi_backlight_setup();
                if (err) {
                        pr_err("Unable to setup backlight device\n");
index 9e701b2..8c146e2 100644 (file)
@@ -1720,27 +1720,14 @@ static int __init samsung_init(void)
        samsung->handle_backlight = true;
        samsung->quirks = quirks;
 
-
 #ifdef CONFIG_ACPI
        if (samsung->quirks->broken_acpi_video)
-               acpi_video_dmi_promote_vendor();
-
-       /* Don't handle backlight here if the acpi video already handle it */
-       if (acpi_video_backlight_support()) {
-               samsung->handle_backlight = false;
-       } else if (samsung->quirks->broken_acpi_video) {
-               pr_info("Disabling ACPI video driver\n");
-               acpi_video_unregister();
-       }
+               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
+       if (samsung->quirks->use_native_backlight)
+               acpi_video_set_dmi_backlight_type(acpi_backlight_native);
 
-       if (samsung->quirks->use_native_backlight) {
-               pr_info("Using native backlight driver\n");
-               /* Tell acpi-video to not handle the backlight */
-               acpi_video_dmi_promote_vendor();
-               acpi_video_unregister();
-               /* And also do not handle it ourselves */
+       if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                samsung->handle_backlight = false;
-       }
 #endif
 
        ret = samsung_platform_init(samsung);
@@ -1751,12 +1738,6 @@ static int __init samsung_init(void)
        if (ret)
                goto error_sabi;
 
-#ifdef CONFIG_ACPI
-       /* Only log that if we are really on a sabi platform */
-       if (acpi_video_backlight_support())
-               pr_info("Backlight controlled by ACPI video driver\n");
-#endif
-
        ret = samsung_sysfs_init(samsung);
        if (ret)
                goto error_sysfs;
index e51c1e7..aeb80d1 100644 (file)
@@ -69,6 +69,7 @@
 #include <linux/miscdevice.h>
 #endif
 #include <asm/uaccess.h>
+#include <acpi/video.h>
 
 #define dprintk(fmt, ...)                      \
 do {                                           \
@@ -3198,12 +3199,8 @@ static int sony_nc_add(struct acpi_device *device)
                        sony_nc_function_setup(device, sony_pf_device);
        }
 
-       /* setup input devices and helper fifo */
-       if (acpi_video_backlight_support()) {
-               pr_info("brightness ignored, must be controlled by ACPI video driver\n");
-       } else {
+       if (acpi_video_get_backlight_type() == acpi_backlight_vendor)
                sony_nc_backlight_setup();
-       }
 
        /* create sony_pf sysfs attributes related to the SNC device */
        for (item = sony_nc_values; item->name; ++item) {
index 28f3281..33e488c 100644 (file)
@@ -83,6 +83,7 @@
 #include <sound/control.h>
 #include <sound/initval.h>
 #include <asm/uaccess.h>
+#include <acpi/video.h>
 
 /* ThinkPad CMOS commands */
 #define TP_CMOS_VOLUME_DOWN    0
@@ -3487,7 +3488,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
        /* Do not issue duplicate brightness change events to
         * userspace. tpacpi_detect_brightness_capabilities() must have
         * been called before this point  */
-       if (acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() != acpi_backlight_vendor) {
                pr_info("This ThinkPad has standard ACPI backlight "
                        "brightness control, supported by the ACPI "
                        "video driver\n");
@@ -6491,7 +6492,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                return 1;
        }
 
-       if (acpi_video_backlight_support()) {
+       if (acpi_video_get_backlight_type() != acpi_backlight_vendor) {
                if (brightness_enable > 1) {
                        pr_info("Standard ACPI backlight interface "
                                "available, not loading native one\n");
index 9956b99..59bf27e 100644 (file)
@@ -2640,14 +2640,11 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
         */
        if (dev->tr_backlight_supported ||
            dmi_check_system(toshiba_vendor_backlight_dmi))
-               acpi_video_dmi_promote_vendor();
+               acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);
 
-       if (acpi_video_backlight_support())
+       if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
                return 0;
 
-       /* acpi-video may have loaded before we called dmi_promote_vendor() */
-       acpi_video_unregister_backlight();
-
        memset(&props, 0, sizeof(props));
        props.type = BACKLIGHT_PLATFORM;
        props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
index 49c1720..515f338 100644 (file)
@@ -7,6 +7,7 @@
  *     Bjorn Helgaas <bjorn.helgaas@hp.com>
  */
 
+#include <linux/acpi.h>
 #include <linux/pnp.h>
 #include <linux/device.h>
 #include <linux/init.h>
@@ -22,25 +23,41 @@ static const struct pnp_device_id pnp_dev_table[] = {
        {"", 0}
 };
 
+#ifdef CONFIG_ACPI
+static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
+{
+       u8 space_id = io ? ACPI_ADR_SPACE_SYSTEM_IO : ACPI_ADR_SPACE_SYSTEM_MEMORY;
+       return !acpi_reserve_region(start, length, space_id, IORESOURCE_BUSY, desc);
+}
+#else
+static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
+{
+       struct resource *res;
+
+       res = io ? request_region(start, length, desc) :
+               request_mem_region(start, length, desc);
+       if (res) {
+               res->flags &= ~IORESOURCE_BUSY;
+               return true;
+       }
+       return false;
+}
+#endif
+
 static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
 {
        char *regionid;
        const char *pnpid = dev_name(&dev->dev);
        resource_size_t start = r->start, end = r->end;
-       struct resource *res;
+       bool reserved;
 
        regionid = kmalloc(16, GFP_KERNEL);
        if (!regionid)
                return;
 
        snprintf(regionid, 16, "pnp %s", pnpid);
-       if (port)
-               res = request_region(start, end - start + 1, regionid);
-       else
-               res = request_mem_region(start, end - start + 1, regionid);
-       if (res)
-               res->flags &= ~IORESOURCE_BUSY;
-       else
+       reserved = __reserve_range(start, end - start + 1, !!port, regionid);
+       if (!reserved)
                kfree(regionid);
 
        /*
@@ -49,7 +66,7 @@ static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
         * have double reservations.
         */
        dev_info(&dev->dev, "%pR %s reserved\n", r,
-                res ? "has been" : "could not be");
+                reserved ? "has been" : "could not be");
 }
 
 static void reserve_resources_of_dev(struct pnp_dev *dev)
index 3e62ee4..f4a3694 100644 (file)
@@ -46,13 +46,7 @@ static int xen_acpi_processor_enable(struct acpi_device *device)
        unsigned long long value;
        union acpi_object object = { 0 };
        struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
-       struct acpi_processor *pr;
-
-       pr = acpi_driver_data(device);
-       if (!pr) {
-               pr_err(PREFIX "Cannot find driver data\n");
-               return -EINVAL;
-       }
+       struct acpi_processor *pr = acpi_driver_data(device);
 
        if (!strcmp(acpi_device_hid(device), ACPI_PROCESSOR_OBJECT_HID)) {
                /* Declared with "Processor" statement; match ProcessorID */
@@ -77,7 +71,7 @@ static int xen_acpi_processor_enable(struct acpi_device *device)
 
        pr->id = xen_pcpu_id(pr->acpi_id);
 
-       if ((int)pr->id < 0)
+       if (invalid_logical_cpuid(pr->id))
                /* This cpu is not presented at hypervisor, try to hotadd it */
                if (ACPI_FAILURE(xen_acpi_cpu_hotadd(pr))) {
                        pr_err(PREFIX "Hotadd CPU (acpi_id = %d) failed.\n",
@@ -226,7 +220,7 @@ static acpi_status xen_acpi_cpu_hotadd(struct acpi_processor *pr)
                return AE_ERROR;
 
        pr->id = xen_hotadd_cpu(pr);
-       if ((int)pr->id < 0)
+       if (invalid_logical_cpuid(pr->id))
                return AE_ERROR;
 
        /*
index 54df54d..b43276f 100644 (file)
@@ -274,7 +274,6 @@ struct acpi_device_power_flags {
 struct acpi_device_power_state {
        struct {
                u8 valid:1;
-               u8 os_accessible:1;
                u8 explicit_set:1;      /* _PSx present? */
                u8 reserved:6;
        } flags;
@@ -637,7 +636,7 @@ static inline bool acpi_device_can_wakeup(struct acpi_device *adev)
 
 static inline bool acpi_device_can_poweroff(struct acpi_device *adev)
 {
-       return adev->power.states[ACPI_STATE_D3_COLD].flags.os_accessible;
+       return adev->power.states[ACPI_STATE_D3_COLD].flags.valid;
 }
 
 #else  /* CONFIG_ACPI */
index 0bc78df..d02df0a 100644 (file)
@@ -95,7 +95,7 @@ acpi_physical_address acpi_os_get_root_pointer(void);
 #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_predefined_override
 acpi_status
 acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
-                           acpi_string * new_val);
+                           char **new_val);
 #endif
 
 #ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_table_override
index 08ef57b..d68f1cd 100644 (file)
@@ -46,7 +46,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20150410
+#define ACPI_CA_VERSION                 0x20150515
 
 #include <acpi/acconfig.h>
 #include <acpi/actypes.h>
index d4081fe..cb8a6b9 100644 (file)
@@ -284,6 +284,7 @@ struct acpi_table_fadt {
        struct acpi_generic_address xgpe1_block;        /* 64-bit Extended General Purpose Event 1 Reg Blk address */
        struct acpi_generic_address sleep_control;      /* 64-bit Sleep Control register (ACPI 5.0) */
        struct acpi_generic_address sleep_status;       /* 64-bit Sleep Status register (ACPI 5.0) */
+       u64 hypervisor_id;      /* Hypervisor Vendor ID (ACPI 6.0) */
 };
 
 /* Masks for FADT IA-PC Boot Architecture Flags (boot_flags) [Vx]=Introduced in this FADT revision */
@@ -341,7 +342,7 @@ enum acpi_preferred_pm_profiles {
        PM_TABLET = 8
 };
 
-/* Values for sleep_status and sleep_control registers (V5 FADT) */
+/* Values for sleep_status and sleep_control registers (V5+ FADT) */
 
 #define ACPI_X_WAKE_STATUS          0x80
 #define ACPI_X_SLEEP_TYPE_MASK      0x1C
@@ -398,15 +399,17 @@ struct acpi_table_desc {
  * FADT is the bottom line as to what the version really is.
  *
  * For reference, the values below are as follows:
- *     FADT V1  size: 0x074
- *     FADT V2  size: 0x084
- *     FADT V3  size: 0x0F4
- *     FADT V4  size: 0x0F4
- *     FADT V5  size: 0x10C
+ *     FADT V1 size: 0x074
+ *     FADT V2 size: 0x084
+ *     FADT V3 size: 0x0F4
+ *     FADT V4 size: 0x0F4
+ *     FADT V5 size: 0x10C
+ *     FADT V6 size: 0x114
  */
 #define ACPI_FADT_V1_SIZE       (u32) (ACPI_FADT_OFFSET (flags) + 4)
 #define ACPI_FADT_V2_SIZE       (u32) (ACPI_FADT_OFFSET (minor_revision) + 1)
 #define ACPI_FADT_V3_SIZE       (u32) (ACPI_FADT_OFFSET (sleep_control))
-#define ACPI_FADT_V5_SIZE       (u32) (sizeof (struct acpi_table_fadt))
+#define ACPI_FADT_V5_SIZE       (u32) (ACPI_FADT_OFFSET (hypervisor_id))
+#define ACPI_FADT_V6_SIZE       (u32) (sizeof (struct acpi_table_fadt))
 
 #endif                         /* __ACTBL_H__ */
index b80b0e6..06b61f0 100644 (file)
@@ -71,6 +71,7 @@
 #define ACPI_SIG_SBST           "SBST" /* Smart Battery Specification Table */
 #define ACPI_SIG_SLIT           "SLIT" /* System Locality Distance Information Table */
 #define ACPI_SIG_SRAT           "SRAT" /* System Resource Affinity Table */
+#define ACPI_SIG_NFIT           "NFIT" /* NVDIMM Firmware Interface Table */
 
 /*
  * All tables must be byte-packed to match the ACPI specification, since
@@ -673,7 +674,8 @@ enum acpi_madt_type {
        ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12,
        ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13,
        ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14,
-       ACPI_MADT_TYPE_RESERVED = 15    /* 15 and greater are reserved */
+       ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15,
+       ACPI_MADT_TYPE_RESERVED = 16    /* 16 and greater are reserved */
 };
 
 /*
@@ -794,7 +796,7 @@ struct acpi_madt_local_x2apic_nmi {
        u8 reserved[3];         /* reserved - must be zero */
 };
 
-/* 11: Generic Interrupt (ACPI 5.0) */
+/* 11: Generic Interrupt (ACPI 5.0 + ACPI 6.0 changes) */
 
 struct acpi_madt_generic_interrupt {
        struct acpi_subtable_header header;
@@ -811,6 +813,8 @@ struct acpi_madt_generic_interrupt {
        u32 vgic_interrupt;
        u64 gicr_base_address;
        u64 arm_mpidr;
+       u8 efficiency_class;
+       u8 reserved2[3];
 };
 
 /* Masks for Flags field above */
@@ -819,7 +823,7 @@ struct acpi_madt_generic_interrupt {
 #define ACPI_MADT_PERFORMANCE_IRQ_MODE  (1<<1) /* 01: Performance Interrupt Mode */
 #define ACPI_MADT_VGIC_IRQ_MODE         (1<<2) /* 02: VGIC Maintenance Interrupt mode */
 
-/* 12: Generic Distributor (ACPI 5.0) */
+/* 12: Generic Distributor (ACPI 5.0 + ACPI 6.0 changes) */
 
 struct acpi_madt_generic_distributor {
        struct acpi_subtable_header header;
@@ -827,7 +831,8 @@ struct acpi_madt_generic_distributor {
        u32 gic_id;
        u64 base_address;
        u32 global_irq_base;
-       u32 reserved2;          /* reserved - must be zero */
+       u8 version;
+       u8 reserved2[3];        /* reserved - must be zero */
 };
 
 /* 13: Generic MSI Frame (ACPI 5.1) */
@@ -855,6 +860,16 @@ struct acpi_madt_generic_redistributor {
        u32 length;
 };
 
+/* 15: Generic Translator (ACPI 6.0) */
+
+struct acpi_madt_generic_translator {
+       struct acpi_subtable_header header;
+       u16 reserved;           /* reserved - must be zero */
+       u32 translation_id;
+       u64 base_address;
+       u32 reserved2;
+};
+
 /*
  * Common flags fields for MADT subtables
  */
@@ -906,6 +921,159 @@ struct acpi_msct_proximity {
        u64 memory_capacity;    /* In bytes */
 };
 
+/*******************************************************************************
+ *
+ * NFIT - NVDIMM Interface Table (ACPI 6.0)
+ *        Version 1
+ *
+ ******************************************************************************/
+
+struct acpi_table_nfit {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 reserved;           /* Reserved, must be zero */
+};
+
+/* Subtable header for NFIT */
+
+struct acpi_nfit_header {
+       u16 type;
+       u16 length;
+};
+
+/* Values for subtable type in struct acpi_nfit_header */
+
+enum acpi_nfit_type {
+       ACPI_NFIT_TYPE_SYSTEM_ADDRESS = 0,
+       ACPI_NFIT_TYPE_MEMORY_MAP = 1,
+       ACPI_NFIT_TYPE_INTERLEAVE = 2,
+       ACPI_NFIT_TYPE_SMBIOS = 3,
+       ACPI_NFIT_TYPE_CONTROL_REGION = 4,
+       ACPI_NFIT_TYPE_DATA_REGION = 5,
+       ACPI_NFIT_TYPE_FLUSH_ADDRESS = 6,
+       ACPI_NFIT_TYPE_RESERVED = 7     /* 7 and greater are reserved */
+};
+
+/*
+ * NFIT Subtables
+ */
+
+/* 0: System Physical Address Range Structure */
+
+struct acpi_nfit_system_address {
+       struct acpi_nfit_header header;
+       u16 range_index;
+       u16 flags;
+       u32 reserved;           /* Reseved, must be zero */
+       u32 proximity_domain;
+       u8 range_guid[16];
+       u64 address;
+       u64 length;
+       u64 memory_mapping;
+};
+
+/* Flags */
+
+#define ACPI_NFIT_ADD_ONLINE_ONLY       (1)    /* 00: Add/Online Operation Only */
+#define ACPI_NFIT_PROXIMITY_VALID       (1<<1) /* 01: Proximity Domain Valid */
+
+/* Range Type GUIDs appear in the include/acuuid.h file */
+
+/* 1: Memory Device to System Address Range Map Structure */
+
+struct acpi_nfit_memory_map {
+       struct acpi_nfit_header header;
+       u32 device_handle;
+       u16 physical_id;
+       u16 region_id;
+       u16 range_index;
+       u16 region_index;
+       u64 region_size;
+       u64 region_offset;
+       u64 address;
+       u16 interleave_index;
+       u16 interleave_ways;
+       u16 flags;
+       u16 reserved;           /* Reserved, must be zero */
+};
+
+/* Flags */
+
+#define ACPI_NFIT_MEM_SAVE_FAILED       (1)    /* 00: Last SAVE to Memory Device failed */
+#define ACPI_NFIT_MEM_RESTORE_FAILED    (1<<1) /* 01: Last RESTORE from Memory Device failed */
+#define ACPI_NFIT_MEM_FLUSH_FAILED      (1<<2) /* 02: Platform flush failed */
+#define ACPI_NFIT_MEM_ARMED             (1<<3) /* 03: Memory Device observed to be not armed */
+#define ACPI_NFIT_MEM_HEALTH_OBSERVED   (1<<4) /* 04: Memory Device observed SMART/health events */
+#define ACPI_NFIT_MEM_HEALTH_ENABLED    (1<<5) /* 05: SMART/health events enabled */
+
+/* 2: Interleave Structure */
+
+struct acpi_nfit_interleave {
+       struct acpi_nfit_header header;
+       u16 interleave_index;
+       u16 reserved;           /* Reserved, must be zero */
+       u32 line_count;
+       u32 line_size;
+       u32 line_offset[1];     /* Variable length */
+};
+
+/* 3: SMBIOS Management Information Structure */
+
+struct acpi_nfit_smbios {
+       struct acpi_nfit_header header;
+       u32 reserved;           /* Reserved, must be zero */
+       u8 data[1];             /* Variable length */
+};
+
+/* 4: NVDIMM Control Region Structure */
+
+struct acpi_nfit_control_region {
+       struct acpi_nfit_header header;
+       u16 region_index;
+       u16 vendor_id;
+       u16 device_id;
+       u16 revision_id;
+       u16 subsystem_vendor_id;
+       u16 subsystem_device_id;
+       u16 subsystem_revision_id;
+       u8 reserved[6];         /* Reserved, must be zero */
+       u32 serial_number;
+       u16 code;
+       u16 windows;
+       u64 window_size;
+       u64 command_offset;
+       u64 command_size;
+       u64 status_offset;
+       u64 status_size;
+       u16 flags;
+       u8 reserved1[6];        /* Reserved, must be zero */
+};
+
+/* Flags */
+
+#define ACPI_NFIT_CONTROL_BUFFERED      (1)    /* Block Data Windows implementation is buffered */
+
+/* 5: NVDIMM Block Data Window Region Structure */
+
+struct acpi_nfit_data_region {
+       struct acpi_nfit_header header;
+       u16 region_index;
+       u16 windows;
+       u64 offset;
+       u64 size;
+       u64 capacity;
+       u64 start_address;
+};
+
+/* 6: Flush Hint Address Structure */
+
+struct acpi_nfit_flush_address {
+       struct acpi_nfit_header header;
+       u32 device_handle;
+       u16 hint_count;
+       u8 reserved[6];         /* Reserved, must be zero */
+       u64 hint_address[1];    /* Variable length */
+};
+
 /*******************************************************************************
  *
  * SBST - Smart Battery Specification Table
index cafdeb5..370d69d 100644 (file)
@@ -69,6 +69,7 @@
 #define ACPI_SIG_DMAR           "DMAR" /* DMA Remapping table */
 #define ACPI_SIG_HPET           "HPET" /* High Precision Event Timer table */
 #define ACPI_SIG_IBFT           "IBFT" /* iSCSI Boot Firmware Table */
+#define ACPI_SIG_IORT           "IORT" /* IO Remapping Table */
 #define ACPI_SIG_IVRS           "IVRS" /* I/O Virtualization Reporting Structure */
 #define ACPI_SIG_LPIT           "LPIT" /* Low Power Idle Table */
 #define ACPI_SIG_MCFG           "MCFG" /* PCI Memory Mapped Configuration table */
@@ -648,6 +649,131 @@ struct acpi_ibft_target {
        u16 reverse_chap_secret_offset;
 };
 
+/*******************************************************************************
+ *
+ * IORT - IO Remapping Table
+ *
+ * Conforms to "IO Remapping Table System Software on ARM Platforms",
+ * Document number: ARM DEN 0049A, 2015
+ *
+ ******************************************************************************/
+
+struct acpi_table_iort {
+       struct acpi_table_header header;
+       u32 node_count;
+       u32 node_offset;
+       u32 reserved;
+};
+
+/*
+ * IORT subtables
+ */
+struct acpi_iort_node {
+       u8 type;
+       u16 length;
+       u8 revision;
+       u32 reserved;
+       u32 mapping_count;
+       u32 mapping_offset;
+       char node_data[1];
+};
+
+/* Values for subtable Type above */
+
+enum acpi_iort_node_type {
+       ACPI_IORT_NODE_ITS_GROUP = 0x00,
+       ACPI_IORT_NODE_NAMED_COMPONENT = 0x01,
+       ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02,
+       ACPI_IORT_NODE_SMMU = 0x03
+};
+
+struct acpi_iort_id_mapping {
+       u32 input_base;         /* Lowest value in input range */
+       u32 id_count;           /* Number of IDs */
+       u32 output_base;        /* Lowest value in output range */
+       u32 output_reference;   /* A reference to the output node */
+       u32 flags;
+};
+
+/* Masks for Flags field above for IORT subtable */
+
+#define ACPI_IORT_ID_SINGLE_MAPPING (1)
+
+struct acpi_iort_memory_access {
+       u32 cache_coherency;
+       u8 hints;
+       u16 reserved;
+       u8 memory_flags;
+};
+
+/* Values for cache_coherency field above */
+
+#define ACPI_IORT_NODE_COHERENT         0x00000001     /* The device node is fully coherent */
+#define ACPI_IORT_NODE_NOT_COHERENT     0x00000000     /* The device node is not coherent */
+
+/* Masks for Hints field above */
+
+#define ACPI_IORT_HT_TRANSIENT          (1)
+#define ACPI_IORT_HT_WRITE              (1<<1)
+#define ACPI_IORT_HT_READ               (1<<2)
+#define ACPI_IORT_HT_OVERRIDE           (1<<3)
+
+/* Masks for memory_flags field above */
+
+#define ACPI_IORT_MF_COHERENCY          (1)
+#define ACPI_IORT_MF_ATTRIBUTES         (1<<1)
+
+/*
+ * IORT node specific subtables
+ */
+struct acpi_iort_its_group {
+       u32 its_count;
+       u32 identifiers[1];     /* GIC ITS identifier arrary */
+};
+
+struct acpi_iort_named_component {
+       u32 node_flags;
+       u64 memory_properties;  /* Memory access properties */
+       u8 memory_address_limit;        /* Memory address size limit */
+       char device_name[1];    /* Path of namespace object */
+};
+
+struct acpi_iort_root_complex {
+       u64 memory_properties;  /* Memory access properties */
+       u32 ats_attribute;
+       u32 pci_segment_number;
+};
+
+/* Values for ats_attribute field above */
+
+#define ACPI_IORT_ATS_SUPPORTED         0x00000001     /* The root complex supports ATS */
+#define ACPI_IORT_ATS_UNSUPPORTED       0x00000000     /* The root complex doesn't support ATS */
+
+struct acpi_iort_smmu {
+       u64 base_address;       /* SMMU base address */
+       u64 span;               /* Length of memory range */
+       u32 model;
+       u32 flags;
+       u32 global_interrupt_offset;
+       u32 context_interrupt_count;
+       u32 context_interrupt_offset;
+       u32 pmu_interrupt_count;
+       u32 pmu_interrupt_offset;
+       u64 interrupts[1];      /* Interrupt array */
+};
+
+/* Values for Model field above */
+
+#define ACPI_IORT_SMMU_V1               0x00000000     /* Generic SMMUv1 */
+#define ACPI_IORT_SMMU_V2               0x00000001     /* Generic SMMUv2 */
+#define ACPI_IORT_SMMU_CORELINK_MMU400  0x00000002     /* ARM Corelink MMU-400 */
+#define ACPI_IORT_SMMU_CORELINK_MMU500  0x00000003     /* ARM Corelink MMU-500 */
+
+/* Masks for Flags field above */
+
+#define ACPI_IORT_SMMU_DVM_SUPPORTED    (1)
+#define ACPI_IORT_SMMU_COHERENT_WALK    (1<<1)
+
 /*******************************************************************************
  *
  * IVRS - I/O Virtualization Reporting Structure
@@ -824,7 +950,7 @@ struct acpi_ivrs_memory {
  *
  * LPIT - Low Power Idle Table
  *
- * Conforms to "ACPI Low Power Idle Table (LPIT) and _LPD Proposal (DRAFT)"
+ * Conforms to "ACPI Low Power Idle Table (LPIT)" July 2014.
  *
  ******************************************************************************/
 
@@ -846,8 +972,7 @@ struct acpi_lpit_header {
 
 enum acpi_lpit_type {
        ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00,
-       ACPI_LPIT_TYPE_SIMPLE_IO = 0x01,
-       ACPI_LPIT_TYPE_RESERVED = 0x02  /* 2 and above are reserved */
+       ACPI_LPIT_TYPE_RESERVED = 0x01  /* 1 and above are reserved */
 };
 
 /* Masks for Flags field above  */
@@ -870,21 +995,6 @@ struct acpi_lpit_native {
        u64 counter_frequency;
 };
 
-/* 0x01: Simple I/O based LPI structure */
-
-struct acpi_lpit_io {
-       struct acpi_lpit_header header;
-       struct acpi_generic_address entry_trigger;
-       u32 trigger_action;
-       u64 trigger_value;
-       u64 trigger_mask;
-       struct acpi_generic_address minimum_idle_state;
-       u32 residency;
-       u32 latency;
-       struct acpi_generic_address residency_counter;
-       u64 counter_frequency;
-};
-
 /*******************************************************************************
  *
  * MCFG - PCI Memory Mapped Configuration table and subtable
index 440ca81..4018986 100644 (file)
 #define ACPI_SIG_PCCT           "PCCT" /* Platform Communications Channel Table */
 #define ACPI_SIG_PMTT           "PMTT" /* Platform Memory Topology Table */
 #define ACPI_SIG_RASF           "RASF" /* RAS Feature table */
+#define ACPI_SIG_STAO           "STAO" /* Status Override table */
 #define ACPI_SIG_TPM2           "TPM2" /* Trusted Platform Module 2.0 H/W interface table */
+#define ACPI_SIG_WPBT           "WPBT" /* Windows Platform Binary Table */
+#define ACPI_SIG_XENV           "XENV" /* Xen Environment table */
 
 #define ACPI_SIG_S3PT           "S3PT" /* S3 Performance (sub)Table */
 #define ACPI_SIG_PCCS           "PCC"  /* PCC Shared Memory Region */
@@ -77,7 +80,6 @@
 
 #define ACPI_SIG_MATR           "MATR" /* Memory Address Translation Table */
 #define ACPI_SIG_MSDM           "MSDM" /* Microsoft Data Management Table */
-#define ACPI_SIG_WPBT           "WPBT" /* Windows Platform Binary Table */
 
 /*
  * All tables must be byte-packed to match the ACPI specification, since
@@ -117,6 +119,8 @@ struct acpi_table_bgrt {
 /*******************************************************************************
  *
  * DRTM - Dynamic Root of Trust for Measurement table
+ * Conforms to "TCG D-RTM Architecture" June 17 2013, Version 1.0.0
+ * Table version 1
  *
  ******************************************************************************/
 
@@ -133,22 +137,40 @@ struct acpi_table_drtm {
        u32 flags;
 };
 
-/* 1) Validated Tables List */
+/* Flag Definitions for above */
+
+#define ACPI_DRTM_ACCESS_ALLOWED            (1)
+#define ACPI_DRTM_ENABLE_GAP_CODE           (1<<1)
+#define ACPI_DRTM_INCOMPLETE_MEASUREMENTS   (1<<2)
+#define ACPI_DRTM_AUTHORITY_ORDER           (1<<3)
 
-struct acpi_drtm_vtl_list {
-       u32 validated_table_list_count;
+/* 1) Validated Tables List (64-bit addresses) */
+
+struct acpi_drtm_vtable_list {
+       u32 validated_table_count;
+       u64 validated_tables[1];
 };
 
-/* 2) Resources List */
+/* 2) Resources List (of Resource Descriptors) */
+
+/* Resource Descriptor */
+
+struct acpi_drtm_resource {
+       u8 size[7];
+       u8 type;
+       u64 address;
+};
 
 struct acpi_drtm_resource_list {
-       u32 resource_list_count;
+       u32 resource_count;
+       struct acpi_drtm_resource resources[1];
 };
 
 /* 3) Platform-specific Identifiers List */
 
-struct acpi_drtm_id_list {
-       u32 id_list_count;
+struct acpi_drtm_dps_id {
+       u32 dps_id_length;
+       u8 dps_id[16];
 };
 
 /*******************************************************************************
@@ -683,6 +705,21 @@ enum acpi_rasf_status {
 #define ACPI_RASF_ERROR                 (1<<2)
 #define ACPI_RASF_STATUS                (0x1F<<3)
 
+/*******************************************************************************
+ *
+ * STAO - Status Override Table (_STA override) - ACPI 6.0
+ *        Version 1
+ *
+ * Conforms to "ACPI Specification for Status Override Table"
+ * 6 January 2015
+ *
+ ******************************************************************************/
+
+struct acpi_table_stao {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 ignore_uart;
+};
+
 /*******************************************************************************
  *
  * TPM2 - Trusted Platform Module (TPM) 2.0 Hardware Interface Table
@@ -713,6 +750,41 @@ struct acpi_tpm2_control {
        u64 response_address;
 };
 
+/*******************************************************************************
+ *
+ * WPBT - Windows Platform Environment Table (ACPI 6.0)
+ *        Version 1
+ *
+ * Conforms to "Windows Platform Binary Table (WPBT)" 29 November 2011
+ *
+ ******************************************************************************/
+
+struct acpi_table_wpbt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 handoff_size;
+       u64 handoff_address;
+       u8 layout;
+       u8 type;
+       u16 arguments_length;
+};
+
+/*******************************************************************************
+ *
+ * XENV - Xen Environment Table (ACPI 6.0)
+ *        Version 1
+ *
+ * Conforms to "ACPI Specification for Xen Environment Table" 4 January 2015
+ *
+ ******************************************************************************/
+
+struct acpi_table_xenv {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u64 grant_table_address;
+       u64 grant_table_size;
+       u32 event_interrupt;
+       u8 event_flags;
+};
+
 /* Reset to default packing */
 
 #pragma pack()
index 1c3002e..63fd7f5 100644 (file)
@@ -471,11 +471,6 @@ typedef u8 acpi_owner_id;
 
 #define ACPI_INTEGER_BIT_SIZE           64
 #define ACPI_MAX_DECIMAL_DIGITS         20     /* 2^64 = 18,446,744,073,709,551,616 */
-
-#if ACPI_MACHINE_WIDTH == 64
-#define ACPI_USE_NATIVE_DIVIDE /* Use compiler native 64-bit divide */
-#endif
-
 #define ACPI_MAX64_DECIMAL_DIGITS       20
 #define ACPI_MAX32_DECIMAL_DIGITS       10
 #define ACPI_MAX16_DECIMAL_DIGITS        5
@@ -530,6 +525,7 @@ typedef u64 acpi_integer;
 #define ACPI_CAST_PTR(t, p)             ((t *) (acpi_uintptr_t) (p))
 #define ACPI_CAST_INDIRECT_PTR(t, p)    ((t **) (acpi_uintptr_t) (p))
 #define ACPI_ADD_PTR(t, a, b)           ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8, (a)) + (acpi_size)(b)))
+#define ACPI_SUB_PTR(t, a, b)           ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8, (a)) - (acpi_size)(b)))
 #define ACPI_PTR_DIFF(a, b)             (acpi_size) (ACPI_CAST_PTR (u8, (a)) - ACPI_CAST_PTR (u8, (b)))
 
 /* Pointer/Integer type conversions */
diff --git a/include/acpi/acuuid.h b/include/acpi/acuuid.h
new file mode 100644 (file)
index 0000000..80fe8cf
--- /dev/null
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Name: acuuid.h - ACPI-related UUID/GUID definitions
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2015, Intel Corp.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#ifndef __ACUUID_H__
+#define __ACUUID_H__
+
+/*
+ * Note1: UUIDs and GUIDs are defined to be identical in ACPI.
+ *
+ * Note2: This file is standalone and should remain that way.
+ */
+
+/* Controllers */
+
+#define UUID_GPIO_CONTROLLER            "4f248f40-d5e2-499f-834c-27758ea1cd3f"
+#define UUID_USB_CONTROLLER             "ce2ee385-00e6-48cb-9f05-2edb927c4899"
+#define UUID_SATA_CONTROLLER            "e4db149b-fcfe-425b-a6d8-92357d78fc7f"
+
+/* Devices */
+
+#define UUID_PCI_HOST_BRIDGE            "33db4d5b-1ff7-401c-9657-7441c03dd766"
+#define UUID_I2C_DEVICE                 "3cdff6f7-4267-4555-ad05-b30a3d8938de"
+#define UUID_POWER_BUTTON               "dfbcf3c5-e7a5-44e6-9c1f-29c76f6e059c"
+
+/* Interfaces */
+
+#define UUID_DEVICE_LABELING            "e5c937d0-3553-4d7a-9117-ea4d19c3434d"
+#define UUID_PHYSICAL_PRESENCE          "3dddfaa6-361b-4eb4-a424-8d10089d1653"
+
+/* NVDIMM - NFIT table */
+
+#define UUID_VOLATILE_MEMORY            "7305944f-fdda-44e3-b16c-3f22d252e5d0"
+#define UUID_PERSISTENT_MEMORY          "66f0d379-b4f3-4074-ac43-0d3318b78cdb"
+#define UUID_CONTROL_REGION             "92f701f6-13b4-405d-910b-299367e8234c"
+#define UUID_DATA_REGION                "91af0530-5d86-470e-a6b0-0a2db9408249"
+#define UUID_VOLATILE_VIRTUAL_DISK      "77ab535a-45fc-624b-5560-f7b281d1f96e"
+#define UUID_VOLATILE_VIRTUAL_CD        "3d5abd30-4175-87ce-6d64-d2ade523c4bb"
+#define UUID_PERSISTENT_VIRTUAL_DISK    "5cea02c9-4d07-69d3-269f-4496fbe096f9"
+#define UUID_PERSISTENT_VIRTUAL_CD      "08018188-42cd-bb48-100f-5387d53ded3d"
+
+/* Miscellaneous */
+
+#define UUID_PLATFORM_CAPABILITIES      "0811b06e-4a27-44f9-8d60-3cbbc22e7b48"
+#define UUID_DYNAMIC_ENUMERATION        "d8c1a3a6-be9b-4c9b-91bf-c3cb81fc5daf"
+#define UUID_BATTERY_THERMAL_LIMIT      "4c2067e3-887d-475c-9720-4af1d3ed602e"
+#define UUID_THERMAL_EXTENSIONS         "14d399cd-7a27-4b18-8fb4-7cb7b9f4e500"
+#define UUID_DEVICE_PROPERTIES          "daffd814-6eba-4d8c-8a91-bc9bbf4aa301"
+
+#endif                         /* __AUUID_H__ */
index ecdf940..073997d 100644 (file)
 #elif defined(_APPLE) || defined(__APPLE__)
 #include "acmacosx.h"
 
+#elif defined(__DragonFly__)
+#include "acdragonfly.h"
+
 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include "acfreebsd.h"
 
index 71e5ec5..14dc6f6 100644 (file)
@@ -56,6 +56,9 @@
 #if defined(_LINUX) || defined(__linux__)
 #include <acpi/platform/aclinuxex.h>
 
+#elif defined(__DragonFly__)
+#include "acdragonflyex.h"
+
 #endif
 
 /*! [End] no source code translation !*/
index 843ef1a..a7d7f10 100644 (file)
@@ -16,23 +16,36 @@ struct acpi_device;
 #define ACPI_VIDEO_DISPLAY_LEGACY_PANEL   0x0110
 #define ACPI_VIDEO_DISPLAY_LEGACY_TV      0x0200
 
+enum acpi_backlight_type {
+       acpi_backlight_undef = -1,
+       acpi_backlight_none = 0,
+       acpi_backlight_video,
+       acpi_backlight_vendor,
+       acpi_backlight_native,
+};
+
 #if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
 extern int acpi_video_register(void);
 extern void acpi_video_unregister(void);
-extern void acpi_video_unregister_backlight(void);
 extern int acpi_video_get_edid(struct acpi_device *device, int type,
                               int device_id, void **edid);
-extern bool acpi_video_verify_backlight_support(void);
+extern enum acpi_backlight_type acpi_video_get_backlight_type(void);
+extern void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type);
 #else
 static inline int acpi_video_register(void) { return 0; }
 static inline void acpi_video_unregister(void) { return; }
-static inline void acpi_video_unregister_backlight(void) { return; }
 static inline int acpi_video_get_edid(struct acpi_device *device, int type,
                                      int device_id, void **edid)
 {
        return -ENODEV;
 }
-static inline bool acpi_video_verify_backlight_support(void) { return false; }
+static inline enum acpi_backlight_type acpi_video_get_backlight_type(void)
+{
+       return acpi_backlight_vendor;
+}
+static void acpi_video_set_dmi_backlight_type(enum acpi_backlight_type type)
+{
+}
 #endif
 
 #endif
index d46a48c..400b864 100644 (file)
@@ -158,6 +158,16 @@ typedef u32 phys_cpuid_t;
 #define PHYS_CPUID_INVALID (phys_cpuid_t)(-1)
 #endif
 
+static inline bool invalid_logical_cpuid(u32 cpuid)
+{
+       return (int)cpuid < 0;
+}
+
+static inline bool invalid_phys_cpuid(phys_cpuid_t phys_id)
+{
+       return phys_id == PHYS_CPUID_INVALID;
+}
+
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 /* Arch dependent functions for cpu hotplug support */
 int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu);
@@ -243,50 +253,12 @@ extern bool wmi_has_guid(const char *guid);
 #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR         0x0400
 #define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO          0x0800
 
-#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
-
-extern long acpi_video_get_capabilities(acpi_handle graphics_dev_handle);
+extern char acpi_video_backlight_string[];
 extern long acpi_is_video_device(acpi_handle handle);
-extern void acpi_video_dmi_promote_vendor(void);
-extern void acpi_video_dmi_demote_vendor(void);
-extern int acpi_video_backlight_support(void);
-extern int acpi_video_display_switch_support(void);
-
-#else
-
-static inline long acpi_video_get_capabilities(acpi_handle graphics_dev_handle)
-{
-       return 0;
-}
-
-static inline long acpi_is_video_device(acpi_handle handle)
-{
-       return 0;
-}
-
-static inline void acpi_video_dmi_promote_vendor(void)
-{
-}
-
-static inline void acpi_video_dmi_demote_vendor(void)
-{
-}
-
-static inline int acpi_video_backlight_support(void)
-{
-       return 0;
-}
-
-static inline int acpi_video_display_switch_support(void)
-{
-       return 0;
-}
-
-#endif /* defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) */
-
 extern int acpi_blacklisted(void);
 extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
 extern void acpi_osi_setup(char *str);
+extern bool acpi_osi_is_win8(void);
 
 #ifdef CONFIG_ACPI_NUMA
 int acpi_get_node(acpi_handle handle);
@@ -332,6 +304,9 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
 
 int acpi_resources_are_enforced(void);
 
+int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
+                       unsigned long flags, char *desc);
+
 #ifdef CONFIG_HIBERNATION
 void __init acpi_no_s4_hw_signature(void);
 #endif
@@ -440,6 +415,7 @@ extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
 #define ACPI_OST_SC_INSERT_NOT_SUPPORTED       0x82
 
 extern void acpi_early_init(void);
+extern void acpi_subsystem_init(void);
 
 extern int acpi_nvs_register(__u64 start, __u64 size);
 
@@ -494,6 +470,7 @@ static inline const char *acpi_dev_name(struct acpi_device *adev)
 }
 
 static inline void acpi_early_init(void) { }
+static inline void acpi_subsystem_init(void) { }
 
 static inline int early_acpi_boot_init(void)
 {
@@ -525,6 +502,13 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n,
        return 0;
 }
 
+static inline int acpi_reserve_region(u64 start, unsigned int length,
+                                     u8 space_id, unsigned long flags,
+                                     char *desc)
+{
+       return -ENXIO;
+}
+
 struct acpi_table_header;
 static inline int acpi_table_parse(char *id,
                                int (*handler)(struct acpi_table_header *))
index 2115055..2a89545 100644 (file)
@@ -664,6 +664,7 @@ asmlinkage __visible void __init start_kernel(void)
 
        check_bugs();
 
+       acpi_subsystem_init();
        sfi_init_late();
 
        if (efi_enabled(EFI_RUNTIME_SERVICES)) {