forked from Minki/linux
Merge remote branch 'korg/drm-nvidia-switch-fixes' into drm-core-next
* korg/drm-nvidia-switch-fixes: mxm/wmi: add MXMX interface entry point. nouveau: add optimus detection to DSM code. vgaarb: use bridges to control VGA routing where possible. nouveau/acpi: hook up to the MXM method for mux switching. platform/x86: add MXM WMI driver.
This commit is contained in:
commit
269dc2d919
@ -11,6 +11,7 @@ config DRM_NOUVEAU
|
||||
select FRAMEBUFFER_CONSOLE if !EXPERT
|
||||
select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT
|
||||
select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && INPUT
|
||||
select MXM_WMI if ACPI
|
||||
help
|
||||
Choose this option for open-source nVidia support.
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/video.h>
|
||||
#include <acpi/acpi.h>
|
||||
#include <linux/mxm-wmi.h>
|
||||
|
||||
#include "drmP.h"
|
||||
#include "drm.h"
|
||||
@ -35,15 +37,71 @@
|
||||
|
||||
static struct nouveau_dsm_priv {
|
||||
bool dsm_detected;
|
||||
bool optimus_detected;
|
||||
acpi_handle dhandle;
|
||||
acpi_handle rom_handle;
|
||||
} nouveau_dsm_priv;
|
||||
|
||||
#define NOUVEAU_DSM_HAS_MUX 0x1
|
||||
#define NOUVEAU_DSM_HAS_OPT 0x2
|
||||
|
||||
static const char nouveau_dsm_muid[] = {
|
||||
0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
|
||||
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
|
||||
};
|
||||
|
||||
static const char nouveau_op_dsm_muid[] = {
|
||||
0xF8, 0xD8, 0x86, 0xA4, 0xDA, 0x0B, 0x1B, 0x47,
|
||||
0xA7, 0x2B, 0x60, 0x42, 0xA6, 0xB5, 0xBE, 0xE0,
|
||||
};
|
||||
|
||||
static int nouveau_optimus_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
|
||||
{
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_object_list input;
|
||||
union acpi_object params[4];
|
||||
union acpi_object *obj;
|
||||
int err;
|
||||
|
||||
input.count = 4;
|
||||
input.pointer = params;
|
||||
params[0].type = ACPI_TYPE_BUFFER;
|
||||
params[0].buffer.length = sizeof(nouveau_op_dsm_muid);
|
||||
params[0].buffer.pointer = (char *)nouveau_op_dsm_muid;
|
||||
params[1].type = ACPI_TYPE_INTEGER;
|
||||
params[1].integer.value = 0x00000100;
|
||||
params[2].type = ACPI_TYPE_INTEGER;
|
||||
params[2].integer.value = func;
|
||||
params[3].type = ACPI_TYPE_BUFFER;
|
||||
params[3].buffer.length = 0;
|
||||
|
||||
err = acpi_evaluate_object(handle, "_DSM", &input, &output);
|
||||
if (err) {
|
||||
printk(KERN_INFO "failed to evaluate _DSM: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
obj = (union acpi_object *)output.pointer;
|
||||
|
||||
if (obj->type == ACPI_TYPE_INTEGER)
|
||||
if (obj->integer.value == 0x80000002) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (obj->type == ACPI_TYPE_BUFFER) {
|
||||
if (obj->buffer.length == 4 && result) {
|
||||
*result = 0;
|
||||
*result |= obj->buffer.pointer[0];
|
||||
*result |= (obj->buffer.pointer[1] << 8);
|
||||
*result |= (obj->buffer.pointer[2] << 16);
|
||||
*result |= (obj->buffer.pointer[3] << 24);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(output.pointer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
|
||||
{
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
@ -92,6 +150,8 @@ static int nouveau_dsm(acpi_handle handle, int func, int arg, uint32_t *result)
|
||||
|
||||
static int nouveau_dsm_switch_mux(acpi_handle handle, int mux_id)
|
||||
{
|
||||
mxm_wmi_call_mxmx(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
|
||||
mxm_wmi_call_mxds(mux_id == NOUVEAU_DSM_LED_STAMINA ? MXM_MXDS_ADAPTER_IGD : MXM_MXDS_ADAPTER_0);
|
||||
return nouveau_dsm(handle, NOUVEAU_DSM_LED, mux_id, NULL);
|
||||
}
|
||||
|
||||
@ -148,11 +208,11 @@ static struct vga_switcheroo_handler nouveau_dsm_handler = {
|
||||
.get_client_id = nouveau_dsm_get_client_id,
|
||||
};
|
||||
|
||||
static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
|
||||
static int nouveau_dsm_pci_probe(struct pci_dev *pdev)
|
||||
{
|
||||
acpi_handle dhandle, nvidia_handle;
|
||||
acpi_status status;
|
||||
int ret;
|
||||
int ret, retval = 0;
|
||||
uint32_t result;
|
||||
|
||||
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
|
||||
@ -166,11 +226,17 @@ static bool nouveau_dsm_pci_probe(struct pci_dev *pdev)
|
||||
|
||||
ret = nouveau_dsm(dhandle, NOUVEAU_DSM_SUPPORTED,
|
||||
NOUVEAU_DSM_SUPPORTED_FUNCTIONS, &result);
|
||||
if (ret < 0)
|
||||
return false;
|
||||
if (ret == 0)
|
||||
retval |= NOUVEAU_DSM_HAS_MUX;
|
||||
|
||||
nouveau_dsm_priv.dhandle = dhandle;
|
||||
return true;
|
||||
ret = nouveau_optimus_dsm(dhandle, 0, 0, &result);
|
||||
if (ret == 0)
|
||||
retval |= NOUVEAU_DSM_HAS_OPT;
|
||||
|
||||
if (retval)
|
||||
nouveau_dsm_priv.dhandle = dhandle;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool nouveau_dsm_detect(void)
|
||||
@ -179,22 +245,42 @@ static bool nouveau_dsm_detect(void)
|
||||
struct acpi_buffer buffer = {sizeof(acpi_method_name), acpi_method_name};
|
||||
struct pci_dev *pdev = NULL;
|
||||
int has_dsm = 0;
|
||||
int has_optimus;
|
||||
int vga_count = 0;
|
||||
bool guid_valid;
|
||||
int retval;
|
||||
bool ret = false;
|
||||
|
||||
/* lookup the MXM GUID */
|
||||
guid_valid = mxm_wmi_supported();
|
||||
|
||||
if (guid_valid)
|
||||
printk("MXM: GUID detected in BIOS\n");
|
||||
|
||||
/* now do DSM detection */
|
||||
while ((pdev = pci_get_class(PCI_CLASS_DISPLAY_VGA << 8, pdev)) != NULL) {
|
||||
vga_count++;
|
||||
|
||||
has_dsm |= (nouveau_dsm_pci_probe(pdev) == true);
|
||||
retval = nouveau_dsm_pci_probe(pdev);
|
||||
printk("ret val is %d\n", retval);
|
||||
if (retval & NOUVEAU_DSM_HAS_MUX)
|
||||
has_dsm |= 1;
|
||||
if (retval & NOUVEAU_DSM_HAS_OPT)
|
||||
has_optimus = 1;
|
||||
}
|
||||
|
||||
if (vga_count == 2 && has_dsm) {
|
||||
if (vga_count == 2 && has_dsm && guid_valid) {
|
||||
acpi_get_name(nouveau_dsm_priv.dhandle, ACPI_FULL_PATHNAME, &buffer);
|
||||
printk(KERN_INFO "VGA switcheroo: detected DSM switching method %s handle\n",
|
||||
acpi_method_name);
|
||||
nouveau_dsm_priv.dsm_detected = true;
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
return false;
|
||||
|
||||
if (has_optimus == 1)
|
||||
nouveau_dsm_priv.optimus_detected = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nouveau_register_dsm_handler(void)
|
||||
@ -247,7 +333,7 @@ bool nouveau_acpi_rom_supported(struct pci_dev *pdev)
|
||||
acpi_status status;
|
||||
acpi_handle dhandle, rom_handle;
|
||||
|
||||
if (!nouveau_dsm_priv.dsm_detected)
|
||||
if (!nouveau_dsm_priv.dsm_detected && !nouveau_dsm_priv.optimus_detected)
|
||||
return false;
|
||||
|
||||
dhandle = DEVICE_ACPI_HANDLE(&pdev->dev);
|
||||
|
@ -61,7 +61,7 @@ struct vga_device {
|
||||
unsigned int mem_lock_cnt; /* legacy MEM lock count */
|
||||
unsigned int io_norm_cnt; /* normal IO count */
|
||||
unsigned int mem_norm_cnt; /* normal MEM count */
|
||||
|
||||
bool bridge_has_one_vga;
|
||||
/* allow IRQ enable/disable hook */
|
||||
void *cookie;
|
||||
void (*irq_set_state)(void *cookie, bool enable);
|
||||
@ -165,6 +165,8 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
|
||||
unsigned int wants, legacy_wants, match;
|
||||
struct vga_device *conflict;
|
||||
unsigned int pci_bits;
|
||||
u32 flags = 0;
|
||||
|
||||
/* Account for "normal" resources to lock. If we decode the legacy,
|
||||
* counterpart, we need to request it as well
|
||||
*/
|
||||
@ -237,16 +239,23 @@ static struct vga_device *__vga_tryget(struct vga_device *vgadev,
|
||||
/* looks like he doesn't have a lock, we can steal
|
||||
* them from him
|
||||
*/
|
||||
vga_irq_set_state(conflict, false);
|
||||
|
||||
flags = 0;
|
||||
pci_bits = 0;
|
||||
if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
|
||||
pci_bits |= PCI_COMMAND_MEMORY;
|
||||
if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
|
||||
pci_bits |= PCI_COMMAND_IO;
|
||||
|
||||
pci_set_vga_state(conflict->pdev, false, pci_bits,
|
||||
change_bridge);
|
||||
if (!conflict->bridge_has_one_vga) {
|
||||
vga_irq_set_state(conflict, false);
|
||||
flags |= PCI_VGA_STATE_CHANGE_DECODES;
|
||||
if (lwants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
|
||||
pci_bits |= PCI_COMMAND_MEMORY;
|
||||
if (lwants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
|
||||
pci_bits |= PCI_COMMAND_IO;
|
||||
}
|
||||
|
||||
if (change_bridge)
|
||||
flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
|
||||
|
||||
pci_set_vga_state(conflict->pdev, false, pci_bits, flags);
|
||||
conflict->owns &= ~lwants;
|
||||
/* If he also owned non-legacy, that is no longer the case */
|
||||
if (lwants & VGA_RSRC_LEGACY_MEM)
|
||||
@ -261,14 +270,24 @@ enable_them:
|
||||
* also have in "decodes". We can lock resources we don't decode but
|
||||
* not own them.
|
||||
*/
|
||||
flags = 0;
|
||||
pci_bits = 0;
|
||||
if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
|
||||
pci_bits |= PCI_COMMAND_MEMORY;
|
||||
if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
|
||||
pci_bits |= PCI_COMMAND_IO;
|
||||
pci_set_vga_state(vgadev->pdev, true, pci_bits, !!(wants & VGA_RSRC_LEGACY_MASK));
|
||||
|
||||
vga_irq_set_state(vgadev, true);
|
||||
if (!vgadev->bridge_has_one_vga) {
|
||||
flags |= PCI_VGA_STATE_CHANGE_DECODES;
|
||||
if (wants & (VGA_RSRC_LEGACY_MEM|VGA_RSRC_NORMAL_MEM))
|
||||
pci_bits |= PCI_COMMAND_MEMORY;
|
||||
if (wants & (VGA_RSRC_LEGACY_IO|VGA_RSRC_NORMAL_IO))
|
||||
pci_bits |= PCI_COMMAND_IO;
|
||||
}
|
||||
if (!!(wants & VGA_RSRC_LEGACY_MASK))
|
||||
flags |= PCI_VGA_STATE_CHANGE_BRIDGE;
|
||||
|
||||
pci_set_vga_state(vgadev->pdev, true, pci_bits, flags);
|
||||
|
||||
if (!vgadev->bridge_has_one_vga) {
|
||||
vga_irq_set_state(vgadev, true);
|
||||
}
|
||||
vgadev->owns |= (wants & vgadev->decodes);
|
||||
lock_them:
|
||||
vgadev->locks |= (rsrc & VGA_RSRC_LEGACY_MASK);
|
||||
@ -421,6 +440,62 @@ bail:
|
||||
}
|
||||
EXPORT_SYMBOL(vga_put);
|
||||
|
||||
/* Rules for using a bridge to control a VGA descendant decoding:
|
||||
if a bridge has only one VGA descendant then it can be used
|
||||
to control the VGA routing for that device.
|
||||
It should always use the bridge closest to the device to control it.
|
||||
If a bridge has a direct VGA descendant, but also have a sub-bridge
|
||||
VGA descendant then we cannot use that bridge to control the direct VGA descendant.
|
||||
So for every device we register, we need to iterate all its parent bridges
|
||||
so we can invalidate any devices using them properly.
|
||||
*/
|
||||
static void vga_arbiter_check_bridge_sharing(struct vga_device *vgadev)
|
||||
{
|
||||
struct vga_device *same_bridge_vgadev;
|
||||
struct pci_bus *new_bus, *bus;
|
||||
struct pci_dev *new_bridge, *bridge;
|
||||
|
||||
vgadev->bridge_has_one_vga = true;
|
||||
|
||||
if (list_empty(&vga_list))
|
||||
return;
|
||||
|
||||
/* okay iterate the new devices bridge hierarachy */
|
||||
new_bus = vgadev->pdev->bus;
|
||||
while (new_bus) {
|
||||
new_bridge = new_bus->self;
|
||||
|
||||
if (new_bridge) {
|
||||
/* go through list of devices already registered */
|
||||
list_for_each_entry(same_bridge_vgadev, &vga_list, list) {
|
||||
bus = same_bridge_vgadev->pdev->bus;
|
||||
bridge = bus->self;
|
||||
|
||||
/* see if the share a bridge with this device */
|
||||
if (new_bridge == bridge) {
|
||||
/* if their direct parent bridge is the same
|
||||
as any bridge of this device then it can't be used
|
||||
for that device */
|
||||
same_bridge_vgadev->bridge_has_one_vga = false;
|
||||
}
|
||||
|
||||
/* now iterate the previous devices bridge hierarchy */
|
||||
/* if the new devices parent bridge is in the other devices
|
||||
hierarchy then we can't use it to control this device */
|
||||
while (bus) {
|
||||
bridge = bus->self;
|
||||
if (bridge) {
|
||||
if (bridge == vgadev->pdev->bus->self)
|
||||
vgadev->bridge_has_one_vga = false;
|
||||
}
|
||||
bus = bus->parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
new_bus = new_bus->parent;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Currently, we assume that the "initial" setup of the system is
|
||||
* not sane, that is we come up with conflicting devices and let
|
||||
@ -500,6 +575,8 @@ static bool vga_arbiter_add_pci_device(struct pci_dev *pdev)
|
||||
vga_default = pci_dev_get(pdev);
|
||||
#endif
|
||||
|
||||
vga_arbiter_check_bridge_sharing(vgadev);
|
||||
|
||||
/* Add to the list */
|
||||
list_add(&vgadev->list, &vga_list);
|
||||
vga_count++;
|
||||
@ -1222,6 +1299,7 @@ static int __init vga_arb_device_init(void)
|
||||
{
|
||||
int rc;
|
||||
struct pci_dev *pdev;
|
||||
struct vga_device *vgadev;
|
||||
|
||||
rc = misc_register(&vga_arb_device);
|
||||
if (rc < 0)
|
||||
@ -1238,6 +1316,13 @@ static int __init vga_arb_device_init(void)
|
||||
vga_arbiter_add_pci_device(pdev);
|
||||
|
||||
pr_info("vgaarb: loaded\n");
|
||||
|
||||
list_for_each_entry(vgadev, &vga_list, list) {
|
||||
if (vgadev->bridge_has_one_vga)
|
||||
pr_info("vgaarb: bridge control possible %s\n", pci_name(vgadev->pdev));
|
||||
else
|
||||
pr_info("vgaarb: no bridge control possible %s\n", pci_name(vgadev->pdev));
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
subsys_initcall(vga_arb_device_init);
|
||||
|
@ -2875,31 +2875,34 @@ static int pci_set_vga_state_arch(struct pci_dev *dev, bool decode,
|
||||
* @dev: the PCI device
|
||||
* @decode: true = enable decoding, false = disable decoding
|
||||
* @command_bits: PCI_COMMAND_IO and/or PCI_COMMAND_MEMORY
|
||||
* @change_bridge: traverse ancestors and change bridges
|
||||
* @change_bridge_flags: traverse ancestors and change bridges
|
||||
* CHANGE_BRIDGE_ONLY / CHANGE_BRIDGE
|
||||
*/
|
||||
int pci_set_vga_state(struct pci_dev *dev, bool decode,
|
||||
unsigned int command_bits, bool change_bridge)
|
||||
unsigned int command_bits, u32 flags)
|
||||
{
|
||||
struct pci_bus *bus;
|
||||
struct pci_dev *bridge;
|
||||
u16 cmd;
|
||||
int rc;
|
||||
|
||||
WARN_ON(command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY));
|
||||
WARN_ON((flags & PCI_VGA_STATE_CHANGE_DECODES) & (command_bits & ~(PCI_COMMAND_IO|PCI_COMMAND_MEMORY)));
|
||||
|
||||
/* ARCH specific VGA enables */
|
||||
rc = pci_set_vga_state_arch(dev, decode, command_bits, change_bridge);
|
||||
rc = pci_set_vga_state_arch(dev, decode, command_bits, flags);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
if (decode == true)
|
||||
cmd |= command_bits;
|
||||
else
|
||||
cmd &= ~command_bits;
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
if (flags & PCI_VGA_STATE_CHANGE_DECODES) {
|
||||
pci_read_config_word(dev, PCI_COMMAND, &cmd);
|
||||
if (decode == true)
|
||||
cmd |= command_bits;
|
||||
else
|
||||
cmd &= ~command_bits;
|
||||
pci_write_config_word(dev, PCI_COMMAND, cmd);
|
||||
}
|
||||
|
||||
if (change_bridge == false)
|
||||
if (!(flags & PCI_VGA_STATE_CHANGE_BRIDGE))
|
||||
return 0;
|
||||
|
||||
bus = dev->bus;
|
||||
|
@ -753,4 +753,11 @@ config SAMSUNG_LAPTOP
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called samsung-laptop.
|
||||
|
||||
config MXM_WMI
|
||||
tristate "WMI support for MXM Laptop Graphics"
|
||||
depends on WMI
|
||||
---help---
|
||||
MXM is a standard for laptop graphics cards, the WMI interface
|
||||
is required for switchable nvidia graphics machines
|
||||
|
||||
endif # X86_PLATFORM_DEVICES
|
||||
|
@ -42,3 +42,4 @@ obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o
|
||||
obj-$(CONFIG_IBM_RTL) += ibm_rtl.o
|
||||
obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o
|
||||
obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
|
||||
obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
|
||||
|
111
drivers/platform/x86/mxm-wmi.c
Normal file
111
drivers/platform/x86/mxm-wmi.c
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* MXM WMI driver
|
||||
*
|
||||
* Copyright(C) 2010 Red Hat.
|
||||
*
|
||||
* 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 <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
MODULE_AUTHOR("Dave Airlie");
|
||||
MODULE_DESCRIPTION("MXM WMI Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define MXM_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
|
||||
|
||||
MODULE_ALIAS("wmi:"MXM_WMMX_GUID);
|
||||
|
||||
#define MXM_WMMX_FUNC_MXDS 0x5344584D /* "MXDS" */
|
||||
#define MXM_WMMX_FUNC_MXMX 0x53445344 /* "MXMX" */
|
||||
|
||||
struct mxds_args {
|
||||
u32 func;
|
||||
u32 args;
|
||||
u32 xarg;
|
||||
};
|
||||
|
||||
int mxm_wmi_call_mxds(int adapter)
|
||||
{
|
||||
struct mxds_args args = {
|
||||
.func = MXM_WMMX_FUNC_MXDS,
|
||||
.args = 0,
|
||||
.xarg = 1,
|
||||
};
|
||||
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status;
|
||||
|
||||
printk("calling mux switch %d\n", adapter);
|
||||
|
||||
status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
|
||||
&output);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
printk("mux switched %d\n", status);
|
||||
return 0;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mxm_wmi_call_mxds);
|
||||
|
||||
int mxm_wmi_call_mxmx(int adapter)
|
||||
{
|
||||
struct mxds_args args = {
|
||||
.func = MXM_WMMX_FUNC_MXMX,
|
||||
.args = 0,
|
||||
.xarg = 1,
|
||||
};
|
||||
struct acpi_buffer input = { (acpi_size)sizeof(args), &args };
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_status status;
|
||||
|
||||
printk("calling mux switch %d\n", adapter);
|
||||
|
||||
status = wmi_evaluate_method(MXM_WMMX_GUID, 0x1, adapter, &input,
|
||||
&output);
|
||||
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
printk("mux mutex set switched %d\n", status);
|
||||
return 0;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mxm_wmi_call_mxmx);
|
||||
|
||||
bool mxm_wmi_supported(void)
|
||||
{
|
||||
bool guid_valid;
|
||||
guid_valid = wmi_has_guid(MXM_WMMX_GUID);
|
||||
return guid_valid;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mxm_wmi_supported);
|
||||
|
||||
static int __init mxm_wmi_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit mxm_wmi_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
module_init(mxm_wmi_init);
|
||||
module_exit(mxm_wmi_exit);
|
33
include/linux/mxm-wmi.h
Normal file
33
include/linux/mxm-wmi.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* MXM WMI driver
|
||||
*
|
||||
* Copyright(C) 2010 Red Hat.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef MXM_WMI_H
|
||||
#define MXM_WMI_H
|
||||
|
||||
/* discrete adapters */
|
||||
#define MXM_MXDS_ADAPTER_0 0x0
|
||||
#define MXM_MXDS_ADAPTER_1 0x0
|
||||
/* integrated adapter */
|
||||
#define MXM_MXDS_ADAPTER_IGD 0x10
|
||||
int mxm_wmi_call_mxds(int adapter);
|
||||
int mxm_wmi_call_mxmx(int adapter);
|
||||
bool mxm_wmi_supported(void);
|
||||
|
||||
#endif
|
@ -915,8 +915,11 @@ int pci_cfg_space_size_ext(struct pci_dev *dev);
|
||||
int pci_cfg_space_size(struct pci_dev *dev);
|
||||
unsigned char pci_bus_max_busnr(struct pci_bus *bus);
|
||||
|
||||
#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0)
|
||||
#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1)
|
||||
|
||||
int pci_set_vga_state(struct pci_dev *pdev, bool decode,
|
||||
unsigned int command_bits, bool change_bridge);
|
||||
unsigned int command_bits, u32 flags);
|
||||
/* kmem_cache style wrapper around pci_alloc_consistent() */
|
||||
|
||||
#include <linux/pci-dma.h>
|
||||
@ -1061,7 +1064,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
|
||||
|
||||
/* some architectures require additional setup to direct VGA traffic */
|
||||
typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode,
|
||||
unsigned int command_bits, bool change_bridge);
|
||||
unsigned int command_bits, u32 flags);
|
||||
extern void pci_register_set_vga_state(arch_set_vga_state_t func);
|
||||
|
||||
#else /* CONFIG_PCI is not enabled */
|
||||
|
Loading…
Reference in New Issue
Block a user