aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/asus-laptop.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform/x86/asus-laptop.c')
-rw-r--r--drivers/platform/x86/asus-laptop.c463
1 files changed, 204 insertions, 259 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b756e07d41b4..d65df92e2acc 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -29,7 +29,7 @@
29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point. 29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
30 * Eric Burghard - LED display support for W1N 30 * Eric Burghard - LED display support for W1N
31 * Josh Green - Light Sens support 31 * Josh Green - Light Sens support
32 * Thomas Tuttle - His first patch for led support was very helpfull 32 * Thomas Tuttle - His first patch for led support was very helpful
33 * Sam Lin - GPS support 33 * Sam Lin - GPS support
34 */ 34 */
35 35
@@ -50,6 +50,7 @@
50#include <linux/input/sparse-keymap.h> 50#include <linux/input/sparse-keymap.h>
51#include <linux/rfkill.h> 51#include <linux/rfkill.h>
52#include <linux/slab.h> 52#include <linux/slab.h>
53#include <linux/dmi.h>
53#include <acpi/acpi_drivers.h> 54#include <acpi/acpi_drivers.h>
54#include <acpi/acpi_bus.h> 55#include <acpi/acpi_bus.h>
55 56
@@ -81,6 +82,8 @@ MODULE_PARM_DESC(wapf, "WAPF value");
81 82
82static int wlan_status = 1; 83static int wlan_status = 1;
83static int bluetooth_status = 1; 84static int bluetooth_status = 1;
85static int wimax_status = -1;
86static int wwan_status = -1;
84 87
85module_param(wlan_status, int, 0444); 88module_param(wlan_status, int, 0444);
86MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot " 89MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
@@ -92,6 +95,16 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
92 "(0 = disabled, 1 = enabled, -1 = don't do anything). " 95 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
93 "default is 1"); 96 "default is 1");
94 97
98module_param(wimax_status, int, 0444);
99MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
100 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
101 "default is 1");
102
103module_param(wwan_status, int, 0444);
104MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
105 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
106 "default is 1");
107
95/* 108/*
96 * Some events we use, same for all Asus 109 * Some events we use, same for all Asus
97 */ 110 */
@@ -114,6 +127,8 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
114 */ 127 */
115#define WL_RSTS 0x01 /* internal Wifi */ 128#define WL_RSTS 0x01 /* internal Wifi */
116#define BT_RSTS 0x02 /* internal Bluetooth */ 129#define BT_RSTS 0x02 /* internal Bluetooth */
130#define WM_RSTS 0x08 /* internal wimax */
131#define WW_RSTS 0x20 /* internal wwan */
117 132
118/* LED */ 133/* LED */
119#define METHOD_MLED "MLED" 134#define METHOD_MLED "MLED"
@@ -132,52 +147,20 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
132 */ 147 */
133#define METHOD_WLAN "WLED" 148#define METHOD_WLAN "WLED"
134#define METHOD_BLUETOOTH "BLED" 149#define METHOD_BLUETOOTH "BLED"
150
151/* WWAN and WIMAX */
152#define METHOD_WWAN "GSMC"
153#define METHOD_WIMAX "WMXC"
154
135#define METHOD_WL_STATUS "RSTS" 155#define METHOD_WL_STATUS "RSTS"
136 156
137/* Brightness */ 157/* Brightness */
138#define METHOD_BRIGHTNESS_SET "SPLV" 158#define METHOD_BRIGHTNESS_SET "SPLV"
139#define METHOD_BRIGHTNESS_GET "GPLV" 159#define METHOD_BRIGHTNESS_GET "GPLV"
140 160
141/* Backlight */
142static acpi_handle lcd_switch_handle;
143static char *lcd_switch_paths[] = {
144 "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
145 "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
146 "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
147 "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
148 "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
149 "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
150 "\\_SB.PCI0.PX40.Q10", /* S1x */
151 "\\Q10"}; /* A2x, L2D, L3D, M2E */
152
153/* Display */ 161/* Display */
154#define METHOD_SWITCH_DISPLAY "SDSP" 162#define METHOD_SWITCH_DISPLAY "SDSP"
155 163
156static acpi_handle display_get_handle;
157static char *display_get_paths[] = {
158 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
159 "\\_SB.PCI0.P0P1.VGA.GETD",
160 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
161 "\\_SB.PCI0.P0P2.VGA.GETD",
162 /* A6V A6Q */
163 "\\_SB.PCI0.P0P3.VGA.GETD",
164 /* A6T, A6M */
165 "\\_SB.PCI0.P0PA.VGA.GETD",
166 /* L3C */
167 "\\_SB.PCI0.PCI1.VGAC.NMAP",
168 /* Z96F */
169 "\\_SB.PCI0.VGA.GETD",
170 /* A2D */
171 "\\ACTD",
172 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
173 "\\ADVG",
174 /* P30 */
175 "\\DNXT",
176 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
177 "\\INFB",
178 /* A3F A6F A3N A3L M6N W3N W6A */
179 "\\SSTE"};
180
181#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ 164#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
182#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ 165#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
183 166
@@ -227,7 +210,6 @@ struct asus_laptop {
227 210
228 int wireless_status; 211 int wireless_status;
229 bool have_rsts; 212 bool have_rsts;
230 int lcd_state;
231 213
232 struct rfkill *gps_rfkill; 214 struct rfkill *gps_rfkill;
233 215
@@ -236,7 +218,6 @@ struct asus_laptop {
236 u8 light_level; /* light sensor level */ 218 u8 light_level; /* light sensor level */
237 u8 light_switch; /* light sensor switch value */ 219 u8 light_switch; /* light sensor switch value */
238 u16 event_count[128]; /* count for each event TODO make this better */ 220 u16 event_count[128]; /* count for each event TODO make this better */
239 u16 *keycode_map;
240}; 221};
241 222
242static const struct key_entry asus_keymap[] = { 223static const struct key_entry asus_keymap[] = {
@@ -278,6 +259,7 @@ static const struct key_entry asus_keymap[] = {
278 {KE_KEY, 0x99, { KEY_PHONE } }, 259 {KE_KEY, 0x99, { KEY_PHONE } },
279 {KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, 260 {KE_KEY, 0xc4, { KEY_KBDILLUMUP } },
280 {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, 261 {KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } },
262 {KE_KEY, 0xb5, { KEY_CALC } },
281 {KE_END, 0}, 263 {KE_END, 0},
282}; 264};
283 265
@@ -336,7 +318,7 @@ static int acpi_check_handle(acpi_handle handle, const char *method,
336 318
337 if (status != AE_OK) { 319 if (status != AE_OK) {
338 if (ret) 320 if (ret)
339 pr_warning("Error finding %s\n", method); 321 pr_warn("Error finding %s\n", method);
340 return -ENODEV; 322 return -ENODEV;
341 } 323 }
342 return 0; 324 return 0;
@@ -401,7 +383,7 @@ static int asus_kled_lvl(struct asus_laptop *asus)
401 rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET, 383 rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET,
402 &params, &kblv); 384 &params, &kblv);
403 if (ACPI_FAILURE(rv)) { 385 if (ACPI_FAILURE(rv)) {
404 pr_warning("Error reading kled level\n"); 386 pr_warn("Error reading kled level\n");
405 return -ENODEV; 387 return -ENODEV;
406 } 388 }
407 return kblv; 389 return kblv;
@@ -415,7 +397,7 @@ static int asus_kled_set(struct asus_laptop *asus, int kblv)
415 kblv = 0; 397 kblv = 0;
416 398
417 if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) { 399 if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) {
418 pr_warning("Keyboard LED display write failed\n"); 400 pr_warn("Keyboard LED display write failed\n");
419 return -EINVAL; 401 return -EINVAL;
420 } 402 }
421 return 0; 403 return 0;
@@ -540,48 +522,6 @@ error:
540/* 522/*
541 * Backlight device 523 * Backlight device
542 */ 524 */
543static int asus_lcd_status(struct asus_laptop *asus)
544{
545 return asus->lcd_state;
546}
547
548static int asus_lcd_set(struct asus_laptop *asus, int value)
549{
550 int lcd = 0;
551 acpi_status status = 0;
552
553 lcd = !!value;
554
555 if (lcd == asus_lcd_status(asus))
556 return 0;
557
558 if (!lcd_switch_handle)
559 return -ENODEV;
560
561 status = acpi_evaluate_object(lcd_switch_handle,
562 NULL, NULL, NULL);
563
564 if (ACPI_FAILURE(status)) {
565 pr_warning("Error switching LCD\n");
566 return -ENODEV;
567 }
568
569 asus->lcd_state = lcd;
570 return 0;
571}
572
573static void lcd_blank(struct asus_laptop *asus, int blank)
574{
575 struct backlight_device *bd = asus->backlight_device;
576
577 asus->lcd_state = (blank == FB_BLANK_UNBLANK);
578
579 if (bd) {
580 bd->props.power = blank;
581 backlight_update_status(bd);
582 }
583}
584
585static int asus_read_brightness(struct backlight_device *bd) 525static int asus_read_brightness(struct backlight_device *bd)
586{ 526{
587 struct asus_laptop *asus = bl_get_data(bd); 527 struct asus_laptop *asus = bl_get_data(bd);
@@ -591,7 +531,7 @@ static int asus_read_brightness(struct backlight_device *bd)
591 rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET, 531 rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET,
592 NULL, &value); 532 NULL, &value);
593 if (ACPI_FAILURE(rv)) 533 if (ACPI_FAILURE(rv))
594 pr_warning("Error reading brightness\n"); 534 pr_warn("Error reading brightness\n");
595 535
596 return value; 536 return value;
597} 537}
@@ -601,7 +541,7 @@ static int asus_set_brightness(struct backlight_device *bd, int value)
601 struct asus_laptop *asus = bl_get_data(bd); 541 struct asus_laptop *asus = bl_get_data(bd);
602 542
603 if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) { 543 if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) {
604 pr_warning("Error changing brightness\n"); 544 pr_warn("Error changing brightness\n");
605 return -EIO; 545 return -EIO;
606 } 546 }
607 return 0; 547 return 0;
@@ -609,19 +549,12 @@ static int asus_set_brightness(struct backlight_device *bd, int value)
609 549
610static int update_bl_status(struct backlight_device *bd) 550static int update_bl_status(struct backlight_device *bd)
611{ 551{
612 struct asus_laptop *asus = bl_get_data(bd);
613 int rv;
614 int value = bd->props.brightness; 552 int value = bd->props.brightness;
615 553
616 rv = asus_set_brightness(bd, value); 554 return asus_set_brightness(bd, value);
617 if (rv)
618 return rv;
619
620 value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
621 return asus_lcd_set(asus, value);
622} 555}
623 556
624static struct backlight_ops asusbl_ops = { 557static const struct backlight_ops asusbl_ops = {
625 .get_brightness = asus_read_brightness, 558 .get_brightness = asus_read_brightness,
626 .update_status = update_bl_status, 559 .update_status = update_bl_status,
627}; 560};
@@ -639,29 +572,29 @@ static int asus_backlight_notify(struct asus_laptop *asus)
639static int asus_backlight_init(struct asus_laptop *asus) 572static int asus_backlight_init(struct asus_laptop *asus)
640{ 573{
641 struct backlight_device *bd; 574 struct backlight_device *bd;
642 struct device *dev = &asus->platform_device->dev;
643 struct backlight_properties props; 575 struct backlight_properties props;
644 576
645 if (!acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) && 577 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
646 !acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) && 578 acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL))
647 lcd_switch_handle) { 579 return 0;
648 memset(&props, 0, sizeof(struct backlight_properties));
649 props.max_brightness = 15;
650
651 bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
652 asus, &asusbl_ops, &props);
653 if (IS_ERR(bd)) {
654 pr_err("Could not register asus backlight device\n");
655 asus->backlight_device = NULL;
656 return PTR_ERR(bd);
657 }
658
659 asus->backlight_device = bd;
660 580
661 bd->props.power = FB_BLANK_UNBLANK; 581 memset(&props, 0, sizeof(struct backlight_properties));
662 bd->props.brightness = asus_read_brightness(bd); 582 props.max_brightness = 15;
663 backlight_update_status(bd); 583 props.type = BACKLIGHT_PLATFORM;
584
585 bd = backlight_device_register(ASUS_LAPTOP_FILE,
586 &asus->platform_device->dev, asus,
587 &asusbl_ops, &props);
588 if (IS_ERR(bd)) {
589 pr_err("Could not register asus backlight device\n");
590 asus->backlight_device = NULL;
591 return PTR_ERR(bd);
664 } 592 }
593
594 asus->backlight_device = bd;
595 bd->props.brightness = asus_read_brightness(bd);
596 bd->props.power = FB_BLANK_UNBLANK;
597 backlight_update_status(bd);
665 return 0; 598 return 0;
666} 599}
667 600
@@ -797,7 +730,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
797 rv = parse_arg(buf, count, &value); 730 rv = parse_arg(buf, count, &value);
798 if (rv > 0) { 731 if (rv > 0) {
799 if (write_acpi_int(asus->handle, METHOD_LEDD, value)) { 732 if (write_acpi_int(asus->handle, METHOD_LEDD, value)) {
800 pr_warning("LED display write failed\n"); 733 pr_warn("LED display write failed\n");
801 return -ENODEV; 734 return -ENODEV;
802 } 735 }
803 asus->ledd_status = (u32) value; 736 asus->ledd_status = (u32) value;
@@ -819,7 +752,7 @@ static int asus_wireless_status(struct asus_laptop *asus, int mask)
819 rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS, 752 rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS,
820 NULL, &status); 753 NULL, &status);
821 if (ACPI_FAILURE(rv)) { 754 if (ACPI_FAILURE(rv)) {
822 pr_warning("Error reading Wireless status\n"); 755 pr_warn("Error reading Wireless status\n");
823 return -EINVAL; 756 return -EINVAL;
824 } 757 }
825 return !!(status & mask); 758 return !!(status & mask);
@@ -831,7 +764,7 @@ static int asus_wireless_status(struct asus_laptop *asus, int mask)
831static int asus_wlan_set(struct asus_laptop *asus, int status) 764static int asus_wlan_set(struct asus_laptop *asus, int status)
832{ 765{
833 if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) { 766 if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) {
834 pr_warning("Error setting wlan status to %d", status); 767 pr_warn("Error setting wlan status to %d\n", status);
835 return -EIO; 768 return -EIO;
836 } 769 }
837 return 0; 770 return 0;
@@ -859,7 +792,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
859static int asus_bluetooth_set(struct asus_laptop *asus, int status) 792static int asus_bluetooth_set(struct asus_laptop *asus, int status)
860{ 793{
861 if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) { 794 if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) {
862 pr_warning("Error setting bluetooth status to %d", status); 795 pr_warn("Error setting bluetooth status to %d\n", status);
863 return -EIO; 796 return -EIO;
864 } 797 }
865 return 0; 798 return 0;
@@ -883,49 +816,72 @@ static ssize_t store_bluetooth(struct device *dev,
883} 816}
884 817
885/* 818/*
886 * Display 819 * Wimax
887 */ 820 */
888static void asus_set_display(struct asus_laptop *asus, int value) 821static int asus_wimax_set(struct asus_laptop *asus, int status)
889{ 822{
890 /* no sanity check needed for now */ 823 if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) {
891 if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value)) 824 pr_warn("Error setting wimax status to %d\n", status);
892 pr_warning("Error setting display\n"); 825 return -EIO;
893 return; 826 }
827 return 0;
894} 828}
895 829
896static int read_display(struct asus_laptop *asus) 830static ssize_t show_wimax(struct device *dev,
831 struct device_attribute *attr, char *buf)
897{ 832{
898 unsigned long long value = 0; 833 struct asus_laptop *asus = dev_get_drvdata(dev);
899 acpi_status rv = AE_OK;
900 834
901 /* 835 return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS));
902 * In most of the case, we know how to set the display, but sometime 836}
903 * we can't read it
904 */
905 if (display_get_handle) {
906 rv = acpi_evaluate_integer(display_get_handle, NULL,
907 NULL, &value);
908 if (ACPI_FAILURE(rv))
909 pr_warning("Error reading display status\n");
910 }
911 837
912 value &= 0x0F; /* needed for some models, shouldn't hurt others */ 838static ssize_t store_wimax(struct device *dev,
839 struct device_attribute *attr, const char *buf,
840 size_t count)
841{
842 struct asus_laptop *asus = dev_get_drvdata(dev);
913 843
914 return value; 844 return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX);
915} 845}
916 846
917/* 847/*
918 * Now, *this* one could be more user-friendly, but so far, no-one has 848 * Wwan
919 * complained. The significance of bits is the same as in store_disp()
920 */ 849 */
921static ssize_t show_disp(struct device *dev, 850static int asus_wwan_set(struct asus_laptop *asus, int status)
922 struct device_attribute *attr, char *buf) 851{
852 if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) {
853 pr_warn("Error setting wwan status to %d\n", status);
854 return -EIO;
855 }
856 return 0;
857}
858
859static ssize_t show_wwan(struct device *dev,
860 struct device_attribute *attr, char *buf)
923{ 861{
924 struct asus_laptop *asus = dev_get_drvdata(dev); 862 struct asus_laptop *asus = dev_get_drvdata(dev);
925 863
926 if (!display_get_handle) 864 return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS));
927 return -ENODEV; 865}
928 return sprintf(buf, "%d\n", read_display(asus)); 866
867static ssize_t store_wwan(struct device *dev,
868 struct device_attribute *attr, const char *buf,
869 size_t count)
870{
871 struct asus_laptop *asus = dev_get_drvdata(dev);
872
873 return sysfs_acpi_set(asus, buf, count, METHOD_WWAN);
874}
875
876/*
877 * Display
878 */
879static void asus_set_display(struct asus_laptop *asus, int value)
880{
881 /* no sanity check needed for now */
882 if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value))
883 pr_warn("Error setting display\n");
884 return;
929} 885}
930 886
931/* 887/*
@@ -953,7 +909,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
953static void asus_als_switch(struct asus_laptop *asus, int value) 909static void asus_als_switch(struct asus_laptop *asus, int value)
954{ 910{
955 if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value)) 911 if (write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value))
956 pr_warning("Error setting light sensor switch\n"); 912 pr_warn("Error setting light sensor switch\n");
957 asus->light_switch = value; 913 asus->light_switch = value;
958} 914}
959 915
@@ -981,7 +937,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
981static void asus_als_level(struct asus_laptop *asus, int value) 937static void asus_als_level(struct asus_laptop *asus, int value)
982{ 938{
983 if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value)) 939 if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value))
984 pr_warning("Error setting light sensor level\n"); 940 pr_warn("Error setting light sensor level\n");
985 asus->light_level = value; 941 asus->light_level = value;
986} 942}
987 943
@@ -1020,7 +976,7 @@ static int asus_gps_status(struct asus_laptop *asus)
1020 rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS, 976 rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS,
1021 NULL, &status); 977 NULL, &status);
1022 if (ACPI_FAILURE(rv)) { 978 if (ACPI_FAILURE(rv)) {
1023 pr_warning("Error reading GPS status\n"); 979 pr_warn("Error reading GPS status\n");
1024 return -ENODEV; 980 return -ENODEV;
1025 } 981 }
1026 return !!status; 982 return !!status;
@@ -1065,9 +1021,9 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
1065 */ 1021 */
1066static int asus_gps_rfkill_set(void *data, bool blocked) 1022static int asus_gps_rfkill_set(void *data, bool blocked)
1067{ 1023{
1068 acpi_handle handle = data; 1024 struct asus_laptop *asus = data;
1069 1025
1070 return asus_gps_switch(handle, !blocked); 1026 return asus_gps_switch(asus, !blocked);
1071} 1027}
1072 1028
1073static const struct rfkill_ops asus_gps_rfkill_ops = { 1029static const struct rfkill_ops asus_gps_rfkill_ops = {
@@ -1094,7 +1050,7 @@ static int asus_rfkill_init(struct asus_laptop *asus)
1094 1050
1095 asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev, 1051 asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
1096 RFKILL_TYPE_GPS, 1052 RFKILL_TYPE_GPS,
1097 &asus_gps_rfkill_ops, NULL); 1053 &asus_gps_rfkill_ops, asus);
1098 if (!asus->gps_rfkill) 1054 if (!asus->gps_rfkill)
1099 return -EINVAL; 1055 return -EINVAL;
1100 1056
@@ -1130,7 +1086,6 @@ static int asus_input_init(struct asus_laptop *asus)
1130 input->phys = ASUS_LAPTOP_FILE "/input0"; 1086 input->phys = ASUS_LAPTOP_FILE "/input0";
1131 input->id.bustype = BUS_HOST; 1087 input->id.bustype = BUS_HOST;
1132 input->dev.parent = &asus->platform_device->dev; 1088 input->dev.parent = &asus->platform_device->dev;
1133 input_set_drvdata(input, asus);
1134 1089
1135 error = sparse_keymap_setup(input, asus_keymap, NULL); 1090 error = sparse_keymap_setup(input, asus_keymap, NULL);
1136 if (error) { 1091 if (error) {
@@ -1159,6 +1114,7 @@ static void asus_input_exit(struct asus_laptop *asus)
1159 sparse_keymap_free(asus->inputdev); 1114 sparse_keymap_free(asus->inputdev);
1160 input_unregister_device(asus->inputdev); 1115 input_unregister_device(asus->inputdev);
1161 } 1116 }
1117 asus->inputdev = NULL;
1162} 1118}
1163 1119
1164/* 1120/*
@@ -1169,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
1169 struct asus_laptop *asus = acpi_driver_data(device); 1125 struct asus_laptop *asus = acpi_driver_data(device);
1170 u16 count; 1126 u16 count;
1171 1127
1172 /*
1173 * We need to tell the backlight device when the backlight power is
1174 * switched
1175 */
1176 if (event == ATKD_LCD_ON)
1177 lcd_blank(asus, FB_BLANK_UNBLANK);
1178 else if (event == ATKD_LCD_OFF)
1179 lcd_blank(asus, FB_BLANK_POWERDOWN);
1180
1181 /* TODO Find a better way to handle events count. */ 1128 /* TODO Find a better way to handle events count. */
1182 count = asus->event_count[event % 128]++; 1129 count = asus->event_count[event % 128]++;
1183 acpi_bus_generate_proc_event(asus->device, event, count); 1130 acpi_bus_generate_proc_event(asus->device, event, count);
@@ -1200,111 +1147,111 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
1200 1147
1201static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL); 1148static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
1202static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan); 1149static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
1203static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR, show_bluetooth, 1150static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
1204 store_bluetooth); 1151 show_bluetooth, store_bluetooth);
1205static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); 1152static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
1153static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
1154static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
1206static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); 1155static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
1207static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); 1156static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
1208static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); 1157static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
1209static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps); 1158static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
1210 1159
1211static void asus_sysfs_exit(struct asus_laptop *asus) 1160static struct attribute *asus_attributes[] = {
1212{ 1161 &dev_attr_infos.attr,
1213 struct platform_device *device = asus->platform_device; 1162 &dev_attr_wlan.attr,
1214 1163 &dev_attr_bluetooth.attr,
1215 device_remove_file(&device->dev, &dev_attr_infos); 1164 &dev_attr_wimax.attr,
1216 device_remove_file(&device->dev, &dev_attr_wlan); 1165 &dev_attr_wwan.attr,
1217 device_remove_file(&device->dev, &dev_attr_bluetooth); 1166 &dev_attr_display.attr,
1218 device_remove_file(&device->dev, &dev_attr_display); 1167 &dev_attr_ledd.attr,
1219 device_remove_file(&device->dev, &dev_attr_ledd); 1168 &dev_attr_ls_level.attr,
1220 device_remove_file(&device->dev, &dev_attr_ls_switch); 1169 &dev_attr_ls_switch.attr,
1221 device_remove_file(&device->dev, &dev_attr_ls_level); 1170 &dev_attr_gps.attr,
1222 device_remove_file(&device->dev, &dev_attr_gps); 1171 NULL
1223} 1172};
1224 1173
1225static int asus_sysfs_init(struct asus_laptop *asus) 1174static mode_t asus_sysfs_is_visible(struct kobject *kobj,
1175 struct attribute *attr,
1176 int idx)
1226{ 1177{
1227 struct platform_device *device = asus->platform_device; 1178 struct device *dev = container_of(kobj, struct device, kobj);
1228 int err; 1179 struct platform_device *pdev = to_platform_device(dev);
1180 struct asus_laptop *asus = platform_get_drvdata(pdev);
1181 acpi_handle handle = asus->handle;
1182 bool supported;
1229 1183
1230 err = device_create_file(&device->dev, &dev_attr_infos); 1184 if (attr == &dev_attr_wlan.attr) {
1231 if (err) 1185 supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
1232 return err;
1233 1186
1234 if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL)) { 1187 } else if (attr == &dev_attr_bluetooth.attr) {
1235 err = device_create_file(&device->dev, &dev_attr_wlan); 1188 supported = !acpi_check_handle(handle, METHOD_BLUETOOTH, NULL);
1236 if (err)
1237 return err;
1238 }
1239 1189
1240 if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL)) { 1190 } else if (attr == &dev_attr_display.attr) {
1241 err = device_create_file(&device->dev, &dev_attr_bluetooth); 1191 supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
1242 if (err)
1243 return err;
1244 }
1245 1192
1246 if (!acpi_check_handle(asus->handle, METHOD_SWITCH_DISPLAY, NULL)) { 1193 } else if (attr == &dev_attr_wimax.attr) {
1247 err = device_create_file(&device->dev, &dev_attr_display); 1194 supported =
1248 if (err) 1195 !acpi_check_handle(asus->handle, METHOD_WIMAX, NULL);
1249 return err;
1250 }
1251 1196
1252 if (!acpi_check_handle(asus->handle, METHOD_LEDD, NULL)) { 1197 } else if (attr == &dev_attr_wwan.attr) {
1253 err = device_create_file(&device->dev, &dev_attr_ledd); 1198 supported = !acpi_check_handle(asus->handle, METHOD_WWAN, NULL);
1254 if (err)
1255 return err;
1256 }
1257 1199
1258 if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) && 1200 } else if (attr == &dev_attr_ledd.attr) {
1259 !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) { 1201 supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
1260 err = device_create_file(&device->dev, &dev_attr_ls_switch); 1202
1261 if (err) 1203 } else if (attr == &dev_attr_ls_switch.attr ||
1262 return err; 1204 attr == &dev_attr_ls_level.attr) {
1263 err = device_create_file(&device->dev, &dev_attr_ls_level); 1205 supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
1264 if (err) 1206 !acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
1265 return err;
1266 }
1267 1207
1268 if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) && 1208 } else if (attr == &dev_attr_gps.attr) {
1269 !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) && 1209 supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
1270 !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) { 1210 !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
1271 err = device_create_file(&device->dev, &dev_attr_gps); 1211 !acpi_check_handle(handle, METHOD_GPS_STATUS, NULL);
1272 if (err) 1212 } else {
1273 return err; 1213 supported = true;
1274 } 1214 }
1275 1215
1276 return err; 1216 return supported ? attr->mode : 0;
1277} 1217}
1278 1218
1219
1220static const struct attribute_group asus_attr_group = {
1221 .is_visible = asus_sysfs_is_visible,
1222 .attrs = asus_attributes,
1223};
1224
1279static int asus_platform_init(struct asus_laptop *asus) 1225static int asus_platform_init(struct asus_laptop *asus)
1280{ 1226{
1281 int err; 1227 int result;
1282 1228
1283 asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1); 1229 asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
1284 if (!asus->platform_device) 1230 if (!asus->platform_device)
1285 return -ENOMEM; 1231 return -ENOMEM;
1286 platform_set_drvdata(asus->platform_device, asus); 1232 platform_set_drvdata(asus->platform_device, asus);
1287 1233
1288 err = platform_device_add(asus->platform_device); 1234 result = platform_device_add(asus->platform_device);
1289 if (err) 1235 if (result)
1290 goto fail_platform_device; 1236 goto fail_platform_device;
1291 1237
1292 err = asus_sysfs_init(asus); 1238 result = sysfs_create_group(&asus->platform_device->dev.kobj,
1293 if (err) 1239 &asus_attr_group);
1240 if (result)
1294 goto fail_sysfs; 1241 goto fail_sysfs;
1242
1295 return 0; 1243 return 0;
1296 1244
1297fail_sysfs: 1245fail_sysfs:
1298 asus_sysfs_exit(asus);
1299 platform_device_del(asus->platform_device); 1246 platform_device_del(asus->platform_device);
1300fail_platform_device: 1247fail_platform_device:
1301 platform_device_put(asus->platform_device); 1248 platform_device_put(asus->platform_device);
1302 return err; 1249 return result;
1303} 1250}
1304 1251
1305static void asus_platform_exit(struct asus_laptop *asus) 1252static void asus_platform_exit(struct asus_laptop *asus)
1306{ 1253{
1307 asus_sysfs_exit(asus); 1254 sysfs_remove_group(&asus->platform_device->dev.kobj, &asus_attr_group);
1308 platform_device_unregister(asus->platform_device); 1255 platform_device_unregister(asus->platform_device);
1309} 1256}
1310 1257
@@ -1315,26 +1262,6 @@ static struct platform_driver platform_driver = {
1315 } 1262 }
1316}; 1263};
1317 1264
1318static int asus_handle_init(char *name, acpi_handle * handle,
1319 char **paths, int num_paths)
1320{
1321 int i;
1322 acpi_status status;
1323
1324 for (i = 0; i < num_paths; i++) {
1325 status = acpi_get_handle(NULL, paths[i], handle);
1326 if (ACPI_SUCCESS(status))
1327 return 0;
1328 }
1329
1330 *handle = NULL;
1331 return -ENODEV;
1332}
1333
1334#define ASUS_HANDLE_INIT(object) \
1335 asus_handle_init(#object, &object##_handle, object##_paths, \
1336 ARRAY_SIZE(object##_paths))
1337
1338/* 1265/*
1339 * This function is used to initialize the context with right values. In this 1266 * This function is used to initialize the context with right values. In this
1340 * method, we can make all the detection we want, and modify the asus_laptop 1267 * method, we can make all the detection we want, and modify the asus_laptop
@@ -1357,7 +1284,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
1357 */ 1284 */
1358 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info); 1285 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info);
1359 if (ACPI_FAILURE(status)) 1286 if (ACPI_FAILURE(status))
1360 pr_warning("Couldn't get the DSDT table header\n"); 1287 pr_warn("Couldn't get the DSDT table header\n");
1361 1288
1362 /* We have to write 0 on init this far for all ASUS models */ 1289 /* We have to write 0 on init this far for all ASUS models */
1363 if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) { 1290 if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) {
@@ -1369,7 +1296,7 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
1369 status = 1296 status =
1370 acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result); 1297 acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result);
1371 if (ACPI_FAILURE(status)) 1298 if (ACPI_FAILURE(status))
1372 pr_warning("Error calling BSTS\n"); 1299 pr_warn("Error calling BSTS\n");
1373 else if (bsts_result) 1300 else if (bsts_result)
1374 pr_notice("BSTS called, 0x%02x returned\n", 1301 pr_notice("BSTS called, 0x%02x returned\n",
1375 (uint) bsts_result); 1302 (uint) bsts_result);
@@ -1408,7 +1335,8 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
1408 1335
1409 /* 1336 /*
1410 * The HWRS method return informations about the hardware. 1337 * The HWRS method return informations about the hardware.
1411 * 0x80 bit is for WLAN, 0x100 for Bluetooth. 1338 * 0x80 bit is for WLAN, 0x100 for Bluetooth,
1339 * 0x40 for WWAN, 0x10 for WIMAX.
1412 * The significance of others is yet to be found. 1340 * The significance of others is yet to be found.
1413 */ 1341 */
1414 status = 1342 status =
@@ -1419,17 +1347,11 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
1419 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) 1347 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
1420 asus->have_rsts = true; 1348 asus->have_rsts = true;
1421 1349
1422 /* Scheduled for removal */
1423 ASUS_HANDLE_INIT(lcd_switch);
1424 ASUS_HANDLE_INIT(display_get);
1425
1426 kfree(model); 1350 kfree(model);
1427 1351
1428 return AE_OK; 1352 return AE_OK;
1429} 1353}
1430 1354
1431static bool asus_device_present;
1432
1433static int __devinit asus_acpi_init(struct asus_laptop *asus) 1355static int __devinit asus_acpi_init(struct asus_laptop *asus)
1434{ 1356{
1435 int result = 0; 1357 int result = 0;
@@ -1453,6 +1375,12 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1453 if (wlan_status >= 0) 1375 if (wlan_status >= 0)
1454 asus_wlan_set(asus, !!wlan_status); 1376 asus_wlan_set(asus, !!wlan_status);
1455 1377
1378 if (wimax_status >= 0)
1379 asus_wimax_set(asus, !!wimax_status);
1380
1381 if (wwan_status >= 0)
1382 asus_wwan_set(asus, !!wwan_status);
1383
1456 /* Keyboard Backlight is on by default */ 1384 /* Keyboard Backlight is on by default */
1457 if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL)) 1385 if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL))
1458 asus_kled_set(asus, 1); 1386 asus_kled_set(asus, 1);
@@ -1470,10 +1398,25 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1470 asus_als_level(asus, asus->light_level); 1398 asus_als_level(asus, asus->light_level);
1471 } 1399 }
1472 1400
1473 asus->lcd_state = 1; /* LCD should be on when the module load */
1474 return result; 1401 return result;
1475} 1402}
1476 1403
1404static void __devinit asus_dmi_check(void)
1405{
1406 const char *model;
1407
1408 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1409 if (!model)
1410 return;
1411
1412 /* On L1400B WLED control the sound card, don't mess with it ... */
1413 if (strncmp(model, "L1400B", 6) == 0) {
1414 wlan_status = -1;
1415 }
1416}
1417
1418static bool asus_device_present;
1419
1477static int __devinit asus_acpi_add(struct acpi_device *device) 1420static int __devinit asus_acpi_add(struct acpi_device *device)
1478{ 1421{
1479 struct asus_laptop *asus; 1422 struct asus_laptop *asus;
@@ -1490,6 +1433,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
1490 device->driver_data = asus; 1433 device->driver_data = asus;
1491 asus->device = device; 1434 asus->device = device;
1492 1435
1436 asus_dmi_check();
1437
1493 result = asus_acpi_init(asus); 1438 result = asus_acpi_init(asus);
1494 if (result) 1439 if (result)
1495 goto fail_platform; 1440 goto fail_platform;