diff options
Diffstat (limited to 'drivers/platform/x86/asus-laptop.c')
-rw-r--r-- | drivers/platform/x86/asus-laptop.c | 182 |
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 */ | ||
161 | static acpi_handle lcd_switch_handle; | ||
162 | static 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 | ||
175 | static acpi_handle display_get_handle; | ||
176 | static 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 | */ |
562 | static int asus_lcd_status(struct asus_laptop *asus) | ||
563 | { | ||
564 | return asus->lcd_state; | ||
565 | } | ||
566 | |||
567 | static 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 | |||
592 | static 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 | |||
604 | static int asus_read_brightness(struct backlight_device *bd) | 525 | static 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 | ||
629 | static int update_bl_status(struct backlight_device *bd) | 550 | static 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 | ||
643 | static const struct backlight_ops asusbl_ops = { | 557 | static 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 | ||
974 | static 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 | */ | ||
999 | static 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); |
1283 | static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); | 1152 | static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); |
1284 | static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); | 1153 | static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); |
1285 | static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); | 1154 | static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp); |
1286 | static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); | 1155 | static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); |
1287 | static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); | 1156 | static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); |
1288 | static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); | 1157 | static 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 | ||
1396 | static 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 | ||
1404 | static 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 | |||
1560 | static bool asus_device_present; | 1418 | static bool asus_device_present; |
1561 | 1419 | ||
1562 | static int __devinit asus_acpi_add(struct acpi_device *device) | 1420 | static 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; |