Skip to content

Commit

Permalink
Repository cleanup, added several methods and scripts from feedback
Browse files Browse the repository at this point in the history
  • Loading branch information
mkottman committed Dec 17, 2012
1 parent 02ef13c commit 342a3d2
Show file tree
Hide file tree
Showing 9 changed files with 96 additions and 20 deletions.
29 changes: 18 additions & 11 deletions README → README.md
@@ -1,38 +1,45 @@
A kernel module that enables you to call ACPI methods by writing the method
name followed by arguments to /proc/acpi/call.
A kernel simple module that enables you to call ACPI methods by writing the
method name followed by arguments to `/proc/acpi/call`.

This module is to be considered a proof-of-concept and has been superseeded by
projects like [bbswitch](https://github.com/Bumblebee-Project/bbswitch). It
allows you to tamper with your system and should be used with caution.

Usage:

echo '<call>' | sudo tee /proc/acpi/call

You can then retrieve the result of the call by checking your dmesg or:

sudo cat /proc/acpi/call

An example to turn off discrete graphics card in a dual graphics environment
(like NVIDIA Optimus):

# turn off discrete graphics card
echo '\_SB.PCI0.PEG1.GFX0.DOFF' > /proc/acpi/call
# turn it back on
echo '\_SB.PCI0.PEG1.GFX0.DON' > /proc/acpi/call
# turn off discrete graphics card
echo '\_SB.PCI0.PEG1.GFX0.DOFF' > /proc/acpi/call
# turn it back on
echo '\_SB.PCI0.PEG1.GFX0.DON' > /proc/acpi/call

These work on my ASUS K52J notebook, but may not work for you. For a list of
methods to try, see http://linux-hybrid-graphics.blogspot.com/ or try running
the provided script test_off.sh
the provided script `examples/turn_off_gpu.sh`

It SHOULD be ok to test all of the methods, until you see a drop in battery
drain rate (grep rate /proc/acpi/battery/BAT0/state), however it comes
with NO WARRANTY.
drain rate (`grep rate /proc/acpi/battery/BAT0/state`), however it comes
with NO WARRANTY - it may hang your computer/laptop, fail to work, etc.

You can pass parameters to acpi_call by writing them after the method,
You can pass parameters to `acpi_call` by writing them after the method,
separated by single space. Currently, you can pass the following parameter
types:

* ACPI_INTEGER - by writing NNN or 0xNNN, where NNN is an integer/hex
* ACPI_STRING - by enclosing the string in quotes: "hello, world"
* ACPI_BUFFER - by writing bXXXX, where XXXX is a hex string without spaces,
or by writing { b1, b2, b3, b4 }, where b1-4 are integers

The status after a call can be read back from /proc/acpi/call:
The status after a call can be read back from `/proc/acpi/call`:

* 'not called' - nothing to report
* 'Error: <description>' - the call failed
* '0xNN' - the call succeeded, and returned an integer
Expand Down
22 changes: 21 additions & 1 deletion acpi_call.c
Expand Up @@ -9,7 +9,13 @@

MODULE_LICENSE("GPL");

/* Uncomment the following line to enable debug messages */
/*
#define DEBUG
*/

#define BUFFER_SIZE 256
#define MAX_ACPI_ARGS 16

extern struct proc_dir_entry *acpi_root_dir;

Expand All @@ -23,6 +29,7 @@ static size_t get_avail_bytes(void) {
static char *get_buffer_end(void) {
return result_buffer + strlen(result_buffer);
}

/** Appends the contents of an acpi_object to the result buffer
@param result An acpi object holding result data
@returns 0 if the result could fully be saved, a higher value otherwise
Expand Down Expand Up @@ -87,7 +94,9 @@ static void do_acpi_call(const char * method, int argc, union acpi_object *argv)
struct acpi_object_list arg;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };

#ifdef DEBUG
printk(KERN_INFO "acpi_call: Calling %s\n", method);
#endif

// get the handle of the method, must be a fully qualified path
status = acpi_get_handle(NULL, (acpi_string) method, &handle);
Expand Down Expand Up @@ -117,7 +126,9 @@ static void do_acpi_call(const char * method, int argc, union acpi_object *argv)
acpi_result_to_string(buffer.pointer);
kfree(buffer.pointer);

#ifdef DEBUG
printk(KERN_INFO "acpi_call: Call successful: %s\n", result_buffer);
#endif
}

/** Decodes 2 hex characters to an u8 int
Expand Down Expand Up @@ -146,7 +157,7 @@ static char *parse_acpi_args(char *input, int *nargs, union acpi_object **args)
if (*s == 0)
return input;

*args = (union acpi_object *) kmalloc(16 * sizeof(union acpi_object), GFP_KERNEL);
*args = (union acpi_object *) kmalloc(MAX_ACPI_ARGS * sizeof(union acpi_object), GFP_KERNEL);

while (*s) {
if (*s == ' ') {
Expand Down Expand Up @@ -290,8 +301,11 @@ static int acpi_proc_read(char *page, char **start, off_t off,
return 0;
}

// output the current result buffer
len = strlen(result_buffer);
memcpy(page, result_buffer, len + 1);

// initialize the result buffer for later
strcpy(result_buffer, "not called");

return len;
Expand All @@ -311,15 +325,21 @@ static int __init init_acpi_call(void)

acpi_entry->write_proc = acpi_proc_write;
acpi_entry->read_proc = acpi_proc_read;

#ifdef DEBUG
printk(KERN_INFO "acpi_call: Module loaded successfully\n");
#endif

return 0;
}

static void __exit unload_acpi_call(void)
{
remove_proc_entry("call", acpi_root_dir);

#ifdef DEBUG
printk(KERN_INFO "acpi_call: Module unloaded successfully\n");
#endif
}

module_init(init_acpi_call);
Expand Down
File renamed without changes.
46 changes: 46 additions & 0 deletions examples/dellL702X.sh
@@ -0,0 +1,46 @@
#!/bin/sh
# Power control for Dell L702X
# by Jos Hickson
# adapted from "Power control for Asus 1215N Optimus by Pete Eberlein"

if ! lsmod | grep -q acpi_call; then
echo "Error: acpi_call module not loaded"
exit
fi

acpi_call () {
echo "$*" > /proc/acpi/call
cat /proc/acpi/call
}


case "$1" in
off)
echo _DSM $(acpi_call "\_SB.PCI0.PEG0.PEGP._DSM" \
"{0xF8,0xD8,0x86,0xA4,0xDA,0x0B,0x1B,0x47," \
"0xA7,0x2B,0x60,0x42,0xA6,0xB5,0xBE,0xE0}" \
"0x100 0x1A {0x1,0x0,0x0,0x3}")
# ok to turn off: Buffer {0x59 0x0 0x0 0x11}
# is already off: Buffer {0x41 0x0 0x0 0x11}
echo _PS3 $(acpi_call "\_SB.PCI0.PEG0.PEGP._PS3")
;;
on)
echo _PS0 $(acpi_call "\_SB.PCI0.PEG0.PEGP._PS0")
;;
*)
echo "Usage: $0 [on|off]"
esac


PSC=$(acpi_call "\_SB.PCI0.PEG0.PEGP._PSC")
#echo _PSC ${PSC}
case "$PSC" in
0x0)
PSC="on"
;;
0x3)
PSC="off"
;;
esac
echo "Dell L702X Optimus appears to be ${PSC}"

File renamed without changes.
19 changes: 11 additions & 8 deletions test_off.sh → examples/turn_off_gpu.sh 100644 → 100755
Expand Up @@ -27,23 +27,26 @@ methods="
\_SB.PCI0.LPC.EC.PUBS._OFF
\_SB.PCI0.P0P2.NVID._OFF
\_SB.PCI0.P0P2.VGA.PX02
\_SB_.PCI0.PEGP.DGFX._OFF
\_SB_.PCI0.VGA.PX02
"

for m in $methods; do
echo -n "Trying $m: "
echo $m > /proc/acpi/call
result=$(cat /proc/acpi/call)
case "$result" in
for m in $methods; do
echo -n "Trying $m: "
echo $m > /proc/acpi/call
result=$(cat /proc/acpi/call)
case "$result" in
Error*)
echo "failed"
;;
*)
echo "works!"
#break
# break # try out outher methods too
;;
esac
esac
done

else
echo 'The acpi_call module is not loaded'
echo "The acpi_call module is not loaded, try running 'modprobe acpi_call' or 'insmod acpi_call.ko' as root"
exit 1
fi
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 comments on commit 342a3d2

Please sign in to comment.