asus-ul30 team mailing list archive
-
asus-ul30 team
-
Mailing list archive
-
Message #00104
suspend/resume fixes for nvidia_g210m_acpi.c
Hi,
I have an UL30VT-A1. I was happy to find nvidia-g210m-acpi, but I found
that it was causing problems across suspend/resume cycles. I made some
simple changes that seem to make it work better:
1) catch post suspend event so that module doesn't need to be
unloaded/reloaded after suspend
2) unregister power notifier on unload, so that power events don't
cause kernel panic after module is unloaded.
Hope someone else can benefit. :)
Modified code is attached. Maybe the deb can be updated accordingly?
-- Buck
/*
* Linux kernel module that disables the discrete graphics board
*
* Original version for Lenovo laptops by Sylvain Joyeux <sylvain.joyeux@xxxxxxx> Copyright (c) 2009
*
* mil2 added nVidia GeForce G210M support (for Asus UL30VT, UL50V, UL80V laptops)
* o8x8 added post hibernate support
*
* Charles 'Buck' Krasic <krasic@xxxxxxxxx> added post suspend support and unload fix.
*
* Power down the nVidia card to save up to 4W of power.
*
*/
/*
* Name: nvidia_g210m_acpi.c
* Source code for nvidia_g210m_acpi switch-off kernel module
*
* Licensed under the GNU GPL
*
*/
#include <acpi/acpi.h>
#include <linux/suspend.h>
MODULE_LICENSE("GPL");
static acpi_handle root_handle;
static int kill_nvidia(void)
{
acpi_status status;
// The device handle
acpi_handle handle;
struct acpi_object_list args;
// For the return value
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
status = acpi_get_handle(root_handle, "\\_SB.PCI0.P0P1.VGA._OFF", &handle);
if (ACPI_FAILURE(status))
{
printk("%s: cannot get ACPI handle: %s\n", __func__, acpi_format_exception(status));
return -ENOSYS;
}
args.count = 0;
args.pointer = NULL;
status = acpi_evaluate_object(handle, NULL, &args, &buffer);
if (ACPI_FAILURE(status))
{
printk("%s: _OFF method call failed: %s\n", __func__, acpi_format_exception(status));
return -ENOSYS;
}
kfree(buffer.pointer);
printk("%s: disabled the discrete graphics card\n", __func__);
return 0;
}
static int power_event(struct notifier_block *this, unsigned long event, void *ptr)
{
switch (event) {
case PM_POST_HIBERNATION:
printk("%s: post_hibernation\n", __func__);
kill_nvidia();
break;
case PM_POST_SUSPEND:
printk("%s: post_suspend\n", __func__);
kill_nvidia();
break;
default:
break;
}
return NOTIFY_DONE;
}
static struct notifier_block power_notifier = { .notifier_call = power_event, };
static int __init nvidia_g210m_acpi(void)
{
int ret = register_pm_notifier(&power_notifier);
if (ret) return ret;
printk("%s: init\n", __func__);
return kill_nvidia();
}
static void dummy(void)
{
int ret = unregister_pm_notifier(&power_notifier);
printk("%s: unregiseter %d\n", __func__, ret);
}
module_init(nvidia_g210m_acpi);
module_exit(dummy);