diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/asus-laptop.c | 66 |
1 files changed, 60 insertions, 6 deletions
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c index 65c32a95e121..4f9060a2a2f2 100644 --- a/drivers/misc/asus-laptop.c +++ b/drivers/misc/asus-laptop.c | |||
@@ -30,7 +30,7 @@ | |||
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 helpfull |
33 | * | 33 | * Sam Lin - GPS support |
34 | */ | 34 | */ |
35 | 35 | ||
36 | #include <linux/autoconf.h> | 36 | #include <linux/autoconf.h> |
@@ -48,7 +48,7 @@ | |||
48 | #include <acpi/acpi_bus.h> | 48 | #include <acpi/acpi_bus.h> |
49 | #include <asm/uaccess.h> | 49 | #include <asm/uaccess.h> |
50 | 50 | ||
51 | #define ASUS_LAPTOP_VERSION "0.41" | 51 | #define ASUS_LAPTOP_VERSION "0.42" |
52 | 52 | ||
53 | #define ASUS_HOTK_NAME "Asus Laptop Support" | 53 | #define ASUS_HOTK_NAME "Asus Laptop Support" |
54 | #define ASUS_HOTK_CLASS "hotkey" | 54 | #define ASUS_HOTK_CLASS "hotkey" |
@@ -83,6 +83,7 @@ | |||
83 | #define PLED_ON 0x20 //Phone LED | 83 | #define PLED_ON 0x20 //Phone LED |
84 | #define GLED_ON 0x40 //Gaming LED | 84 | #define GLED_ON 0x40 //Gaming LED |
85 | #define LCD_ON 0x80 //LCD backlight | 85 | #define LCD_ON 0x80 //LCD backlight |
86 | #define GPS_ON 0x100 //GPS | ||
86 | 87 | ||
87 | #define ASUS_LOG ASUS_HOTK_FILE ": " | 88 | #define ASUS_LOG ASUS_HOTK_FILE ": " |
88 | #define ASUS_ERR KERN_ERR ASUS_LOG | 89 | #define ASUS_ERR KERN_ERR ASUS_LOG |
@@ -148,7 +149,7 @@ ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP"); | |||
148 | ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G | 149 | ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L4R M6R A3G |
149 | M6A M6V VX-1 V6J V6V W3Z */ | 150 | M6A M6V VX-1 V6J V6V W3Z */ |
150 | "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V | 151 | "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V |
151 | S5A M5A z33A W1Jc W2V */ | 152 | S5A M5A z33A W1Jc W2V G1 */ |
152 | "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ | 153 | "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */ |
153 | "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ | 154 | "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */ |
154 | "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ | 155 | "\\_SB.PCI0.PCI1.VGAC.NMAP", /* L3C */ |
@@ -162,6 +163,12 @@ ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD", /* A6B, A6K A6R A7D F3JM L | |||
162 | ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ | 163 | ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC"); /* Z71A Z71V */ |
163 | ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ | 164 | ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL"); /* Z71A Z71V */ |
164 | 165 | ||
166 | /* GPS */ | ||
167 | /* R2H use different handle for GPS on/off */ | ||
168 | ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON"); /* R2H */ | ||
169 | ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF"); /* R2H */ | ||
170 | ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST"); | ||
171 | |||
165 | /* | 172 | /* |
166 | * This is the main structure, we can use it to store anything interesting | 173 | * This is the main structure, we can use it to store anything interesting |
167 | * about the hotk device | 174 | * about the hotk device |
@@ -278,12 +285,28 @@ static int read_wireless_status(int mask) | |||
278 | return (hotk->status & mask) ? 1 : 0; | 285 | return (hotk->status & mask) ? 1 : 0; |
279 | } | 286 | } |
280 | 287 | ||
288 | static int read_gps_status(void) | ||
289 | { | ||
290 | ulong status; | ||
291 | acpi_status rv = AE_OK; | ||
292 | |||
293 | rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status); | ||
294 | if (ACPI_FAILURE(rv)) | ||
295 | printk(ASUS_WARNING "Error reading GPS status\n"); | ||
296 | else | ||
297 | return status ? 1 : 0; | ||
298 | |||
299 | return (hotk->status & GPS_ON) ? 1 : 0; | ||
300 | } | ||
301 | |||
281 | /* Generic LED functions */ | 302 | /* Generic LED functions */ |
282 | static int read_status(int mask) | 303 | static int read_status(int mask) |
283 | { | 304 | { |
284 | /* There is a special method for both wireless devices */ | 305 | /* There is a special method for both wireless devices */ |
285 | if (mask == BT_ON || mask == WL_ON) | 306 | if (mask == BT_ON || mask == WL_ON) |
286 | return read_wireless_status(mask); | 307 | return read_wireless_status(mask); |
308 | else if (mask == GPS_ON) | ||
309 | return read_gps_status(); | ||
287 | 310 | ||
288 | return (hotk->status & mask) ? 1 : 0; | 311 | return (hotk->status & mask) ? 1 : 0; |
289 | } | 312 | } |
@@ -299,6 +322,10 @@ static void write_status(acpi_handle handle, int out, int mask) | |||
299 | case GLED_ON: | 322 | case GLED_ON: |
300 | out = (out & 0x1) + 1; | 323 | out = (out & 0x1) + 1; |
301 | break; | 324 | break; |
325 | case GPS_ON: | ||
326 | handle = (out) ? gps_on_handle : gps_off_handle; | ||
327 | out = 0x02; | ||
328 | break; | ||
302 | default: | 329 | default: |
303 | out &= 0x1; | 330 | out &= 0x1; |
304 | break; | 331 | break; |
@@ -667,6 +694,21 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr, | |||
667 | return rv; | 694 | return rv; |
668 | } | 695 | } |
669 | 696 | ||
697 | /* | ||
698 | * GPS | ||
699 | */ | ||
700 | static ssize_t show_gps(struct device *dev, | ||
701 | struct device_attribute *attr, char *buf) | ||
702 | { | ||
703 | return sprintf(buf, "%d\n", read_status(GPS_ON)); | ||
704 | } | ||
705 | |||
706 | static ssize_t store_gps(struct device *dev, struct device_attribute *attr, | ||
707 | const char *buf, size_t count) | ||
708 | { | ||
709 | return store_status(buf, count, NULL, GPS_ON); | ||
710 | } | ||
711 | |||
670 | static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) | 712 | static void asus_hotk_notify(acpi_handle handle, u32 event, void *data) |
671 | { | 713 | { |
672 | /* TODO Find a better way to handle events count. */ | 714 | /* TODO Find a better way to handle events count. */ |
@@ -715,6 +757,7 @@ static ASUS_CREATE_DEVICE_ATTR(display); | |||
715 | static ASUS_CREATE_DEVICE_ATTR(ledd); | 757 | static ASUS_CREATE_DEVICE_ATTR(ledd); |
716 | static ASUS_CREATE_DEVICE_ATTR(ls_switch); | 758 | static ASUS_CREATE_DEVICE_ATTR(ls_switch); |
717 | static ASUS_CREATE_DEVICE_ATTR(ls_level); | 759 | static ASUS_CREATE_DEVICE_ATTR(ls_level); |
760 | static ASUS_CREATE_DEVICE_ATTR(gps); | ||
718 | 761 | ||
719 | static struct attribute *asuspf_attributes[] = { | 762 | static struct attribute *asuspf_attributes[] = { |
720 | &dev_attr_infos.attr, | 763 | &dev_attr_infos.attr, |
@@ -724,6 +767,7 @@ static struct attribute *asuspf_attributes[] = { | |||
724 | &dev_attr_ledd.attr, | 767 | &dev_attr_ledd.attr, |
725 | &dev_attr_ls_switch.attr, | 768 | &dev_attr_ls_switch.attr, |
726 | &dev_attr_ls_level.attr, | 769 | &dev_attr_ls_level.attr, |
770 | &dev_attr_gps.attr, | ||
727 | NULL | 771 | NULL |
728 | }; | 772 | }; |
729 | 773 | ||
@@ -763,6 +807,9 @@ static void asus_hotk_add_fs(void) | |||
763 | ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); | 807 | ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl); |
764 | ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); | 808 | ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw); |
765 | } | 809 | } |
810 | |||
811 | if (gps_status_handle && gps_on_handle && gps_off_handle) | ||
812 | ASUS_SET_DEVICE_ATTR(gps, 0644, show_gps, store_gps); | ||
766 | } | 813 | } |
767 | 814 | ||
768 | static int asus_handle_init(char *name, acpi_handle * handle, | 815 | static int asus_handle_init(char *name, acpi_handle * handle, |
@@ -890,9 +937,13 @@ static int asus_hotk_get_info(void) | |||
890 | 937 | ||
891 | /* There is a lot of models with "ALSL", but a few get | 938 | /* There is a lot of models with "ALSL", but a few get |
892 | a real light sens, so we need to check it. */ | 939 | a real light sens, so we need to check it. */ |
893 | if (ASUS_HANDLE_INIT(ls_switch)) | 940 | if (!ASUS_HANDLE_INIT(ls_switch)) |
894 | ASUS_HANDLE_INIT(ls_level); | 941 | ASUS_HANDLE_INIT(ls_level); |
895 | 942 | ||
943 | ASUS_HANDLE_INIT(gps_on); | ||
944 | ASUS_HANDLE_INIT(gps_off); | ||
945 | ASUS_HANDLE_INIT(gps_status); | ||
946 | |||
896 | kfree(model); | 947 | kfree(model); |
897 | 948 | ||
898 | return AE_OK; | 949 | return AE_OK; |
@@ -950,7 +1001,7 @@ static int asus_hotk_add(struct acpi_device *device) | |||
950 | * We install the handler, it will receive the hotk in parameter, so, we | 1001 | * We install the handler, it will receive the hotk in parameter, so, we |
951 | * could add other data to the hotk struct | 1002 | * could add other data to the hotk struct |
952 | */ | 1003 | */ |
953 | status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, | 1004 | status = acpi_install_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, |
954 | asus_hotk_notify, hotk); | 1005 | asus_hotk_notify, hotk); |
955 | if (ACPI_FAILURE(status)) | 1006 | if (ACPI_FAILURE(status)) |
956 | printk(ASUS_ERR "Error installing notify handler\n"); | 1007 | printk(ASUS_ERR "Error installing notify handler\n"); |
@@ -981,6 +1032,9 @@ static int asus_hotk_add(struct acpi_device *device) | |||
981 | if (ls_level_handle) | 1032 | if (ls_level_handle) |
982 | set_light_sens_level(hotk->light_level); | 1033 | set_light_sens_level(hotk->light_level); |
983 | 1034 | ||
1035 | /* GPS is on by default */ | ||
1036 | write_status(NULL, 1, GPS_ON); | ||
1037 | |||
984 | end: | 1038 | end: |
985 | if (result) { | 1039 | if (result) { |
986 | kfree(hotk->name); | 1040 | kfree(hotk->name); |
@@ -997,7 +1051,7 @@ static int asus_hotk_remove(struct acpi_device *device, int type) | |||
997 | if (!device || !acpi_driver_data(device)) | 1051 | if (!device || !acpi_driver_data(device)) |
998 | return -EINVAL; | 1052 | return -EINVAL; |
999 | 1053 | ||
1000 | status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY, | 1054 | status = acpi_remove_notify_handler(hotk->handle, ACPI_ALL_NOTIFY, |
1001 | asus_hotk_notify); | 1055 | asus_hotk_notify); |
1002 | if (ACPI_FAILURE(status)) | 1056 | if (ACPI_FAILURE(status)) |
1003 | printk(ASUS_ERR "Error removing notify handler\n"); | 1057 | printk(ASUS_ERR "Error removing notify handler\n"); |