Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
obj-m += als.o

KVERSION := $(shell uname -r)
KDIR := /lib/modules/$(KVERSION)/build
PWD := $(shell pwd)

all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
$(MAKE) -C $(KDIR) M=$(PWD) modules

clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
$(MAKE) -C $(KDIR) M=$(PWD) clean

install:
$(MAKE) -C $(KDIR) M=$(PWD) modules_install

18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,25 @@ ALS (Ambient Light Sensor) Driver

ASUS Zenbook Ambient Light Sensor Driver.

Device /sys/bus/acpi/devices/ACPI0008:00 (ACPI path: \_SB.ALS).
Device /sys/bus/acpi/devices/ACPI0008:00 (ACPI path: \_SB.ALS).

Exported attributes:
- ali (Ambient Light Illuminance) (ACPI path: \_SB.ALS._ALI)
- enable (write 1 or 0 to this attribute to enable or disable the sensor)
- raw_value (value from EC) (ACPI path: \_SB.PCI0.LPCB.EC0.RRAM 0x04c9)
- raw_max = 0xf (const value)

Installation with DKMS
==

Under root:

cd /usr/src && \
wget https://github.com/danieleds/als/archive/master.tar.gz && \
tar xvf als-master.tar.gz
dkms add -m als -v master
dkms install -m als -v master
echo als >>/etc/modules

Asus Zenbook:
==
Expand All @@ -23,7 +37,7 @@ For notifications set acpi_osi="Windows 2012".

What methods notify ALS device about changes:
- \_SB.ATKD.ALSC (flag) // status changed
- \_SB.PCI0.LPCB.EC0.EC0W
- \_SB.PCI0.LPCB.EC0.EC0W
- \_SB.PCI0.LPCB.EC0._QCD () // illuminance changed
- \_SB.PCI0.LPCB.EC0._QDD () // illuminance changed

Expand Down
132 changes: 131 additions & 1 deletion als.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ MODULE_LICENSE("GPL");
static int als_add(struct acpi_device *device);
static int als_remove(struct acpi_device *device);
static void als_notify(struct acpi_device *device, u32 event);
static acpi_handle acpi_handle_from_string(const char *str);

static const struct acpi_device_id als_device_ids[] = {
{"ACPI0008", 0},
Expand Down Expand Up @@ -49,10 +50,139 @@ static ssize_t als_show_ali(struct device *dev,
return sprintf(buf, "%d\n", als_get_ali(device));
}

static DEVICE_ATTR(ali, S_IRUGO, als_show_ali, NULL);
static u32 als_get_raw_value(struct acpi_device *device)
{
acpi_status status;
acpi_handle handle;
char path[] = "\\_SB.PCI0.LPCB.EC0.RRAM";
u32 addr = 0x04c9;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object arg0; //TODO: inplace union initialization
struct acpi_object_list arg = { .count = 1, .pointer = &arg0 };
u32 raw_value; //function result
union acpi_object* result = NULL; //buffer result

// prepare parameters
arg0.type = ACPI_TYPE_INTEGER;
arg0.integer.value = addr;

// get the handle of the method, must be a fully qualified path
handle = acpi_handle_from_string(path);
if (NULL == handle)
{
printk(KERN_ERR "als: unable to get handle for: %s\n", path);
return -1;
}

//get value
status = acpi_evaluate_object(handle, NULL, &arg, &buffer);
if (ACPI_FAILURE(status))
{
printk(KERN_ERR "als: unable to evalute: %s 0x%04x\n", path, addr);
return -1;
}

result = buffer.pointer;
if (ACPI_TYPE_INTEGER != result->type)
{
kfree(buffer.pointer);
return -1;
}
raw_value = result->integer.value;

kfree(buffer.pointer);
return raw_value;
}

static ssize_t als_show_raw_value(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct acpi_device *device = to_acpi_device(dev);

return sprintf(buf, "%d\n", als_get_raw_value(device));
}

static ssize_t als_show_raw_max(struct device *dev,
struct device_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", 0xf );
}

static DEVICE_ATTR(ali, S_IRUGO, als_show_ali, NULL);
static DEVICE_ATTR(raw_value, S_IRUGO, als_show_raw_value, NULL);
static DEVICE_ATTR(raw_max, S_IRUGO, als_show_raw_max, NULL);

static acpi_handle acpi_handle_from_string(const char *str) {
acpi_handle handle;
acpi_status handle_status;
handle_status = acpi_get_handle(NULL, (acpi_string) str, &handle);

if (ACPI_FAILURE(handle_status)) {
return NULL;
} else {
return handle;
}
}

static ssize_t als_enable_disable(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
if (count >= 1) {
acpi_handle tals_handle;
struct acpi_object_list arg;
union acpi_object param_0, param_1;

param_0.type = ACPI_TYPE_INTEGER;
param_0.integer.value = 0;
param_1.type = ACPI_TYPE_INTEGER;
param_1.integer.value = 1;

tals_handle = acpi_handle_from_string("\\_SB.PCI0.LPCB.EC0.TALS");
if (tals_handle == NULL) {
printk(KERN_ERR "als: unable to get handle for \\_SB.PCI0.LPCB.EC0.TALS\n");
return count;
}

if (buf[0] == '0') {
// Disable
acpi_status result;

arg.count = 1;
arg.pointer = &param_0;
result = acpi_evaluate_object(tals_handle, NULL, &arg, NULL);

} else if (buf[0] == '1') {
// Enable
acpi_handle alsc_handle;
acpi_status result;

arg.count = 1;
arg.pointer = &param_1;
result = acpi_evaluate_object(tals_handle, NULL, &arg, NULL);

alsc_handle = acpi_handle_from_string("\\_SB.ATKD.ALSC");
if (alsc_handle == NULL) {
printk(KERN_ERR "als: unable to get handle for \\_SB.ATKD.ALSC\n");
return count;
}

result = acpi_evaluate_object(alsc_handle, NULL, &arg, NULL);
}

return count;

} else {
return count;
}
}

static DEVICE_ATTR(enable, S_IWUSR, NULL, als_enable_disable);

static struct attribute *als_attributes[] = {
&dev_attr_ali.attr,
&dev_attr_enable.attr,
&dev_attr_raw_value.attr,
&dev_attr_raw_max.attr,
NULL
};

Expand Down
7 changes: 7 additions & 0 deletions dkms.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
PACKAGE_NAME="als"
PACKAGE_VERSION="1.0"
CLEAN="make clean"
MAKE[0]="make all KVERSION=$kernelver"
BUILT_MODULE_NAME[0]="als"
DEST_MODULE_LOCATION[0]="/updates"
AUTOINSTALL="yes"