aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/asus_acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/asus_acpi.c')
-rw-r--r--drivers/acpi/asus_acpi.c335
1 files changed, 225 insertions, 110 deletions
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index 055cfd5c8766..e9ee4c52a5f6 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -2,7 +2,7 @@
2 * asus_acpi.c - Asus Laptop ACPI Extras 2 * asus_acpi.c - Asus Laptop ACPI Extras
3 * 3 *
4 * 4 *
5 * Copyright (C) 2002, 2003, 2004 Julien Lerouge, Karol Kozimor 5 * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -26,11 +26,8 @@
26 * Pontus Fuchs - Helper functions, cleanup 26 * Pontus Fuchs - Helper functions, cleanup
27 * Johann Wiesner - Small compile fixes 27 * Johann Wiesner - Small compile fixes
28 * John Belmonte - ACPI code for Toshiba laptop was a good starting point. 28 * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
29 * Éric Burghard - LED display support for W1N
29 * 30 *
30 * TODO:
31 * add Fn key status
32 * Add mode selection on module loading (parameter) -> still necessary?
33 * Complete display switching -- may require dirty hacks or calling _DOS?
34 */ 31 */
35 32
36#include <linux/kernel.h> 33#include <linux/kernel.h>
@@ -42,12 +39,14 @@
42#include <acpi/acpi_bus.h> 39#include <acpi/acpi_bus.h>
43#include <asm/uaccess.h> 40#include <asm/uaccess.h>
44 41
45#define ASUS_ACPI_VERSION "0.29" 42#define ASUS_ACPI_VERSION "0.30"
46 43
47#define PROC_ASUS "asus" //the directory 44#define PROC_ASUS "asus" //the directory
48#define PROC_MLED "mled" 45#define PROC_MLED "mled"
49#define PROC_WLED "wled" 46#define PROC_WLED "wled"
50#define PROC_TLED "tled" 47#define PROC_TLED "tled"
48#define PROC_BT "bluetooth"
49#define PROC_LEDD "ledd"
51#define PROC_INFO "info" 50#define PROC_INFO "info"
52#define PROC_LCD "lcd" 51#define PROC_LCD "lcd"
53#define PROC_BRN "brn" 52#define PROC_BRN "brn"
@@ -67,9 +66,10 @@
67/* 66/*
68 * Flags for hotk status 67 * Flags for hotk status
69 */ 68 */
70#define MLED_ON 0x01 //is MLED ON ? 69#define MLED_ON 0x01 //mail LED
71#define WLED_ON 0x02 70#define WLED_ON 0x02 //wireless LED
72#define TLED_ON 0x04 71#define TLED_ON 0x04 //touchpad LED
72#define BT_ON 0x08 //internal Bluetooth
73 73
74MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); 74MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
75MODULE_DESCRIPTION(ACPI_HOTK_NAME); 75MODULE_DESCRIPTION(ACPI_HOTK_NAME);
@@ -92,7 +92,10 @@ struct model_data {
92 char *wled_status; //node to handle wled reading_______A 92 char *wled_status; //node to handle wled reading_______A
93 char *mt_tled; //method to handle tled_____________R 93 char *mt_tled; //method to handle tled_____________R
94 char *tled_status; //node to handle tled reading_______A 94 char *tled_status; //node to handle tled reading_______A
95 char *mt_lcd_switch; //method to turn LCD ON/OFF_________A 95 char *mt_ledd; //method to handle LED display______R
96 char *mt_bt_switch; //method to switch Bluetooth on/off_R
97 char *bt_status; //no model currently supports this__?
98 char *mt_lcd_switch; //method to turn LCD on/off_________A
96 char *lcd_status; //node to read LCD panel state______A 99 char *lcd_status; //node to read LCD panel state______A
97 char *brightness_up; //method to set brightness up_______A 100 char *brightness_up; //method to set brightness up_______A
98 char *brightness_down; //guess what ?______________________A 101 char *brightness_down; //guess what ?______________________A
@@ -111,27 +114,31 @@ struct asus_hotk {
111 struct acpi_device *device; //the device we are in 114 struct acpi_device *device; //the device we are in
112 acpi_handle handle; //the handle of the hotk device 115 acpi_handle handle; //the handle of the hotk device
113 char status; //status of the hotk, for LEDs, ... 116 char status; //status of the hotk, for LEDs, ...
117 u32 ledd_status; //status of the LED display
114 struct model_data *methods; //methods available on the laptop 118 struct model_data *methods; //methods available on the laptop
115 u8 brightness; //brightness level 119 u8 brightness; //brightness level
116 enum { 120 enum {
117 A1x = 0, //A1340D, A1300F 121 A1x = 0, //A1340D, A1300F
118 A2x, //A2500H 122 A2x, //A2500H
123 A4G, //A4700G
119 D1x, //D1 124 D1x, //D1
120 L2D, //L2000D 125 L2D, //L2000D
121 L3C, //L3800C 126 L3C, //L3800C
122 L3D, //L3400D 127 L3D, //L3400D
123 L3H, //L3H, but also L2000E 128 L3H, //L3H, L2000E, L5D
124 L4R, //L4500R 129 L4R, //L4500R
125 L5x, //L5800C 130 L5x, //L5800C
126 L8L, //L8400L 131 L8L, //L8400L
127 M1A, //M1300A 132 M1A, //M1300A
128 M2E, //M2400E, L4400L 133 M2E, //M2400E, L4400L
129 M6N, //M6800N 134 M6N, //M6800N, W3400N
130 M6R, //M6700R 135 M6R, //M6700R, A3000G
131 P30, //Samsung P30 136 P30, //Samsung P30
132 S1x, //S1300A, but also L1400B and M2400A (L84F) 137 S1x, //S1300A, but also L1400B and M2400A (L84F)
133 S2x, //S200 (J1 reported), Victor MP-XP7210 138 S2x, //S200 (J1 reported), Victor MP-XP7210
134 xxN, //M2400N, M3700N, M5200N, S1300N, S5200N, W1OOON 139 W1N, //W1000N
140 W5A, //W5A
141 xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
135 //(Centrino) 142 //(Centrino)
136 END_MODEL 143 END_MODEL
137 } model; //Models currently supported 144 } model; //Models currently supported
@@ -149,17 +156,8 @@ struct asus_hotk {
149 156
150static struct model_data model_conf[END_MODEL] = { 157static struct model_data model_conf[END_MODEL] = {
151 /* 158 /*
152 * Those pathnames are relative to the HOTK / ATKD device :
153 * - mt_mled
154 * - mt_wled
155 * - brightness_set
156 * - brightness_get
157 * - display_set
158 * - display_get
159 *
160 * TODO I have seen a SWBX and AIBX method on some models, like L1400B, 159 * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
161 * it seems to be a kind of switch, but what for ? 160 * it seems to be a kind of switch, but what for ?
162 *
163 */ 161 */
164 162
165 { 163 {
@@ -184,6 +182,16 @@ static struct model_data model_conf[END_MODEL] = {
184 .display_get = "\\INFB"}, 182 .display_get = "\\INFB"},
185 183
186 { 184 {
185 .name = "A4G",
186 .mt_mled = "MLED",
187/* WLED present, but not controlled by ACPI */
188 .mt_lcd_switch = xxN_PREFIX "_Q10",
189 .brightness_set = "SPLV",
190 .brightness_get = "GPLV",
191 .display_set = "SDSP",
192 .display_get = "\\ADVG"},
193
194 {
187 .name = "D1x", 195 .name = "D1x",
188 .mt_mled = "MLED", 196 .mt_mled = "MLED",
189 .mt_lcd_switch = "\\Q0D", 197 .mt_lcd_switch = "\\Q0D",
@@ -302,7 +310,8 @@ static struct model_data model_conf[END_MODEL] = {
302 .brightness_set = "SPLV", 310 .brightness_set = "SPLV",
303 .brightness_get = "GPLV", 311 .brightness_get = "GPLV",
304 .display_set = "SDSP", 312 .display_set = "SDSP",
305 .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"}, 313 .display_get = "\\SSTE"},
314
306 { 315 {
307 .name = "M6R", 316 .name = "M6R",
308 .mt_mled = "MLED", 317 .mt_mled = "MLED",
@@ -312,7 +321,7 @@ static struct model_data model_conf[END_MODEL] = {
312 .brightness_set = "SPLV", 321 .brightness_set = "SPLV",
313 .brightness_get = "GPLV", 322 .brightness_get = "GPLV",
314 .display_set = "SDSP", 323 .display_set = "SDSP",
315 .display_get = "\\SSTE"}, 324 .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
316 325
317 { 326 {
318 .name = "P30", 327 .name = "P30",
@@ -345,6 +354,28 @@ static struct model_data model_conf[END_MODEL] = {
345 .brightness_down = S2x_PREFIX "_Q0A"}, 354 .brightness_down = S2x_PREFIX "_Q0A"},
346 355
347 { 356 {
357 .name = "W1N",
358 .mt_mled = "MLED",
359 .mt_wled = "WLED",
360 .mt_ledd = "SLCM",
361 .mt_lcd_switch = xxN_PREFIX "_Q10",
362 .lcd_status = "\\BKLT",
363 .brightness_set = "SPLV",
364 .brightness_get = "GPLV",
365 .display_set = "SDSP",
366 .display_get = "\\ADVG"},
367
368 {
369 .name = "W5A",
370 .mt_bt_switch = "BLED",
371 .mt_wled = "WLED",
372 .mt_lcd_switch = xxN_PREFIX "_Q10",
373 .brightness_set = "SPLV",
374 .brightness_get = "GPLV",
375 .display_set = "SDSP",
376 .display_get = "\\ADVG"},
377
378 {
348 .name = "xxN", 379 .name = "xxN",
349 .mt_mled = "MLED", 380 .mt_mled = "MLED",
350/* WLED present, but not controlled by ACPI */ 381/* WLED present, but not controlled by ACPI */
@@ -563,6 +594,36 @@ proc_write_mled(struct file *file, const char __user * buffer,
563} 594}
564 595
565/* 596/*
597 * Proc handlers for LED display
598 */
599static int
600proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
601 void *data)
602{
603 return sprintf(page, "0x%08x\n", hotk->ledd_status);
604}
605
606static int
607proc_write_ledd(struct file *file, const char __user * buffer,
608 unsigned long count, void *data)
609{
610 int value;
611
612 count = parse_arg(buffer, count, &value);
613 if (count > 0) {
614 if (!write_acpi_int
615 (hotk->handle, hotk->methods->mt_ledd, value, NULL))
616 printk(KERN_WARNING
617 "Asus ACPI: LED display write failed\n");
618 else
619 hotk->ledd_status = (u32) value;
620 } else if (count < 0)
621 printk(KERN_WARNING "Asus ACPI: Error reading user input\n");
622
623 return count;
624}
625
626/*
566 * Proc handlers for WLED 627 * Proc handlers for WLED
567 */ 628 */
568static int 629static int
@@ -581,6 +642,25 @@ proc_write_wled(struct file *file, const char __user * buffer,
581} 642}
582 643
583/* 644/*
645 * Proc handlers for Bluetooth
646 */
647static int
648proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
649 void *data)
650{
651 return sprintf(page, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
652}
653
654static int
655proc_write_bluetooth(struct file *file, const char __user * buffer,
656 unsigned long count, void *data)
657{
658 /* Note: mt_bt_switch controls both internal Bluetooth adapter's
659 presence and its LED */
660 return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
661}
662
663/*
584 * Proc handlers for TLED 664 * Proc handlers for TLED
585 */ 665 */
586static int 666static int
@@ -876,6 +956,11 @@ static int asus_hotk_add_fs(struct acpi_device *device)
876 mode, device); 956 mode, device);
877 } 957 }
878 958
959 if (hotk->methods->mt_ledd) {
960 asus_proc_add(PROC_LEDD, &proc_write_ledd, &proc_read_ledd,
961 mode, device);
962 }
963
879 if (hotk->methods->mt_mled) { 964 if (hotk->methods->mt_mled) {
880 asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled, 965 asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled,
881 mode, device); 966 mode, device);
@@ -886,6 +971,11 @@ static int asus_hotk_add_fs(struct acpi_device *device)
886 mode, device); 971 mode, device);
887 } 972 }
888 973
974 if (hotk->methods->mt_bt_switch) {
975 asus_proc_add(PROC_BT, &proc_write_bluetooth,
976 &proc_read_bluetooth, mode, device);
977 }
978
889 /* 979 /*
890 * We need both read node and write method as LCD switch is also accessible 980 * We need both read node and write method as LCD switch is also accessible
891 * from keyboard 981 * from keyboard
@@ -919,6 +1009,10 @@ static int asus_hotk_remove_fs(struct acpi_device *device)
919 remove_proc_entry(PROC_MLED, acpi_device_dir(device)); 1009 remove_proc_entry(PROC_MLED, acpi_device_dir(device));
920 if (hotk->methods->mt_tled) 1010 if (hotk->methods->mt_tled)
921 remove_proc_entry(PROC_TLED, acpi_device_dir(device)); 1011 remove_proc_entry(PROC_TLED, acpi_device_dir(device));
1012 if (hotk->methods->mt_ledd)
1013 remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
1014 if (hotk->methods->mt_bt_switch)
1015 remove_proc_entry(PROC_BT, acpi_device_dir(device));
922 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) 1016 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
923 remove_proc_entry(PROC_LCD, acpi_device_dir(device)); 1017 remove_proc_entry(PROC_LCD, acpi_device_dir(device));
924 if ((hotk->methods->brightness_up 1018 if ((hotk->methods->brightness_up
@@ -951,6 +1045,65 @@ static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
951} 1045}
952 1046
953/* 1047/*
1048 * Match the model string to the list of supported models. Return END_MODEL if
1049 * no match or model is NULL.
1050 */
1051static int asus_model_match(char *model)
1052{
1053 if (model == NULL)
1054 return END_MODEL;
1055
1056 if (strncmp(model, "L3D", 3) == 0)
1057 return L3D;
1058 else if (strncmp(model, "L2E", 3) == 0 ||
1059 strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
1060 return L3H;
1061 else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
1062 return L3C;
1063 else if (strncmp(model, "L8L", 3) == 0)
1064 return L8L;
1065 else if (strncmp(model, "L4R", 3) == 0)
1066 return L4R;
1067 else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
1068 return M6N;
1069 else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
1070 return M6R;
1071 else if (strncmp(model, "M2N", 3) == 0 ||
1072 strncmp(model, "M3N", 3) == 0 ||
1073 strncmp(model, "M5N", 3) == 0 ||
1074 strncmp(model, "M6N", 3) == 0 ||
1075 strncmp(model, "S1N", 3) == 0 ||
1076 strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0)
1077 return xxN;
1078 else if (strncmp(model, "M1", 2) == 0)
1079 return M1A;
1080 else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
1081 return M2E;
1082 else if (strncmp(model, "L2", 2) == 0)
1083 return L2D;
1084 else if (strncmp(model, "L8", 2) == 0)
1085 return S1x;
1086 else if (strncmp(model, "D1", 2) == 0)
1087 return D1x;
1088 else if (strncmp(model, "A1", 2) == 0)
1089 return A1x;
1090 else if (strncmp(model, "A2", 2) == 0)
1091 return A2x;
1092 else if (strncmp(model, "J1", 2) == 0)
1093 return S2x;
1094 else if (strncmp(model, "L5", 2) == 0)
1095 return L5x;
1096 else if (strncmp(model, "A4G", 3) == 0)
1097 return A4G;
1098 else if (strncmp(model, "W1N", 3) == 0)
1099 return W1N;
1100 else if (strncmp(model, "W5A", 3) == 0)
1101 return W5A;
1102 else
1103 return END_MODEL;
1104}
1105
1106/*
954 * This function is used to initialize the hotk with right values. In this 1107 * This function is used to initialize the hotk with right values. In this
955 * method, we can make all the detection we want, and modify the hotk struct 1108 * method, we can make all the detection we want, and modify the hotk struct
956 */ 1109 */
@@ -960,6 +1113,7 @@ static int asus_hotk_get_info(void)
960 struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL }; 1113 struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
961 union acpi_object *model = NULL; 1114 union acpi_object *model = NULL;
962 int bsts_result; 1115 int bsts_result;
1116 char *string = NULL;
963 acpi_status status; 1117 acpi_status status;
964 1118
965 /* 1119 /*
@@ -989,114 +1143,73 @@ static int asus_hotk_get_info(void)
989 printk(KERN_NOTICE " BSTS called, 0x%02x returned\n", 1143 printk(KERN_NOTICE " BSTS called, 0x%02x returned\n",
990 bsts_result); 1144 bsts_result);
991 1145
992 /* This is unlikely with implicit return */
993 if (buffer.pointer == NULL)
994 return -EINVAL;
995
996 model = (union acpi_object *) buffer.pointer;
997 /* 1146 /*
998 * Samsung P30 has a device with a valid _HID whose INIT does not 1147 * Try to match the object returned by INIT to the specific model.
999 * return anything. It used to be possible to catch this exception, 1148 * Handle every possible object (or the lack of thereof) the DSDT
1000 * but the implicit return code will now happily confuse the 1149 * writers might throw at us. When in trouble, we pass NULL to
1001 * driver. We assume that every ACPI_TYPE_STRING is a valid model 1150 * asus_model_match() and try something completely different.
1002 * identifier but it's still possible to get completely bogus data.
1003 */ 1151 */
1004 if (model->type == ACPI_TYPE_STRING) { 1152 if (buffer.pointer) {
1005 printk(KERN_NOTICE " %s model detected, ", model->string.pointer); 1153 model = (union acpi_object *)buffer.pointer;
1006 } else { 1154 switch (model->type) {
1007 if (asus_info && /* Samsung P30 */ 1155 case ACPI_TYPE_STRING:
1156 string = model->string.pointer;
1157 break;
1158 case ACPI_TYPE_BUFFER:
1159 string = model->buffer.pointer;
1160 break;
1161 default:
1162 kfree(model);
1163 break;
1164 }
1165 }
1166 hotk->model = asus_model_match(string);
1167 if (hotk->model == END_MODEL) { /* match failed */
1168 if (asus_info &&
1008 strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) { 1169 strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
1009 hotk->model = P30; 1170 hotk->model = P30;
1010 printk(KERN_NOTICE 1171 printk(KERN_NOTICE
1011 " Samsung P30 detected, supported\n"); 1172 " Samsung P30 detected, supported\n");
1012 } else { 1173 } else {
1013 hotk->model = M2E; 1174 hotk->model = M2E;
1014 printk(KERN_WARNING " no string returned by INIT\n"); 1175 printk(KERN_NOTICE " unsupported model %s, trying "
1015 printk(KERN_WARNING " trying default values, supply " 1176 "default values\n", string);
1016 "the developers with your DSDT\n"); 1177 printk(KERN_NOTICE
1178 " send /proc/acpi/dsdt to the developers\n");
1017 } 1179 }
1018 hotk->methods = &model_conf[hotk->model]; 1180 hotk->methods = &model_conf[hotk->model];
1019
1020 acpi_os_free(model);
1021
1022 return AE_OK; 1181 return AE_OK;
1023 } 1182 }
1024
1025 hotk->model = END_MODEL;
1026 if (strncmp(model->string.pointer, "L3D", 3) == 0)
1027 hotk->model = L3D;
1028 else if (strncmp(model->string.pointer, "L3H", 3) == 0 ||
1029 strncmp(model->string.pointer, "L2E", 3) == 0)
1030 hotk->model = L3H;
1031 else if (strncmp(model->string.pointer, "L3", 2) == 0 ||
1032 strncmp(model->string.pointer, "L2B", 3) == 0)
1033 hotk->model = L3C;
1034 else if (strncmp(model->string.pointer, "L8L", 3) == 0)
1035 hotk->model = L8L;
1036 else if (strncmp(model->string.pointer, "L4R", 3) == 0)
1037 hotk->model = L4R;
1038 else if (strncmp(model->string.pointer, "M6N", 3) == 0)
1039 hotk->model = M6N;
1040 else if (strncmp(model->string.pointer, "M6R", 3) == 0)
1041 hotk->model = M6R;
1042 else if (strncmp(model->string.pointer, "M2N", 3) == 0 ||
1043 strncmp(model->string.pointer, "M3N", 3) == 0 ||
1044 strncmp(model->string.pointer, "M5N", 3) == 0 ||
1045 strncmp(model->string.pointer, "M6N", 3) == 0 ||
1046 strncmp(model->string.pointer, "S1N", 3) == 0 ||
1047 strncmp(model->string.pointer, "S5N", 3) == 0 ||
1048 strncmp(model->string.pointer, "W1N", 3) == 0)
1049 hotk->model = xxN;
1050 else if (strncmp(model->string.pointer, "M1", 2) == 0)
1051 hotk->model = M1A;
1052 else if (strncmp(model->string.pointer, "M2", 2) == 0 ||
1053 strncmp(model->string.pointer, "L4E", 3) == 0)
1054 hotk->model = M2E;
1055 else if (strncmp(model->string.pointer, "L2", 2) == 0)
1056 hotk->model = L2D;
1057 else if (strncmp(model->string.pointer, "L8", 2) == 0)
1058 hotk->model = S1x;
1059 else if (strncmp(model->string.pointer, "D1", 2) == 0)
1060 hotk->model = D1x;
1061 else if (strncmp(model->string.pointer, "A1", 2) == 0)
1062 hotk->model = A1x;
1063 else if (strncmp(model->string.pointer, "A2", 2) == 0)
1064 hotk->model = A2x;
1065 else if (strncmp(model->string.pointer, "J1", 2) == 0)
1066 hotk->model = S2x;
1067 else if (strncmp(model->string.pointer, "L5", 2) == 0)
1068 hotk->model = L5x;
1069
1070 if (hotk->model == END_MODEL) {
1071 printk("unsupported, trying default values, supply the "
1072 "developers with your DSDT\n");
1073 hotk->model = M2E;
1074 } else {
1075 printk("supported\n");
1076 }
1077
1078 hotk->methods = &model_conf[hotk->model]; 1183 hotk->methods = &model_conf[hotk->model];
1184 printk(KERN_NOTICE " %s model detected, supported\n", string);
1079 1185
1080 /* Sort of per-model blacklist */ 1186 /* Sort of per-model blacklist */
1081 if (strncmp(model->string.pointer, "L2B", 3) == 0) 1187 if (strncmp(string, "L2B", 3) == 0)
1082 hotk->methods->lcd_status = NULL; 1188 hotk->methods->lcd_status = NULL;
1083 /* L2B is similar enough to L3C to use its settings, with this only 1189 /* L2B is similar enough to L3C to use its settings, with this only
1084 exception */ 1190 exception */
1085 else if (strncmp(model->string.pointer, "S5N", 3) == 0 || 1191 else if (strncmp(string, "A3G", 3) == 0)
1086 strncmp(model->string.pointer, "M5N", 3) == 0) 1192 hotk->methods->lcd_status = "\\BLFG";
1193 /* A3G is like M6R */
1194 else if (strncmp(string, "S5N", 3) == 0 ||
1195 strncmp(string, "M5N", 3) == 0 ||
1196 strncmp(string, "W3N", 3) == 0)
1087 hotk->methods->mt_mled = NULL; 1197 hotk->methods->mt_mled = NULL;
1088 /* S5N and M5N have no MLED */ 1198 /* S5N, M5N and W3N have no MLED */
1089 else if (strncmp(model->string.pointer, "M2N", 3) == 0 || 1199 else if (strncmp(string, "L5D", 3) == 0)
1090 strncmp(model->string.pointer, "W1N", 3) == 0) 1200 hotk->methods->mt_wled = NULL;
1201 /* L5D's WLED is not controlled by ACPI */
1202 else if (strncmp(string, "M2N", 3) == 0 ||
1203 strncmp(string, "S1N", 3) == 0)
1091 hotk->methods->mt_wled = "WLED"; 1204 hotk->methods->mt_wled = "WLED";
1092 /* M2N and W1N have a usable WLED */ 1205 /* M2N and S1N have a usable WLED */
1093 else if (asus_info) { 1206 else if (asus_info) {
1094 if (strncmp(asus_info->oem_table_id, "L1", 2) == 0) 1207 if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
1095 hotk->methods->mled_status = NULL; 1208 hotk->methods->mled_status = NULL;
1096 /* S1300A reports L84F, but L1400B too, account for that */ 1209 /* S1300A reports L84F, but L1400B too, account for that */
1097 } 1210 }
1098 1211
1099 acpi_os_free(model); 1212 kfree(model);
1100 1213
1101 return AE_OK; 1214 return AE_OK;
1102} 1215}
@@ -1164,8 +1277,7 @@ static int asus_hotk_add(struct acpi_device *device)
1164 /* For laptops without GPLV: init the hotk->brightness value */ 1277 /* For laptops without GPLV: init the hotk->brightness value */
1165 if ((!hotk->methods->brightness_get) 1278 if ((!hotk->methods->brightness_get)
1166 && (!hotk->methods->brightness_status) 1279 && (!hotk->methods->brightness_status)
1167 && (hotk->methods->brightness_up 1280 && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
1168 && hotk->methods->brightness_down)) {
1169 status = 1281 status =
1170 acpi_evaluate_object(NULL, hotk->methods->brightness_down, 1282 acpi_evaluate_object(NULL, hotk->methods->brightness_down,
1171 NULL, NULL); 1283 NULL, NULL);
@@ -1184,6 +1296,9 @@ static int asus_hotk_add(struct acpi_device *device)
1184 1296
1185 asus_hotk_found = 1; 1297 asus_hotk_found = 1;
1186 1298
1299 /* LED display is off by default */
1300 hotk->ledd_status = 0xFFF;
1301
1187 end: 1302 end:
1188 if (result) { 1303 if (result) {
1189 kfree(hotk); 1304 kfree(hotk);
@@ -1256,7 +1371,7 @@ static void __exit asus_acpi_exit(void)
1256 acpi_bus_unregister_driver(&asus_hotk_driver); 1371 acpi_bus_unregister_driver(&asus_hotk_driver);
1257 remove_proc_entry(PROC_ASUS, acpi_root_dir); 1372 remove_proc_entry(PROC_ASUS, acpi_root_dir);
1258 1373
1259 acpi_os_free(asus_info); 1374 kfree(asus_info);
1260 1375
1261 return; 1376 return;
1262} 1377}