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.c182
1 files changed, 21 insertions, 161 deletions
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 5a6f7d7575d6..c53b3ff7978a 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
@@ -157,46 +158,9 @@ MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
157#define METHOD_BRIGHTNESS_SET "SPLV" 158#define METHOD_BRIGHTNESS_SET "SPLV"
158#define METHOD_BRIGHTNESS_GET "GPLV" 159#define METHOD_BRIGHTNESS_GET "GPLV"
159 160
160/* Backlight */
161static acpi_handle lcd_switch_handle;
162static char *lcd_switch_paths[] = {
163 "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */
164 "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */
165 "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */
166 "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */
167 "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
168 "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */
169 "\\_SB.PCI0.PX40.Q10", /* S1x */
170 "\\Q10"}; /* A2x, L2D, L3D, M2E */
171
172/* Display */ 161/* Display */
173#define METHOD_SWITCH_DISPLAY "SDSP" 162#define METHOD_SWITCH_DISPLAY "SDSP"
174 163
175static acpi_handle display_get_handle;
176static char *display_get_paths[] = {
177 /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */
178 "\\_SB.PCI0.P0P1.VGA.GETD",
179 /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */
180 "\\_SB.PCI0.P0P2.VGA.GETD",
181 /* A6V A6Q */
182 "\\_SB.PCI0.P0P3.VGA.GETD",
183 /* A6T, A6M */
184 "\\_SB.PCI0.P0PA.VGA.GETD",
185 /* L3C */
186 "\\_SB.PCI0.PCI1.VGAC.NMAP",
187 /* Z96F */
188 "\\_SB.PCI0.VGA.GETD",
189 /* A2D */
190 "\\ACTD",
191 /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
192 "\\ADVG",
193 /* P30 */
194 "\\DNXT",
195 /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
196 "\\INFB",
197 /* A3F A6F A3N A3L M6N W3N W6A */
198 "\\SSTE"};
199
200#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ 164#define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */
201#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ 165#define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */
202 166
@@ -246,7 +210,6 @@ struct asus_laptop {
246 210
247 int wireless_status; 211 int wireless_status;
248 bool have_rsts; 212 bool have_rsts;
249 int lcd_state;
250 213
251 struct rfkill *gps_rfkill; 214 struct rfkill *gps_rfkill;
252 215
@@ -559,48 +522,6 @@ error:
559/* 522/*
560 * Backlight device 523 * Backlight device
561 */ 524 */
562static int asus_lcd_status(struct asus_laptop *asus)
563{
564 return asus->lcd_state;
565}
566
567static int asus_lcd_set(struct asus_laptop *asus, int value)
568{
569 int lcd = 0;
570 acpi_status status = 0;
571
572 lcd = !!value;
573
574 if (lcd == asus_lcd_status(asus))
575 return 0;
576
577 if (!lcd_switch_handle)
578 return -ENODEV;
579
580 status = acpi_evaluate_object(lcd_switch_handle,
581 NULL, NULL, NULL);
582
583 if (ACPI_FAILURE(status)) {
584 pr_warning("Error switching LCD\n");
585 return -ENODEV;
586 }
587
588 asus->lcd_state = lcd;
589 return 0;
590}
591
592static void lcd_blank(struct asus_laptop *asus, int blank)
593{
594 struct backlight_device *bd = asus->backlight_device;
595
596 asus->lcd_state = (blank == FB_BLANK_UNBLANK);
597
598 if (bd) {
599 bd->props.power = blank;
600 backlight_update_status(bd);
601 }
602}
603
604static int asus_read_brightness(struct backlight_device *bd) 525static int asus_read_brightness(struct backlight_device *bd)
605{ 526{
606 struct asus_laptop *asus = bl_get_data(bd); 527 struct asus_laptop *asus = bl_get_data(bd);
@@ -628,16 +549,9 @@ static int asus_set_brightness(struct backlight_device *bd, int value)
628 549
629static int update_bl_status(struct backlight_device *bd) 550static int update_bl_status(struct backlight_device *bd)
630{ 551{
631 struct asus_laptop *asus = bl_get_data(bd);
632 int rv;
633 int value = bd->props.brightness; 552 int value = bd->props.brightness;
634 553
635 rv = asus_set_brightness(bd, value); 554 return asus_set_brightness(bd, value);
636 if (rv)
637 return rv;
638
639 value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
640 return asus_lcd_set(asus, value);
641} 555}
642 556
643static const struct backlight_ops asusbl_ops = { 557static const struct backlight_ops asusbl_ops = {
@@ -661,8 +575,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
661 struct backlight_properties props; 575 struct backlight_properties props;
662 576
663 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || 577 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
664 acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) || 578 acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL))
665 !lcd_switch_handle)
666 return 0; 579 return 0;
667 580
668 memset(&props, 0, sizeof(struct backlight_properties)); 581 memset(&props, 0, sizeof(struct backlight_properties));
@@ -971,41 +884,6 @@ static void asus_set_display(struct asus_laptop *asus, int value)
971 return; 884 return;
972} 885}
973 886
974static int read_display(struct asus_laptop *asus)
975{
976 unsigned long long value = 0;
977 acpi_status rv = AE_OK;
978
979 /*
980 * In most of the case, we know how to set the display, but sometime
981 * we can't read it
982 */
983 if (display_get_handle) {
984 rv = acpi_evaluate_integer(display_get_handle, NULL,
985 NULL, &value);
986 if (ACPI_FAILURE(rv))
987 pr_warning("Error reading display status\n");
988 }
989
990 value &= 0x0F; /* needed for some models, shouldn't hurt others */
991
992 return value;
993}
994
995/*
996 * Now, *this* one could be more user-friendly, but so far, no-one has
997 * complained. The significance of bits is the same as in store_disp()
998 */
999static ssize_t show_disp(struct device *dev,
1000 struct device_attribute *attr, char *buf)
1001{
1002 struct asus_laptop *asus = dev_get_drvdata(dev);
1003
1004 if (!display_get_handle)
1005 return -ENODEV;
1006 return sprintf(buf, "%d\n", read_display(asus));
1007}
1008
1009/* 887/*
1010 * Experimental support for display switching. As of now: 1 should activate 888 * Experimental support for display switching. As of now: 1 should activate
1011 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. 889 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
@@ -1247,15 +1125,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
1247 struct asus_laptop *asus = acpi_driver_data(device); 1125 struct asus_laptop *asus = acpi_driver_data(device);
1248 u16 count; 1126 u16 count;
1249 1127
1250 /*
1251 * We need to tell the backlight device when the backlight power is
1252 * switched
1253 */
1254 if (event == ATKD_LCD_ON)
1255 lcd_blank(asus, FB_BLANK_UNBLANK);
1256 else if (event == ATKD_LCD_OFF)
1257 lcd_blank(asus, FB_BLANK_POWERDOWN);
1258
1259 /* TODO Find a better way to handle events count. */ 1128 /* TODO Find a better way to handle events count. */
1260 count = asus->event_count[event % 128]++; 1129 count = asus->event_count[event % 128]++;
1261 acpi_bus_generate_proc_event(asus->device, event, count); 1130 acpi_bus_generate_proc_event(asus->device, event, count);
@@ -1282,7 +1151,7 @@ static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
1282 show_bluetooth, store_bluetooth); 1151 show_bluetooth, store_bluetooth);
1283static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); 1152static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
1284static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); 1153static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
1285static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); 1154static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
1286static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); 1155static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
1287static 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);
1288static 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);
@@ -1393,26 +1262,6 @@ static struct platform_driver platform_driver = {
1393 } 1262 }
1394}; 1263};
1395 1264
1396static int asus_handle_init(char *name, acpi_handle * handle,
1397 char **paths, int num_paths)
1398{
1399 int i;
1400 acpi_status status;
1401
1402 for (i = 0; i < num_paths; i++) {
1403 status = acpi_get_handle(NULL, paths[i], handle);
1404 if (ACPI_SUCCESS(status))
1405 return 0;
1406 }
1407
1408 *handle = NULL;
1409 return -ENODEV;
1410}
1411
1412#define ASUS_HANDLE_INIT(object) \
1413 asus_handle_init(#object, &object##_handle, object##_paths, \
1414 ARRAY_SIZE(object##_paths))
1415
1416/* 1265/*
1417 * 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
1418 * 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
@@ -1498,10 +1347,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
1498 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) 1347 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
1499 asus->have_rsts = true; 1348 asus->have_rsts = true;
1500 1349
1501 /* Scheduled for removal */
1502 ASUS_HANDLE_INIT(lcd_switch);
1503 ASUS_HANDLE_INIT(display_get);
1504
1505 kfree(model); 1350 kfree(model);
1506 1351
1507 return AE_OK; 1352 return AE_OK;
@@ -1553,10 +1398,23 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1553 asus_als_level(asus, asus->light_level); 1398 asus_als_level(asus, asus->light_level);
1554 } 1399 }
1555 1400
1556 asus->lcd_state = 1; /* LCD should be on when the module load */
1557 return result; 1401 return result;
1558} 1402}
1559 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
1560static bool asus_device_present; 1418static bool asus_device_present;
1561 1419
1562static int __devinit asus_acpi_add(struct acpi_device *device) 1420static int __devinit asus_acpi_add(struct acpi_device *device)
@@ -1575,6 +1433,8 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
1575 device->driver_data = asus; 1433 device->driver_data = asus;
1576 asus->device = device; 1434 asus->device = device;
1577 1435
1436 asus_dmi_check();
1437
1578 result = asus_acpi_init(asus); 1438 result = asus_acpi_init(asus);
1579 if (result) 1439 if (result)
1580 goto fail_platform; 1440 goto fail_platform;