From: Matthew Garrett <mjg59@srcf.ucam.org>
To: Norbert Preining <preining@logic.at>
Cc: Len Brown <lenb@kernel.org>,
sony-vaio-z-series@lists.launchpad.net,
Mattia Dongili <malattia@linux.it>,
Matthias Welwarsky <matze@welwarsky.de>,
linux-acpi@vger.kernel.org
Subject: Re: new fixes for sony-acpi
Date: Tue, 31 Mar 2009 16:20:35 +0100 [thread overview]
Message-ID: <20090331152035.GA20946@srcf.ucam.org> (raw)
In-Reply-To: <20090328120008.GA22470@srcf.ucam.org>
[-- Attachment #1: Type: text/plain, Size: 710 bytes --]
I've done some more work on this and here's the current state of things.
It's a module that loads, checks what state the firmware thinks the
hardware is in and then ensures that the hardware is actually in that
state. I believe that it gets the choice between internal and discrete
GPUs correct. It doesn't support runtime switching right now since
there's no way to do anything useful with it, but it's a trivial sysfs
attribute.
I've done this outside sony-laptop since it's not specific to Sonys in
any way. It would be wonderful if anyone with any of the other hybrid
nvidias (except the Apples, which seem to be entirely different) could
give it a go.
--
Matthew Garrett | mjg59@srcf.ucam.org
[-- Attachment #2: nvidia-control.c --]
[-- Type: text/x-csrc, Size: 2852 bytes --]
#include <linux/acpi.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acpi_bus.h>
#include <linux/pci.h>
static int nvidia_dsm(struct pci_dev *dev, int func, int arg, int *result)
{
static char muid[] = {
0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
};
struct acpi_handle *handle;
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_object_list input;
union acpi_object params[4];
union acpi_object *obj;
int err;
handle = DEVICE_ACPI_HANDLE(&dev->dev);
if (!handle)
return -ENODEV;
input.count = 4;
input.pointer = params;
params[0].type = ACPI_TYPE_BUFFER;
params[0].buffer.length = sizeof(muid);
params[0].buffer.pointer = (char *)muid;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = 0x00000102;
params[2].type = ACPI_TYPE_INTEGER;
params[2].integer.value = func;
params[3].type = ACPI_TYPE_INTEGER;
params[3].integer.value = arg;
err = acpi_evaluate_object(handle, "_DSM", &input, &output);
if (err) {
printk(KERN_ERR "nvidia-control: 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;
}
int nvidia_control_setup(struct pci_dev *dev)
{
int result;
if (nvidia_dsm(dev, 1, 0, &result))
return -ENODEV;
printk(KERN_INFO "nvidia-control: hardware status gave 0x%x\n", result);
if (result &= 0x1) { /* Stamina mode - disable the external GPU */
nvidia_dsm(dev, 0x2, 0x11, NULL);
nvidia_dsm(dev, 0x3, 0x02, NULL);
} else { /* Ensure that the external GPU is enabled */
nvidia_dsm(dev, 0x2, 0x12, NULL);
nvidia_dsm(dev, 0x3, 0x01, NULL);
}
return 0;
}
int nvidia_control_probe(struct pci_dev *dev)
{
int support = 0;
if (nvidia_dsm(dev, 0, 0, &support))
return -ENODEV;
if (!support)
return -ENODEV;
return 0;
}
static int __init nvidia_control_init(void)
{
struct pci_dev *dev = NULL;
while ((dev = pci_get_device(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, dev))) {
if (dev->class == 0x30000)
if (!nvidia_control_probe(dev))
nvidia_control_setup(dev);
}
return 0;
}
static void __exit nvidia_control_exit(void)
{
return;
}
static const struct pci_device_id pci_ids [] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
(PCI_CLASS_DISPLAY_VGA << 8), 0xffff00},
{ },
};
MODULE_DEVICE_TABLE(pci, pci_ids);
module_init(nvidia_control_init);
module_exit(nvidia_control_exit);
MODULE_LICENSE("GPL");
[-- Attachment #3: Makefile --]
[-- Type: text/plain, Size: 79 bytes --]
obj-m += nvidia-control.o
all:
make -C /lib/modules/`uname -r`/build M=`pwd`
next prev parent reply other threads:[~2009-03-31 15:20 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-03-23 16:34 new fixes for sony-acpi Norbert Preining
2009-03-28 1:34 ` Len Brown
2009-03-28 1:38 ` Matthew Garrett
2009-03-28 8:33 ` Norbert Preining
2009-03-28 12:00 ` Matthew Garrett
2009-03-31 15:20 ` Matthew Garrett [this message]
2009-04-13 15:03 ` Norbert Preining
2009-04-13 15:06 ` Matthew Garrett
2009-04-13 15:11 ` Norbert Preining
2009-04-13 15:26 ` Matthew Garrett
2009-04-13 15:43 ` Norbert Preining
2009-04-13 15:45 ` Matthew Garrett
2009-03-28 8:41 ` Matthias Welwarsky
2009-03-28 12:11 ` Albert Vilella
2009-03-28 12:19 ` Matthew Garrett
2009-03-28 12:22 ` Matthew Garrett
2009-03-28 14:19 ` Matthias Welwarsky
2009-03-28 14:44 ` Matthew Garrett
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20090331152035.GA20946@srcf.ucam.org \
--to=mjg59@srcf.ucam.org \
--cc=lenb@kernel.org \
--cc=linux-acpi@vger.kernel.org \
--cc=malattia@linux.it \
--cc=matze@welwarsky.de \
--cc=preining@logic.at \
--cc=sony-vaio-z-series@lists.launchpad.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox