public inbox for linux-acpi@vger.kernel.org
 help / color / mirror / Atom feed
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`

  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