--- drivers/acpi/asus_acpi.c.orig 2006-05-03 13:54:39.000000000 +0200 +++ drivers/acpi/asus_acpi.c 2006-05-03 14:39:00.000000000 +0200 @@ -51,6 +51,8 @@ #define PROC_INFO "info" #define PROC_LCD "lcd" #define PROC_BRN "brn" +#define PROC_LSSW "lssw" +#define PROC_LSLVL "lslvl" #define PROC_DISP "disp" #define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver" @@ -71,6 +73,10 @@ #define WLED_ON 0x02 #define TLED_ON 0x04 +/* default (initial) values for light sensor */ +#define DEFAULT_LIGHT_SWITCH_VALUE 0 // 0: Disable light sensor, 1: Enable light sensor +#define DEFAULT_LIGHT_LEVEL_VALUE 5 // Light sensor level 0-15 (FIXME - Are we sure?) + MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); MODULE_DESCRIPTION(ACPI_HOTK_NAME); MODULE_LICENSE("GPL"); @@ -99,6 +105,8 @@ char *brightness_set; //method to set absolute brightness_R char *brightness_get; //method to get absolute brightness_R char *brightness_status; //node to get brightness____________A + char *light_sens_switch; //light sensor enable/disable set method + char *light_sens_level; //light sensor level set method char *display_set; //method to set video output________R char *display_get; //method to get video output________R }; @@ -113,6 +121,8 @@ char status; //status of the hotk, for LEDs, ... struct model_data *methods; //methods available on the laptop u8 brightness; //brightness level + u8 light_level; //light sensor level + u8 light_switch; //light sensor switch value enum { A1x = 0, //A1340D, A1300F A2x, //A2500H @@ -128,6 +138,7 @@ M2E, //M2400E, L4400L M6N, //M6800N M6R, //M6700R + M7V, //ASUS Z71V platform (others too?) P30, //Samsung P30 S1x, //S1300A, but also L1400B and M2400A (L84F) S2x, //S200 (J1 reported), Victor MP-XP7210 @@ -289,6 +300,8 @@ .lcd_status = "\\GP06", .brightness_set = "SPLV", .brightness_get = "GPLV", + .light_sens_switch = "ALSC", /* For Z71A, FIXME - OK for other models? */ + .light_sens_level = "ALSL", /* For Z71A, FIXME - OK for other models? */ .display_set = "SDSP", .display_get = "\\INFB"}, @@ -315,6 +328,19 @@ .display_get = "\\SSTE"}, { + .name = "M7V", + .mt_mled = "MLED", +/* WLED present in dsdt but can be controlled directly by wifi card */ + .mt_lcd_switch = xxN_PREFIX "_Q10", + .lcd_status = xxN_PREFIX "RPIN", /* Different for onboard GFX? (z71a) */ + .brightness_set = "SPLV", + .brightness_get = "GPLV", + .light_sens_switch = "ALSC", + .light_sens_level = "ALSL", + .display_set = "SDSP", /* Works but buggy, especially tv-out*/ + .display_get = "\\_SB.PCI0.P0P2.VGA.GETD"}, /* Different for onboard GFX?*/ + + { .name = "P30", .mt_wled = "WLED", .mt_lcd_switch = P30_PREFIX "_Q0E", @@ -602,15 +628,8 @@ { int lcd = 0; - if (hotk->model != L3H) { - /* We don't have to check anything if we are here */ - if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd)) - printk(KERN_WARNING - "Asus ACPI: Error reading LCD status\n"); - - if (hotk->model == L2D) - lcd = ~lcd; - } else { /* L3H and the like have to be handled differently */ + /* L3H and the like have to be handled differently */ + if (hotk->model == L3H) { acpi_status status = 0; struct acpi_object_list input; union acpi_object mt_params[2]; @@ -638,7 +657,30 @@ /* That's what the AML code does */ lcd = out_obj.integer.value >> 8; } + else if (hotk->model == M7V) { /* M7V works differently */ + struct acpi_buffer output; + union acpi_object out_obj; + output.length = sizeof(out_obj); + output.pointer = &out_obj; + + if (!write_acpi_int(NULL, hotk->methods->lcd_status, 0x56, &output)) { + printk(KERN_WARNING "Asus ACPI: Error reading LCD status\n"); + return -1; + } + + if (out_obj.type == ACPI_TYPE_INTEGER) + lcd = out_obj.integer.value; + } + else { + /* We don't have to check anything if we are here */ + if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd)) + printk(KERN_WARNING + "Asus ACPI: Error reading LCD status\n"); + if (hotk->model == L2D) + lcd = ~lcd; + } + return (lcd & 1); } @@ -764,6 +806,72 @@ return count; } +static void set_light_sens_switch(int value) +{ + /* no sanity check needed for now */ + if (!write_acpi_int(hotk->handle, hotk->methods->light_sens_switch, + value, NULL)) + printk(KERN_WARNING "Asus ACPI: Error setting light sensor switch\n"); + hotk->light_switch = value; + return; +} + +static int +proc_read_lssw(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + return sprintf(page, "%d\n", hotk->light_switch); +} + +static int +proc_write_lssw(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int value; + + count = parse_arg(buffer, count, &value); + if (count > 0) + set_light_sens_switch(value ? 1 : 0); + else if (count < 0) + printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); + + return count; +} + +static void set_light_sens_level(int value) +{ + /* no sanity check needed for now */ + if (!write_acpi_int(hotk->handle, hotk->methods->light_sens_level, + value, NULL)) + printk(KERN_WARNING "Asus ACPI: Error setting light sensor level\n"); + hotk->light_level = value; + return; +} + +static int +proc_read_lslvl(char *page, char **start, off_t off, int count, int *eof, + void *data) +{ + return sprintf(page, "%d\n", hotk->light_level); +} + +static int +proc_write_lslvl(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int value; + + count = parse_arg(buffer, count, &value); + if (count > 0) { + value = (0 < value) ? ((15 < value) ? 15 : value) : 0; + set_light_sens_level(value); + } + else if (count < 0) + printk(KERN_WARNING "Asus ACPI: Error reading user input\n"); + + return count; +} + static void set_display(int value) { /* no sanity check needed for now */ @@ -901,6 +1009,16 @@ device); } + if (hotk->methods->light_sens_switch) { + asus_proc_add(PROC_LSSW, &proc_write_lssw, &proc_read_lssw, mode, + device); + } + + if (hotk->methods->light_sens_level) { + asus_proc_add(PROC_LSLVL, &proc_write_lslvl, &proc_read_lslvl, mode, + device); + } + if (hotk->methods->display_set) { asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp, mode, device); @@ -926,6 +1044,10 @@ || (hotk->methods->brightness_get && hotk->methods->brightness_set)) remove_proc_entry(PROC_BRN, acpi_device_dir(device)); + if (hotk->methods->light_sens_switch) + remove_proc_entry(PROC_LSSW, acpi_device_dir(device)); + if (hotk->methods->light_sens_level) + remove_proc_entry(PROC_LSLVL, acpi_device_dir(device)); if (hotk->methods->display_set) remove_proc_entry(PROC_DISP, acpi_device_dir(device)); } @@ -989,10 +1111,6 @@ printk(KERN_NOTICE " BSTS called, 0x%02x returned\n", bsts_result); - /* This is unlikely with implicit return */ - if (buffer.pointer == NULL) - return -EINVAL; - model = (union acpi_object *) buffer.pointer; /* * Samsung P30 has a device with a valid _HID whose INIT does not @@ -1001,9 +1119,7 @@ * driver. We assume that every ACPI_TYPE_STRING is a valid model * identifier but it's still possible to get completely bogus data. */ - if (model->type == ACPI_TYPE_STRING) { - printk(KERN_NOTICE " %s model detected, ", model->string.pointer); - } else { + if (!model) { if (asus_info && /* Samsung P30 */ strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) { hotk->model = P30; @@ -1022,6 +1138,9 @@ return AE_OK; } + if (model->type == ACPI_TYPE_STRING) + printk(KERN_NOTICE " %s model detected, ", model->string.pointer); + hotk->model = END_MODEL; if (strncmp(model->string.pointer, "L3D", 3) == 0) hotk->model = L3D; @@ -1039,6 +1158,8 @@ hotk->model = M6N; else if (strncmp(model->string.pointer, "M6R", 3) == 0) hotk->model = M6R; + else if (strncmp(model->string.pointer, "M7V", 3) == 0) + hotk->model = M7V; else if (strncmp(model->string.pointer, "M2N", 3) == 0 || strncmp(model->string.pointer, "M3N", 3) == 0 || strncmp(model->string.pointer, "M5N", 3) == 0 || @@ -1180,6 +1301,16 @@ } } + /* Set initial values of light sensor switch and level */ + hotk->light_switch = DEFAULT_LIGHT_SWITCH_VALUE; + hotk->light_level = DEFAULT_LIGHT_LEVEL_VALUE; + + if (hotk->methods->light_sens_switch) + set_light_sens_switch (hotk->light_switch); + + if (hotk->methods->light_sens_level) + set_light_sens_level (hotk->light_level); + end: if (result) { kfree(hotk);