diff options
Diffstat (limited to 'drivers/acpi/asus_acpi.c')
| -rw-r--r-- | drivers/acpi/asus_acpi.c | 335 |
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 | ||
| 74 | MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); | 74 | MODULE_AUTHOR("Julien Lerouge, Karol Kozimor"); |
| 75 | MODULE_DESCRIPTION(ACPI_HOTK_NAME); | 75 | MODULE_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 | ||
| 150 | static struct model_data model_conf[END_MODEL] = { | 157 | static 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 | */ | ||
| 599 | static int | ||
| 600 | proc_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 | |||
| 606 | static int | ||
| 607 | proc_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 | */ |
| 568 | static int | 629 | static 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 | */ | ||
| 647 | static int | ||
| 648 | proc_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 | |||
| 654 | static int | ||
| 655 | proc_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 | */ |
| 586 | static int | 666 | static 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 | */ | ||
| 1051 | static 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 | } |
