aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/x86/Kconfig95
-rw-r--r--drivers/platform/x86/Makefile7
-rw-r--r--drivers/platform/x86/acer-wmi.c152
-rw-r--r--drivers/platform/x86/acerhdf.c19
-rw-r--r--drivers/platform/x86/amilo-rfkill.c5
-rw-r--r--drivers/platform/x86/apple-gmux.c244
-rw-r--r--drivers/platform/x86/asus-laptop.c273
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c12
-rw-r--r--drivers/platform/x86/asus-wmi.c70
-rw-r--r--drivers/platform/x86/asus-wmi.h14
-rw-r--r--drivers/platform/x86/asus_acpi.c1513
-rw-r--r--drivers/platform/x86/compal-laptop.c14
-rw-r--r--drivers/platform/x86/dell-laptop.c34
-rw-r--r--drivers/platform/x86/eeepc-laptop.c15
-rw-r--r--drivers/platform/x86/eeepc-wmi.c108
-rw-r--r--drivers/platform/x86/hdaps.c8
-rw-r--r--drivers/platform/x86/intel_mid_powerbtn.c44
-rw-r--r--drivers/platform/x86/intel_mid_thermal.c61
-rw-r--r--drivers/platform/x86/intel_oaktrail.c2
-rw-r--r--drivers/platform/x86/intel_rar_register.c669
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c208
-rw-r--r--drivers/platform/x86/intel_scu_ipcutil.c32
-rw-r--r--drivers/platform/x86/samsung-laptop.c1749
-rw-r--r--drivers/platform/x86/sony-laptop.c15
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c2
-rw-r--r--drivers/platform/x86/toshiba_acpi.c254
-rw-r--r--drivers/platform/x86/xo1-rfkill.c13
27 files changed, 2298 insertions, 3334 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 15dbd8cc445f..2a262f5c5c0c 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -26,6 +26,10 @@ config ACER_WMI
26 depends on RFKILL || RFKILL = n 26 depends on RFKILL || RFKILL = n
27 depends on ACPI_WMI 27 depends on ACPI_WMI
28 select INPUT_SPARSEKMAP 28 select INPUT_SPARSEKMAP
29 # Acer WMI depends on ACPI_VIDEO when ACPI is enabled
30 # but for select to work, need to select ACPI_VIDEO's dependencies, ick
31 select VIDEO_OUTPUT_CONTROL if ACPI
32 select ACPI_VIDEO if ACPI
29 ---help--- 33 ---help---
30 This is a driver for newer Acer (and Wistron) laptops. It adds 34 This is a driver for newer Acer (and Wistron) laptops. It adds
31 wireless radio and bluetooth control, and on some laptops, 35 wireless radio and bluetooth control, and on some laptops,
@@ -54,7 +58,6 @@ config ACERHDF
54config ASUS_LAPTOP 58config ASUS_LAPTOP
55 tristate "Asus Laptop Extras" 59 tristate "Asus Laptop Extras"
56 depends on ACPI 60 depends on ACPI
57 depends on !ACPI_ASUS
58 select LEDS_CLASS 61 select LEDS_CLASS
59 select NEW_LEDS 62 select NEW_LEDS
60 select BACKLIGHT_CLASS_DEVICE 63 select BACKLIGHT_CLASS_DEVICE
@@ -460,10 +463,9 @@ config INTEL_MENLOW
460 If unsure, say N. 463 If unsure, say N.
461 464
462config EEEPC_LAPTOP 465config EEEPC_LAPTOP
463 tristate "Eee PC Hotkey Driver (EXPERIMENTAL)" 466 tristate "Eee PC Hotkey Driver"
464 depends on ACPI 467 depends on ACPI
465 depends on INPUT 468 depends on INPUT
466 depends on EXPERIMENTAL
467 depends on RFKILL || RFKILL = n 469 depends on RFKILL || RFKILL = n
468 depends on HOTPLUG_PCI 470 depends on HOTPLUG_PCI
469 select BACKLIGHT_CLASS_DEVICE 471 select BACKLIGHT_CLASS_DEVICE
@@ -482,11 +484,10 @@ config EEEPC_LAPTOP
482 doesn't work on your Eee PC, try eeepc-wmi instead. 484 doesn't work on your Eee PC, try eeepc-wmi instead.
483 485
484config ASUS_WMI 486config ASUS_WMI
485 tristate "ASUS WMI Driver (EXPERIMENTAL)" 487 tristate "ASUS WMI Driver"
486 depends on ACPI_WMI 488 depends on ACPI_WMI
487 depends on INPUT 489 depends on INPUT
488 depends on HWMON 490 depends on HWMON
489 depends on EXPERIMENTAL
490 depends on BACKLIGHT_CLASS_DEVICE 491 depends on BACKLIGHT_CLASS_DEVICE
491 depends on RFKILL || RFKILL = n 492 depends on RFKILL || RFKILL = n
492 depends on HOTPLUG_PCI 493 depends on HOTPLUG_PCI
@@ -501,7 +502,7 @@ config ASUS_WMI
501 be called asus-wmi. 502 be called asus-wmi.
502 503
503config ASUS_NB_WMI 504config ASUS_NB_WMI
504 tristate "Asus Notebook WMI Driver (EXPERIMENTAL)" 505 tristate "Asus Notebook WMI Driver"
505 depends on ASUS_WMI 506 depends on ASUS_WMI
506 ---help--- 507 ---help---
507 This is a driver for newer Asus notebooks. It adds extra features 508 This is a driver for newer Asus notebooks. It adds extra features
@@ -514,7 +515,7 @@ config ASUS_NB_WMI
514 here. 515 here.
515 516
516config EEEPC_WMI 517config EEEPC_WMI
517 tristate "Eee PC WMI Driver (EXPERIMENTAL)" 518 tristate "Eee PC WMI Driver"
518 depends on ASUS_WMI 519 depends on ASUS_WMI
519 ---help--- 520 ---help---
520 This is a driver for newer Eee PC laptops. It adds extra features 521 This is a driver for newer Eee PC laptops. It adds extra features
@@ -559,38 +560,6 @@ config MSI_WMI
559 To compile this driver as a module, choose M here: the module will 560 To compile this driver as a module, choose M here: the module will
560 be called msi-wmi. 561 be called msi-wmi.
561 562
562config ACPI_ASUS
563 tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
564 depends on ACPI
565 select BACKLIGHT_CLASS_DEVICE
566 ---help---
567 This driver provides support for extra features of ACPI-compatible
568 ASUS laptops. As some of Medion laptops are made by ASUS, it may also
569 support some Medion laptops (such as 9675 for example). It makes all
570 the extra buttons generate standard ACPI events that go through
571 /proc/acpi/events, and (on some models) adds support for changing the
572 display brightness and output, switching the LCD backlight on and off,
573 and most importantly, allows you to blink those fancy LEDs intended
574 for reporting mail and wireless status.
575
576 Note: display switching code is currently considered EXPERIMENTAL,
577 toying with these values may even lock your machine.
578
579 All settings are changed via /proc/acpi/asus directory entries. Owner
580 and group for these entries can be set with asus_uid and asus_gid
581 parameters.
582
583 More information and a userspace daemon for handling the extra buttons
584 at <http://acpi4asus.sf.net>.
585
586 If you have an ACPI-compatible ASUS laptop, say Y or M here. This
587 driver is still under development, so if your laptop is unsupported or
588 something works not quite as expected, please use the mailing list
589 available on the above page (acpi4asus-user@lists.sourceforge.net).
590
591 NOTE: This driver is deprecated and will probably be removed soon,
592 use asus-laptop instead.
593
594config TOPSTAR_LAPTOP 563config TOPSTAR_LAPTOP
595 tristate "Topstar Laptop Extras" 564 tristate "Topstar Laptop Extras"
596 depends on ACPI 565 depends on ACPI
@@ -604,6 +573,7 @@ config TOPSTAR_LAPTOP
604config ACPI_TOSHIBA 573config ACPI_TOSHIBA
605 tristate "Toshiba Laptop Extras" 574 tristate "Toshiba Laptop Extras"
606 depends on ACPI 575 depends on ACPI
576 depends on ACPI_WMI
607 select LEDS_CLASS 577 select LEDS_CLASS
608 select NEW_LEDS 578 select NEW_LEDS
609 depends on BACKLIGHT_CLASS_DEVICE 579 depends on BACKLIGHT_CLASS_DEVICE
@@ -696,33 +666,11 @@ config INTEL_MID_POWER_BUTTON
696 666
697config INTEL_MFLD_THERMAL 667config INTEL_MFLD_THERMAL
698 tristate "Thermal driver for Intel Medfield platform" 668 tristate "Thermal driver for Intel Medfield platform"
699 depends on INTEL_SCU_IPC && THERMAL 669 depends on MFD_INTEL_MSIC && THERMAL
700 help 670 help
701 Say Y here to enable thermal driver support for the Intel Medfield 671 Say Y here to enable thermal driver support for the Intel Medfield
702 platform. 672 platform.
703 673
704config RAR_REGISTER
705 bool "Restricted Access Region Register Driver"
706 depends on PCI && X86_MRST
707 default n
708 ---help---
709 This driver allows other kernel drivers access to the
710 contents of the restricted access region control registers.
711
712 The restricted access region control registers
713 (rar_registers) are used to pass address and
714 locking information on restricted access regions
715 to other drivers that use restricted access regions.
716
717 The restricted access regions are regions of memory
718 on the Intel MID Platform that are not accessible to
719 the x86 processor, but are accessible to dedicated
720 processors on board peripheral devices.
721
722 The purpose of the restricted access regions is to
723 protect sensitive data from compromise by unauthorized
724 programs running on the x86 processor.
725
726config INTEL_IPS 674config INTEL_IPS
727 tristate "Intel Intelligent Power Sharing" 675 tristate "Intel Intelligent Power Sharing"
728 depends on ACPI 676 depends on ACPI
@@ -768,13 +716,18 @@ config XO15_EBOOK
768 716
769config SAMSUNG_LAPTOP 717config SAMSUNG_LAPTOP
770 tristate "Samsung Laptop driver" 718 tristate "Samsung Laptop driver"
771 depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 719 depends on X86
720 depends on RFKILL || RFKILL = n
721 depends on BACKLIGHT_CLASS_DEVICE
722 select LEDS_CLASS
723 select NEW_LEDS
772 ---help--- 724 ---help---
773 This module implements a driver for a wide range of different 725 This module implements a driver for a wide range of different
774 Samsung laptops. It offers control over the different 726 Samsung laptops. It offers control over the different
775 function keys, wireless LED, LCD backlight level, and 727 function keys, wireless LED, LCD backlight level.
776 sometimes provides a "performance_control" sysfs file to allow 728
777 the performance level of the laptop to be changed. 729 It may also provide some sysfs files described in
730 <file:Documentation/ABI/testing/sysfs-platform-samsung-laptop>
778 731
779 To compile this driver as a module, choose M here: the module 732 To compile this driver as a module, choose M here: the module
780 will be called samsung-laptop. 733 will be called samsung-laptop.
@@ -803,4 +756,14 @@ config SAMSUNG_Q10
803 This driver provides support for backlight control on Samsung Q10 756 This driver provides support for backlight control on Samsung Q10
804 and related laptops, including Dell Latitude X200. 757 and related laptops, including Dell Latitude X200.
805 758
759config APPLE_GMUX
760 tristate "Apple Gmux Driver"
761 depends on PNP
762 select BACKLIGHT_CLASS_DEVICE
763 ---help---
764 This driver provides support for the gmux device found on many
765 Apple laptops, which controls the display mux for the hybrid
766 graphics as well as the backlight. Currently only backlight
767 control is supported by the driver.
768
806endif # X86_PLATFORM_DEVICES 769endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index d328f21e9fdd..bf7e4f935b17 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -29,14 +29,16 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
29obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o 29obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
30obj-$(CONFIG_ACPI_WMI) += wmi.o 30obj-$(CONFIG_ACPI_WMI) += wmi.o
31obj-$(CONFIG_MSI_WMI) += msi-wmi.o 31obj-$(CONFIG_MSI_WMI) += msi-wmi.o
32obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
33obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o 32obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
33
34# toshiba_acpi must link after wmi to ensure that wmi devices are found
35# before toshiba_acpi initializes
34obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 36obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
37
35obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 38obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
36obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 39obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o
37obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o 40obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o
38obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o 41obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
39obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o
40obj-$(CONFIG_INTEL_IPS) += intel_ips.o 42obj-$(CONFIG_INTEL_IPS) += intel_ips.o
41obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o 43obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o
42obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o 44obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o
@@ -47,3 +49,4 @@ obj-$(CONFIG_MXM_WMI) += mxm-wmi.o
47obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o 49obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += intel_mid_powerbtn.o
48obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o 50obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o
49obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o 51obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o
52obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 1e5290b5396d..c1a3fd8e1243 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -43,6 +43,7 @@
43#include <linux/input/sparse-keymap.h> 43#include <linux/input/sparse-keymap.h>
44 44
45#include <acpi/acpi_drivers.h> 45#include <acpi/acpi_drivers.h>
46#include <acpi/video.h>
46 47
47MODULE_AUTHOR("Carlos Corbacho"); 48MODULE_AUTHOR("Carlos Corbacho");
48MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 49MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
@@ -105,13 +106,19 @@ static const struct key_entry acer_wmi_keymap[] = {
105 {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */ 106 {KE_KEY, 0x22, {KEY_PROG2} }, /* Arcade */
106 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ 107 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */
107 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ 108 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */
109 {KE_KEY, 0x29, {KEY_PROG3} }, /* P_Key for TM8372 */
108 {KE_IGNORE, 0x41, {KEY_MUTE} }, 110 {KE_IGNORE, 0x41, {KEY_MUTE} },
109 {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} }, 111 {KE_IGNORE, 0x42, {KEY_PREVIOUSSONG} },
112 {KE_IGNORE, 0x4d, {KEY_PREVIOUSSONG} },
110 {KE_IGNORE, 0x43, {KEY_NEXTSONG} }, 113 {KE_IGNORE, 0x43, {KEY_NEXTSONG} },
114 {KE_IGNORE, 0x4e, {KEY_NEXTSONG} },
111 {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} }, 115 {KE_IGNORE, 0x44, {KEY_PLAYPAUSE} },
116 {KE_IGNORE, 0x4f, {KEY_PLAYPAUSE} },
112 {KE_IGNORE, 0x45, {KEY_STOP} }, 117 {KE_IGNORE, 0x45, {KEY_STOP} },
118 {KE_IGNORE, 0x50, {KEY_STOP} },
113 {KE_IGNORE, 0x48, {KEY_VOLUMEUP} }, 119 {KE_IGNORE, 0x48, {KEY_VOLUMEUP} },
114 {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} }, 120 {KE_IGNORE, 0x49, {KEY_VOLUMEDOWN} },
121 {KE_IGNORE, 0x4a, {KEY_VOLUMEDOWN} },
115 {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} }, 122 {KE_IGNORE, 0x61, {KEY_SWITCHVIDEOMODE} },
116 {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} }, 123 {KE_IGNORE, 0x62, {KEY_BRIGHTNESSUP} },
117 {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} }, 124 {KE_IGNORE, 0x63, {KEY_BRIGHTNESSDOWN} },
@@ -153,7 +160,14 @@ struct lm_return_value {
153 u16 reserved; 160 u16 reserved;
154} __attribute__((packed)); 161} __attribute__((packed));
155 162
156struct wmid3_gds_input_param { /* Get Device Status input parameter */ 163struct wmid3_gds_set_input_param { /* Set Device Status input parameter */
164 u8 function_num; /* Function Number */
165 u8 hotkey_number; /* Hotkey Number */
166 u16 devices; /* Set Device */
167 u8 volume_value; /* Volume Value */
168} __attribute__((packed));
169
170struct wmid3_gds_get_input_param { /* Get Device Status input parameter */
157 u8 function_num; /* Function Number */ 171 u8 function_num; /* Function Number */
158 u8 hotkey_number; /* Hotkey Number */ 172 u8 hotkey_number; /* Hotkey Number */
159 u16 devices; /* Get Device */ 173 u16 devices; /* Get Device */
@@ -171,6 +185,11 @@ struct hotkey_function_type_aa {
171 u8 length; 185 u8 length;
172 u16 handle; 186 u16 handle;
173 u16 commun_func_bitmap; 187 u16 commun_func_bitmap;
188 u16 application_func_bitmap;
189 u16 media_func_bitmap;
190 u16 display_func_bitmap;
191 u16 others_func_bitmap;
192 u8 commun_fn_key_number;
174} __attribute__((packed)); 193} __attribute__((packed));
175 194
176/* 195/*
@@ -207,6 +226,7 @@ static int force_series;
207static bool ec_raw_mode; 226static bool ec_raw_mode;
208static bool has_type_aa; 227static bool has_type_aa;
209static u16 commun_func_bitmap; 228static u16 commun_func_bitmap;
229static u8 commun_fn_key_number;
210 230
211module_param(mailled, int, 0444); 231module_param(mailled, int, 0444);
212module_param(brightness, int, 0444); 232module_param(brightness, int, 0444);
@@ -468,6 +488,15 @@ static struct dmi_system_id acer_quirks[] = {
468 }, 488 },
469 { 489 {
470 .callback = dmi_matched, 490 .callback = dmi_matched,
491 .ident = "Lenovo Ideapad S205 (Brazos)",
492 .matches = {
493 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
494 DMI_MATCH(DMI_PRODUCT_NAME, "Brazos"),
495 },
496 .driver_data = &quirk_lenovo_ideapad_s205,
497 },
498 {
499 .callback = dmi_matched,
471 .ident = "Lenovo 3000 N200", 500 .ident = "Lenovo 3000 N200",
472 .matches = { 501 .matches = {
473 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), 502 DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
@@ -478,6 +507,25 @@ static struct dmi_system_id acer_quirks[] = {
478 {} 507 {}
479}; 508};
480 509
510static int video_set_backlight_video_vendor(const struct dmi_system_id *d)
511{
512 interface->capability &= ~ACER_CAP_BRIGHTNESS;
513 pr_info("Brightness must be controlled by generic video driver\n");
514 return 0;
515}
516
517static const struct dmi_system_id video_vendor_dmi_table[] = {
518 {
519 .callback = video_set_backlight_video_vendor,
520 .ident = "Acer TravelMate 4750",
521 .matches = {
522 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
523 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
524 },
525 },
526 {}
527};
528
481/* Find which quirks are needed for a particular vendor/ model pair */ 529/* Find which quirks are needed for a particular vendor/ model pair */
482static void find_quirks(void) 530static void find_quirks(void)
483{ 531{
@@ -536,8 +584,7 @@ struct acpi_buffer *result)
536 return status; 584 return status;
537} 585}
538 586
539static acpi_status AMW0_get_u32(u32 *value, u32 cap, 587static acpi_status AMW0_get_u32(u32 *value, u32 cap)
540struct wmi_interface *iface)
541{ 588{
542 int err; 589 int err;
543 u8 result; 590 u8 result;
@@ -607,7 +654,7 @@ struct wmi_interface *iface)
607 return AE_OK; 654 return AE_OK;
608} 655}
609 656
610static acpi_status AMW0_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 657static acpi_status AMW0_set_u32(u32 value, u32 cap)
611{ 658{
612 struct wmab_args args; 659 struct wmab_args args;
613 660
@@ -692,6 +739,7 @@ static const struct acpi_device_id norfkill_ids[] = {
692 { "VPC2004", 0}, 739 { "VPC2004", 0},
693 { "IBM0068", 0}, 740 { "IBM0068", 0},
694 { "LEN0068", 0}, 741 { "LEN0068", 0},
742 { "SNY5001", 0}, /* sony-laptop in charge */
695 { "", 0}, 743 { "", 0},
696}; 744};
697 745
@@ -827,8 +875,7 @@ WMI_execute_u32(u32 method_id, u32 in, u32 *out)
827 return status; 875 return status;
828} 876}
829 877
830static acpi_status WMID_get_u32(u32 *value, u32 cap, 878static acpi_status WMID_get_u32(u32 *value, u32 cap)
831struct wmi_interface *iface)
832{ 879{
833 acpi_status status; 880 acpi_status status;
834 u8 tmp; 881 u8 tmp;
@@ -864,7 +911,7 @@ struct wmi_interface *iface)
864 return status; 911 return status;
865} 912}
866 913
867static acpi_status WMID_set_u32(u32 value, u32 cap, struct wmi_interface *iface) 914static acpi_status WMID_set_u32(u32 value, u32 cap)
868{ 915{
869 u32 method_id = 0; 916 u32 method_id = 0;
870 char param; 917 char param;
@@ -912,13 +959,13 @@ static acpi_status wmid3_get_device_status(u32 *value, u16 device)
912 struct wmid3_gds_return_value return_value; 959 struct wmid3_gds_return_value return_value;
913 acpi_status status; 960 acpi_status status;
914 union acpi_object *obj; 961 union acpi_object *obj;
915 struct wmid3_gds_input_param params = { 962 struct wmid3_gds_get_input_param params = {
916 .function_num = 0x1, 963 .function_num = 0x1,
917 .hotkey_number = 0x01, 964 .hotkey_number = commun_fn_key_number,
918 .devices = device, 965 .devices = device,
919 }; 966 };
920 struct acpi_buffer input = { 967 struct acpi_buffer input = {
921 sizeof(struct wmid3_gds_input_param), 968 sizeof(struct wmid3_gds_get_input_param),
922 &params 969 &params
923 }; 970 };
924 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 971 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -981,19 +1028,28 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
981 acpi_status status; 1028 acpi_status status;
982 union acpi_object *obj; 1029 union acpi_object *obj;
983 u16 devices; 1030 u16 devices;
984 struct wmid3_gds_input_param params = { 1031 struct wmid3_gds_get_input_param get_params = {
985 .function_num = 0x1, 1032 .function_num = 0x1,
986 .hotkey_number = 0x01, 1033 .hotkey_number = commun_fn_key_number,
987 .devices = commun_func_bitmap, 1034 .devices = commun_func_bitmap,
988 }; 1035 };
989 struct acpi_buffer input = { 1036 struct acpi_buffer get_input = {
990 sizeof(struct wmid3_gds_input_param), 1037 sizeof(struct wmid3_gds_get_input_param),
991 &params 1038 &get_params
1039 };
1040 struct wmid3_gds_set_input_param set_params = {
1041 .function_num = 0x2,
1042 .hotkey_number = commun_fn_key_number,
1043 .devices = commun_func_bitmap,
1044 };
1045 struct acpi_buffer set_input = {
1046 sizeof(struct wmid3_gds_set_input_param),
1047 &set_params
992 }; 1048 };
993 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 1049 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
994 struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL }; 1050 struct acpi_buffer output2 = { ACPI_ALLOCATE_BUFFER, NULL };
995 1051
996 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &input, &output); 1052 status = wmi_evaluate_method(WMID_GUID3, 0, 0x2, &get_input, &output);
997 if (ACPI_FAILURE(status)) 1053 if (ACPI_FAILURE(status))
998 return status; 1054 return status;
999 1055
@@ -1006,7 +1062,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
1006 return AE_ERROR; 1062 return AE_ERROR;
1007 } 1063 }
1008 if (obj->buffer.length != 8) { 1064 if (obj->buffer.length != 8) {
1009 pr_warning("Unknown buffer length %d\n", obj->buffer.length); 1065 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1010 kfree(obj); 1066 kfree(obj);
1011 return AE_ERROR; 1067 return AE_ERROR;
1012 } 1068 }
@@ -1015,18 +1071,16 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
1015 kfree(obj); 1071 kfree(obj);
1016 1072
1017 if (return_value.error_code || return_value.ec_return_value) { 1073 if (return_value.error_code || return_value.ec_return_value) {
1018 pr_warning("Get Current Device Status failed: " 1074 pr_warn("Get Current Device Status failed: 0x%x - 0x%x\n",
1019 "0x%x - 0x%x\n", return_value.error_code, 1075 return_value.error_code,
1020 return_value.ec_return_value); 1076 return_value.ec_return_value);
1021 return status; 1077 return status;
1022 } 1078 }
1023 1079
1024 devices = return_value.devices; 1080 devices = return_value.devices;
1025 params.function_num = 0x2; 1081 set_params.devices = (value) ? (devices | device) : (devices & ~device);
1026 params.hotkey_number = 0x01;
1027 params.devices = (value) ? (devices | device) : (devices & ~device);
1028 1082
1029 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &input, &output2); 1083 status = wmi_evaluate_method(WMID_GUID3, 0, 0x1, &set_input, &output2);
1030 if (ACPI_FAILURE(status)) 1084 if (ACPI_FAILURE(status))
1031 return status; 1085 return status;
1032 1086
@@ -1039,7 +1093,7 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
1039 return AE_ERROR; 1093 return AE_ERROR;
1040 } 1094 }
1041 if (obj->buffer.length != 4) { 1095 if (obj->buffer.length != 4) {
1042 pr_warning("Unknown buffer length %d\n", obj->buffer.length); 1096 pr_warn("Unknown buffer length %d\n", obj->buffer.length);
1043 kfree(obj); 1097 kfree(obj);
1044 return AE_ERROR; 1098 return AE_ERROR;
1045 } 1099 }
@@ -1048,8 +1102,8 @@ static acpi_status wmid3_set_device_status(u32 value, u16 device)
1048 kfree(obj); 1102 kfree(obj);
1049 1103
1050 if (return_value.error_code || return_value.ec_return_value) 1104 if (return_value.error_code || return_value.ec_return_value)
1051 pr_warning("Set Device Status failed: " 1105 pr_warn("Set Device Status failed: 0x%x - 0x%x\n",
1052 "0x%x - 0x%x\n", return_value.error_code, 1106 return_value.error_code,
1053 return_value.ec_return_value); 1107 return_value.ec_return_value);
1054 1108
1055 return status; 1109 return status;
@@ -1096,6 +1150,8 @@ static void type_aa_dmi_decode(const struct dmi_header *header, void *dummy)
1096 interface->capability |= ACER_CAP_THREEG; 1150 interface->capability |= ACER_CAP_THREEG;
1097 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH) 1151 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_BLUETOOTH)
1098 interface->capability |= ACER_CAP_BLUETOOTH; 1152 interface->capability |= ACER_CAP_BLUETOOTH;
1153
1154 commun_fn_key_number = type_aa->commun_fn_key_number;
1099} 1155}
1100 1156
1101static acpi_status WMID_set_capabilities(void) 1157static acpi_status WMID_set_capabilities(void)
@@ -1154,15 +1210,15 @@ static acpi_status get_u32(u32 *value, u32 cap)
1154 1210
1155 switch (interface->type) { 1211 switch (interface->type) {
1156 case ACER_AMW0: 1212 case ACER_AMW0:
1157 status = AMW0_get_u32(value, cap, interface); 1213 status = AMW0_get_u32(value, cap);
1158 break; 1214 break;
1159 case ACER_AMW0_V2: 1215 case ACER_AMW0_V2:
1160 if (cap == ACER_CAP_MAILLED) { 1216 if (cap == ACER_CAP_MAILLED) {
1161 status = AMW0_get_u32(value, cap, interface); 1217 status = AMW0_get_u32(value, cap);
1162 break; 1218 break;
1163 } 1219 }
1164 case ACER_WMID: 1220 case ACER_WMID:
1165 status = WMID_get_u32(value, cap, interface); 1221 status = WMID_get_u32(value, cap);
1166 break; 1222 break;
1167 case ACER_WMID_v2: 1223 case ACER_WMID_v2:
1168 if (cap & (ACER_CAP_WIRELESS | 1224 if (cap & (ACER_CAP_WIRELESS |
@@ -1170,7 +1226,7 @@ static acpi_status get_u32(u32 *value, u32 cap)
1170 ACER_CAP_THREEG)) 1226 ACER_CAP_THREEG))
1171 status = wmid_v2_get_u32(value, cap); 1227 status = wmid_v2_get_u32(value, cap);
1172 else if (wmi_has_guid(WMID_GUID2)) 1228 else if (wmi_has_guid(WMID_GUID2))
1173 status = WMID_get_u32(value, cap, interface); 1229 status = WMID_get_u32(value, cap);
1174 break; 1230 break;
1175 } 1231 }
1176 1232
@@ -1184,10 +1240,10 @@ static acpi_status set_u32(u32 value, u32 cap)
1184 if (interface->capability & cap) { 1240 if (interface->capability & cap) {
1185 switch (interface->type) { 1241 switch (interface->type) {
1186 case ACER_AMW0: 1242 case ACER_AMW0:
1187 return AMW0_set_u32(value, cap, interface); 1243 return AMW0_set_u32(value, cap);
1188 case ACER_AMW0_V2: 1244 case ACER_AMW0_V2:
1189 if (cap == ACER_CAP_MAILLED) 1245 if (cap == ACER_CAP_MAILLED)
1190 return AMW0_set_u32(value, cap, interface); 1246 return AMW0_set_u32(value, cap);
1191 1247
1192 /* 1248 /*
1193 * On some models, some WMID methods don't toggle 1249 * On some models, some WMID methods don't toggle
@@ -1197,21 +1253,21 @@ static acpi_status set_u32(u32 value, u32 cap)
1197 */ 1253 */
1198 if (cap == ACER_CAP_WIRELESS || 1254 if (cap == ACER_CAP_WIRELESS ||
1199 cap == ACER_CAP_BLUETOOTH) { 1255 cap == ACER_CAP_BLUETOOTH) {
1200 status = WMID_set_u32(value, cap, interface); 1256 status = WMID_set_u32(value, cap);
1201 if (ACPI_FAILURE(status)) 1257 if (ACPI_FAILURE(status))
1202 return status; 1258 return status;
1203 1259
1204 return AMW0_set_u32(value, cap, interface); 1260 return AMW0_set_u32(value, cap);
1205 } 1261 }
1206 case ACER_WMID: 1262 case ACER_WMID:
1207 return WMID_set_u32(value, cap, interface); 1263 return WMID_set_u32(value, cap);
1208 case ACER_WMID_v2: 1264 case ACER_WMID_v2:
1209 if (cap & (ACER_CAP_WIRELESS | 1265 if (cap & (ACER_CAP_WIRELESS |
1210 ACER_CAP_BLUETOOTH | 1266 ACER_CAP_BLUETOOTH |
1211 ACER_CAP_THREEG)) 1267 ACER_CAP_THREEG))
1212 return wmid_v2_set_u32(value, cap); 1268 return wmid_v2_set_u32(value, cap);
1213 else if (wmi_has_guid(WMID_GUID2)) 1269 else if (wmi_has_guid(WMID_GUID2))
1214 return WMID_set_u32(value, cap, interface); 1270 return WMID_set_u32(value, cap);
1215 default: 1271 default:
1216 return AE_BAD_PARAMETER; 1272 return AE_BAD_PARAMETER;
1217 } 1273 }
@@ -1488,8 +1544,8 @@ static ssize_t show_bool_threeg(struct device *dev,
1488 u32 result; \ 1544 u32 result; \
1489 acpi_status status; 1545 acpi_status status;
1490 1546
1491 pr_info("This threeg sysfs will be removed in 2012" 1547 pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
1492 " - used by: %s\n", current->comm); 1548 current->comm);
1493 status = get_u32(&result, ACER_CAP_THREEG); 1549 status = get_u32(&result, ACER_CAP_THREEG);
1494 if (ACPI_SUCCESS(status)) 1550 if (ACPI_SUCCESS(status))
1495 return sprintf(buf, "%u\n", result); 1551 return sprintf(buf, "%u\n", result);
@@ -1501,8 +1557,8 @@ static ssize_t set_bool_threeg(struct device *dev,
1501{ 1557{
1502 u32 tmp = simple_strtoul(buf, NULL, 10); 1558 u32 tmp = simple_strtoul(buf, NULL, 10);
1503 acpi_status status = set_u32(tmp, ACER_CAP_THREEG); 1559 acpi_status status = set_u32(tmp, ACER_CAP_THREEG);
1504 pr_info("This threeg sysfs will be removed in 2012" 1560 pr_info("This threeg sysfs will be removed in 2012 - used by: %s\n",
1505 " - used by: %s\n", current->comm); 1561 current->comm);
1506 if (ACPI_FAILURE(status)) 1562 if (ACPI_FAILURE(status))
1507 return -EINVAL; 1563 return -EINVAL;
1508 return count; 1564 return count;
@@ -1513,8 +1569,8 @@ static DEVICE_ATTR(threeg, S_IRUGO | S_IWUSR, show_bool_threeg,
1513static ssize_t show_interface(struct device *dev, struct device_attribute *attr, 1569static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1514 char *buf) 1570 char *buf)
1515{ 1571{
1516 pr_info("This interface sysfs will be removed in 2012" 1572 pr_info("This interface sysfs will be removed in 2012 - used by: %s\n",
1517 " - used by: %s\n", current->comm); 1573 current->comm);
1518 switch (interface->type) { 1574 switch (interface->type) {
1519 case ACER_AMW0: 1575 case ACER_AMW0:
1520 return sprintf(buf, "AMW0\n"); 1576 return sprintf(buf, "AMW0\n");
@@ -1981,9 +2037,13 @@ static int __init acer_wmi_init(void)
1981 set_quirks(); 2037 set_quirks();
1982 2038
1983 if (acpi_video_backlight_support()) { 2039 if (acpi_video_backlight_support()) {
1984 interface->capability &= ~ACER_CAP_BRIGHTNESS; 2040 if (dmi_check_system(video_vendor_dmi_table)) {
1985 pr_info("Brightness must be controlled by " 2041 acpi_video_unregister();
1986 "generic video driver\n"); 2042 } else {
2043 interface->capability &= ~ACER_CAP_BRIGHTNESS;
2044 pr_info("Brightness must be controlled by "
2045 "acpi video driver\n");
2046 }
1987 } 2047 }
1988 2048
1989 if (wmi_has_guid(WMID_GUID3)) { 2049 if (wmi_has_guid(WMID_GUID3)) {
@@ -2008,7 +2068,7 @@ static int __init acer_wmi_init(void)
2008 2068
2009 err = platform_driver_register(&acer_platform_driver); 2069 err = platform_driver_register(&acer_platform_driver);
2010 if (err) { 2070 if (err) {
2011 pr_err("Unable to register platform driver.\n"); 2071 pr_err("Unable to register platform driver\n");
2012 goto error_platform_register; 2072 goto error_platform_register;
2013 } 2073 }
2014 2074
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index 760c6d7624fe..bc8384c6f3eb 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -244,12 +244,11 @@ static void acerhdf_change_fanstate(int state)
244 unsigned char cmd; 244 unsigned char cmd;
245 245
246 if (verbose) 246 if (verbose)
247 pr_notice("fan %s\n", (state == ACERHDF_FAN_OFF) ? 247 pr_notice("fan %s\n", state == ACERHDF_FAN_OFF ? "OFF" : "ON");
248 "OFF" : "ON");
249 248
250 if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) { 249 if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
251 pr_err("invalid fan state %d requested, setting to auto!\n", 250 pr_err("invalid fan state %d requested, setting to auto!\n",
252 state); 251 state);
253 state = ACERHDF_FAN_AUTO; 252 state = ACERHDF_FAN_AUTO;
254 } 253 }
255 254
@@ -264,19 +263,18 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
264{ 263{
265 if (fanon > ACERHDF_MAX_FANON) { 264 if (fanon > ACERHDF_MAX_FANON) {
266 pr_err("fanon temperature too high, set to %d\n", 265 pr_err("fanon temperature too high, set to %d\n",
267 ACERHDF_MAX_FANON); 266 ACERHDF_MAX_FANON);
268 fanon = ACERHDF_MAX_FANON; 267 fanon = ACERHDF_MAX_FANON;
269 } 268 }
270 269
271 if (kernelmode && prev_interval != interval) { 270 if (kernelmode && prev_interval != interval) {
272 if (interval > ACERHDF_MAX_INTERVAL) { 271 if (interval > ACERHDF_MAX_INTERVAL) {
273 pr_err("interval too high, set to %d\n", 272 pr_err("interval too high, set to %d\n",
274 ACERHDF_MAX_INTERVAL); 273 ACERHDF_MAX_INTERVAL);
275 interval = ACERHDF_MAX_INTERVAL; 274 interval = ACERHDF_MAX_INTERVAL;
276 } 275 }
277 if (verbose) 276 if (verbose)
278 pr_notice("interval changed to: %d\n", 277 pr_notice("interval changed to: %d\n", interval);
279 interval);
280 thermal->polling_delay = interval*1000; 278 thermal->polling_delay = interval*1000;
281 prev_interval = interval; 279 prev_interval = interval;
282 } 280 }
@@ -587,8 +585,8 @@ static int acerhdf_check_hardware(void)
587 } 585 }
588 586
589 if (!bios_cfg) { 587 if (!bios_cfg) {
590 pr_err("unknown (unsupported) BIOS version %s/%s/%s, " 588 pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n",
591 "please report, aborting!\n", vendor, product, version); 589 vendor, product, version);
592 return -EINVAL; 590 return -EINVAL;
593 } 591 }
594 592
@@ -598,8 +596,7 @@ static int acerhdf_check_hardware(void)
598 */ 596 */
599 if (!kernelmode) { 597 if (!kernelmode) {
600 pr_notice("Fan control off, to enable do:\n"); 598 pr_notice("Fan control off, to enable do:\n");
601 pr_notice("echo -n \"enabled\" > " 599 pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zone0/mode\n");
602 "/sys/class/thermal/thermal_zone0/mode\n");
603 } 600 }
604 601
605 return 0; 602 return 0;
diff --git a/drivers/platform/x86/amilo-rfkill.c b/drivers/platform/x86/amilo-rfkill.c
index 19170bb7700b..a514bf66fdd7 100644
--- a/drivers/platform/x86/amilo-rfkill.c
+++ b/drivers/platform/x86/amilo-rfkill.c
@@ -97,9 +97,12 @@ static struct rfkill *amilo_rfkill_dev;
97 97
98static int __devinit amilo_rfkill_probe(struct platform_device *device) 98static int __devinit amilo_rfkill_probe(struct platform_device *device)
99{ 99{
100 int rc;
100 const struct dmi_system_id *system_id = 101 const struct dmi_system_id *system_id =
101 dmi_first_match(amilo_rfkill_id_table); 102 dmi_first_match(amilo_rfkill_id_table);
102 int rc; 103
104 if (!system_id)
105 return -ENXIO;
103 106
104 amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev, 107 amilo_rfkill_dev = rfkill_alloc(KBUILD_MODNAME, &device->dev,
105 RFKILL_TYPE_WLAN, 108 RFKILL_TYPE_WLAN,
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
new file mode 100644
index 000000000000..8a582bdfdc76
--- /dev/null
+++ b/drivers/platform/x86/apple-gmux.c
@@ -0,0 +1,244 @@
1/*
2 * Gmux driver for Apple laptops
3 *
4 * Copyright (C) Canonical Ltd. <seth.forshee@canonical.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12
13#include <linux/module.h>
14#include <linux/kernel.h>
15#include <linux/init.h>
16#include <linux/backlight.h>
17#include <linux/acpi.h>
18#include <linux/pnp.h>
19#include <linux/apple_bl.h>
20#include <linux/slab.h>
21#include <acpi/video.h>
22#include <asm/io.h>
23
24struct apple_gmux_data {
25 unsigned long iostart;
26 unsigned long iolen;
27
28 struct backlight_device *bdev;
29};
30
31/*
32 * gmux port offsets. Many of these are not yet used, but may be in the
33 * future, and it's useful to have them documented here anyhow.
34 */
35#define GMUX_PORT_VERSION_MAJOR 0x04
36#define GMUX_PORT_VERSION_MINOR 0x05
37#define GMUX_PORT_VERSION_RELEASE 0x06
38#define GMUX_PORT_SWITCH_DISPLAY 0x10
39#define GMUX_PORT_SWITCH_GET_DISPLAY 0x11
40#define GMUX_PORT_INTERRUPT_ENABLE 0x14
41#define GMUX_PORT_INTERRUPT_STATUS 0x16
42#define GMUX_PORT_SWITCH_DDC 0x28
43#define GMUX_PORT_SWITCH_EXTERNAL 0x40
44#define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41
45#define GMUX_PORT_DISCRETE_POWER 0x50
46#define GMUX_PORT_MAX_BRIGHTNESS 0x70
47#define GMUX_PORT_BRIGHTNESS 0x74
48
49#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
50
51#define GMUX_INTERRUPT_ENABLE 0xff
52#define GMUX_INTERRUPT_DISABLE 0x00
53
54#define GMUX_INTERRUPT_STATUS_ACTIVE 0
55#define GMUX_INTERRUPT_STATUS_DISPLAY (1 << 0)
56#define GMUX_INTERRUPT_STATUS_POWER (1 << 2)
57#define GMUX_INTERRUPT_STATUS_HOTPLUG (1 << 3)
58
59#define GMUX_BRIGHTNESS_MASK 0x00ffffff
60#define GMUX_MAX_BRIGHTNESS GMUX_BRIGHTNESS_MASK
61
62static inline u8 gmux_read8(struct apple_gmux_data *gmux_data, int port)
63{
64 return inb(gmux_data->iostart + port);
65}
66
67static inline void gmux_write8(struct apple_gmux_data *gmux_data, int port,
68 u8 val)
69{
70 outb(val, gmux_data->iostart + port);
71}
72
73static inline u32 gmux_read32(struct apple_gmux_data *gmux_data, int port)
74{
75 return inl(gmux_data->iostart + port);
76}
77
78static int gmux_get_brightness(struct backlight_device *bd)
79{
80 struct apple_gmux_data *gmux_data = bl_get_data(bd);
81 return gmux_read32(gmux_data, GMUX_PORT_BRIGHTNESS) &
82 GMUX_BRIGHTNESS_MASK;
83}
84
85static int gmux_update_status(struct backlight_device *bd)
86{
87 struct apple_gmux_data *gmux_data = bl_get_data(bd);
88 u32 brightness = bd->props.brightness;
89
90 /*
91 * Older gmux versions require writing out lower bytes first then
92 * setting the upper byte to 0 to flush the values. Newer versions
93 * accept a single u32 write, but the old method also works, so we
94 * just use the old method for all gmux versions.
95 */
96 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS, brightness);
97 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 1, brightness >> 8);
98 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 2, brightness >> 16);
99 gmux_write8(gmux_data, GMUX_PORT_BRIGHTNESS + 3, 0);
100
101 return 0;
102}
103
104static const struct backlight_ops gmux_bl_ops = {
105 .get_brightness = gmux_get_brightness,
106 .update_status = gmux_update_status,
107};
108
109static int __devinit gmux_probe(struct pnp_dev *pnp,
110 const struct pnp_device_id *id)
111{
112 struct apple_gmux_data *gmux_data;
113 struct resource *res;
114 struct backlight_properties props;
115 struct backlight_device *bdev;
116 u8 ver_major, ver_minor, ver_release;
117 int ret = -ENXIO;
118
119 gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
120 if (!gmux_data)
121 return -ENOMEM;
122 pnp_set_drvdata(pnp, gmux_data);
123
124 res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
125 if (!res) {
126 pr_err("Failed to find gmux I/O resource\n");
127 goto err_free;
128 }
129
130 gmux_data->iostart = res->start;
131 gmux_data->iolen = res->end - res->start;
132
133 if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
134 pr_err("gmux I/O region too small (%lu < %u)\n",
135 gmux_data->iolen, GMUX_MIN_IO_LEN);
136 goto err_free;
137 }
138
139 if (!request_region(gmux_data->iostart, gmux_data->iolen,
140 "Apple gmux")) {
141 pr_err("gmux I/O already in use\n");
142 goto err_free;
143 }
144
145 /*
146 * On some machines the gmux is in ACPI even thought the machine
147 * doesn't really have a gmux. Check for invalid version information
148 * to detect this.
149 */
150 ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
151 ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
152 ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
153 if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
154 pr_info("gmux device not present\n");
155 ret = -ENODEV;
156 goto err_release;
157 }
158
159 pr_info("Found gmux version %d.%d.%d\n", ver_major, ver_minor,
160 ver_release);
161
162 memset(&props, 0, sizeof(props));
163 props.type = BACKLIGHT_PLATFORM;
164 props.max_brightness = gmux_read32(gmux_data, GMUX_PORT_MAX_BRIGHTNESS);
165
166 /*
167 * Currently it's assumed that the maximum brightness is less than
168 * 2^24 for compatibility with old gmux versions. Cap the max
169 * brightness at this value, but print a warning if the hardware
170 * reports something higher so that it can be fixed.
171 */
172 if (WARN_ON(props.max_brightness > GMUX_MAX_BRIGHTNESS))
173 props.max_brightness = GMUX_MAX_BRIGHTNESS;
174
175 bdev = backlight_device_register("gmux_backlight", &pnp->dev,
176 gmux_data, &gmux_bl_ops, &props);
177 if (IS_ERR(bdev)) {
178 ret = PTR_ERR(bdev);
179 goto err_release;
180 }
181
182 gmux_data->bdev = bdev;
183 bdev->props.brightness = gmux_get_brightness(bdev);
184 backlight_update_status(bdev);
185
186 /*
187 * The backlight situation on Macs is complicated. If the gmux is
188 * present it's the best choice, because it always works for
189 * backlight control and supports more levels than other options.
190 * Disable the other backlight choices.
191 */
192 acpi_video_unregister();
193 apple_bl_unregister();
194
195 return 0;
196
197err_release:
198 release_region(gmux_data->iostart, gmux_data->iolen);
199err_free:
200 kfree(gmux_data);
201 return ret;
202}
203
204static void __devexit gmux_remove(struct pnp_dev *pnp)
205{
206 struct apple_gmux_data *gmux_data = pnp_get_drvdata(pnp);
207
208 backlight_device_unregister(gmux_data->bdev);
209 release_region(gmux_data->iostart, gmux_data->iolen);
210 kfree(gmux_data);
211
212 acpi_video_register();
213 apple_bl_register();
214}
215
216static const struct pnp_device_id gmux_device_ids[] = {
217 {"APP000B", 0},
218 {"", 0}
219};
220
221static struct pnp_driver gmux_pnp_driver = {
222 .name = "apple-gmux",
223 .probe = gmux_probe,
224 .remove = __devexit_p(gmux_remove),
225 .id_table = gmux_device_ids,
226};
227
228static int __init apple_gmux_init(void)
229{
230 return pnp_register_driver(&gmux_pnp_driver);
231}
232
233static void __exit apple_gmux_exit(void)
234{
235 pnp_unregister_driver(&gmux_pnp_driver);
236}
237
238module_init(apple_gmux_init);
239module_exit(apple_gmux_exit);
240
241MODULE_AUTHOR("Seth Forshee <seth.forshee@canonical.com>");
242MODULE_DESCRIPTION("Apple Gmux Driver");
243MODULE_LICENSE("GPL");
244MODULE_DEVICE_TABLE(pnp, gmux_device_ids);
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index b7944f903886..e38f91be0b10 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -81,6 +81,19 @@ static uint wapf = 1;
81module_param(wapf, uint, 0444); 81module_param(wapf, uint, 0444);
82MODULE_PARM_DESC(wapf, "WAPF value"); 82MODULE_PARM_DESC(wapf, "WAPF value");
83 83
84static char *wled_type = "unknown";
85static char *bled_type = "unknown";
86
87module_param(wled_type, charp, 0444);
88MODULE_PARM_DESC(wlan_status, "Set the wled type on boot "
89 "(unknown, led or rfkill). "
90 "default is unknown");
91
92module_param(bled_type, charp, 0444);
93MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
94 "(unknown, led or rfkill). "
95 "default is unknown");
96
84static int wlan_status = 1; 97static int wlan_status = 1;
85static int bluetooth_status = 1; 98static int bluetooth_status = 1;
86static int wimax_status = -1; 99static int wimax_status = -1;
@@ -137,6 +150,11 @@ MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
137#define WM_RSTS 0x08 /* internal wimax */ 150#define WM_RSTS 0x08 /* internal wimax */
138#define WW_RSTS 0x20 /* internal wwan */ 151#define WW_RSTS 0x20 /* internal wwan */
139 152
153/* WLED and BLED type */
154#define TYPE_UNKNOWN 0
155#define TYPE_LED 1
156#define TYPE_RFKILL 2
157
140/* LED */ 158/* LED */
141#define METHOD_MLED "MLED" 159#define METHOD_MLED "MLED"
142#define METHOD_TLED "TLED" 160#define METHOD_TLED "TLED"
@@ -218,8 +236,9 @@ struct asus_led {
218/* 236/*
219 * Same thing for rfkill 237 * Same thing for rfkill
220 */ 238 */
221struct asus_pega_rfkill { 239struct asus_rfkill {
222 int control_id; /* type of control. Maps to PEGA_* values */ 240 /* type of control. Maps to PEGA_* values or *_RSTS */
241 int control_id;
223 struct rfkill *rfkill; 242 struct rfkill *rfkill;
224 struct asus_laptop *asus; 243 struct asus_laptop *asus;
225}; 244};
@@ -240,6 +259,8 @@ struct asus_laptop {
240 struct key_entry *keymap; 259 struct key_entry *keymap;
241 struct input_polled_dev *pega_accel_poll; 260 struct input_polled_dev *pega_accel_poll;
242 261
262 struct asus_led wled;
263 struct asus_led bled;
243 struct asus_led mled; 264 struct asus_led mled;
244 struct asus_led tled; 265 struct asus_led tled;
245 struct asus_led rled; 266 struct asus_led rled;
@@ -248,6 +269,8 @@ struct asus_laptop {
248 struct asus_led kled; 269 struct asus_led kled;
249 struct workqueue_struct *led_workqueue; 270 struct workqueue_struct *led_workqueue;
250 271
272 int wled_type;
273 int bled_type;
251 int wireless_status; 274 int wireless_status;
252 bool have_rsts; 275 bool have_rsts;
253 bool is_pega_lucid; 276 bool is_pega_lucid;
@@ -256,11 +279,11 @@ struct asus_laptop {
256 int pega_acc_y; 279 int pega_acc_y;
257 int pega_acc_z; 280 int pega_acc_z;
258 281
259 struct rfkill *gps_rfkill; 282 struct asus_rfkill wlan;
260 283 struct asus_rfkill bluetooth;
261 struct asus_pega_rfkill wlanrfk; 284 struct asus_rfkill wwan;
262 struct asus_pega_rfkill btrfk; 285 struct asus_rfkill wimax;
263 struct asus_pega_rfkill wwanrfk; 286 struct asus_rfkill gps;
264 287
265 acpi_handle handle; /* the handle of the hotk device */ 288 acpi_handle handle; /* the handle of the hotk device */
266 u32 ledd_status; /* status of the LED display */ 289 u32 ledd_status; /* status of the LED display */
@@ -274,6 +297,7 @@ static const struct key_entry asus_keymap[] = {
274 {KE_KEY, 0x02, { KEY_SCREENLOCK } }, 297 {KE_KEY, 0x02, { KEY_SCREENLOCK } },
275 {KE_KEY, 0x05, { KEY_WLAN } }, 298 {KE_KEY, 0x05, { KEY_WLAN } },
276 {KE_KEY, 0x08, { KEY_F13 } }, 299 {KE_KEY, 0x08, { KEY_F13 } },
300 {KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
277 {KE_KEY, 0x17, { KEY_ZOOM } }, 301 {KE_KEY, 0x17, { KEY_ZOOM } },
278 {KE_KEY, 0x1f, { KEY_BATTERY } }, 302 {KE_KEY, 0x1f, { KEY_BATTERY } },
279 /* End of Lenovo SL Specific keycodes */ 303 /* End of Lenovo SL Specific keycodes */
@@ -299,6 +323,8 @@ static const struct key_entry asus_keymap[] = {
299 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, 323 {KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } },
300 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, 324 {KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } },
301 {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */ 325 {KE_KEY, 0x6B, { KEY_F13 } }, /* Lock Touchpad */
326 {KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
327 {KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
302 {KE_KEY, 0x7E, { KEY_BLUETOOTH } }, 328 {KE_KEY, 0x7E, { KEY_BLUETOOTH } },
303 {KE_KEY, 0x7D, { KEY_BLUETOOTH } }, 329 {KE_KEY, 0x7D, { KEY_BLUETOOTH } },
304 {KE_KEY, 0x82, { KEY_CAMERA } }, 330 {KE_KEY, 0x82, { KEY_CAMERA } },
@@ -601,6 +627,10 @@ static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
601 627
602static void asus_led_exit(struct asus_laptop *asus) 628static void asus_led_exit(struct asus_laptop *asus)
603{ 629{
630 if (!IS_ERR_OR_NULL(asus->wled.led.dev))
631 led_classdev_unregister(&asus->wled.led);
632 if (!IS_ERR_OR_NULL(asus->bled.led.dev))
633 led_classdev_unregister(&asus->bled.led);
604 if (!IS_ERR_OR_NULL(asus->mled.led.dev)) 634 if (!IS_ERR_OR_NULL(asus->mled.led.dev))
605 led_classdev_unregister(&asus->mled.led); 635 led_classdev_unregister(&asus->mled.led);
606 if (!IS_ERR_OR_NULL(asus->tled.led.dev)) 636 if (!IS_ERR_OR_NULL(asus->tled.led.dev))
@@ -642,7 +672,7 @@ static int asus_led_register(struct asus_laptop *asus,
642 672
643static int asus_led_init(struct asus_laptop *asus) 673static int asus_led_init(struct asus_laptop *asus)
644{ 674{
645 int r; 675 int r = 0;
646 676
647 /* 677 /*
648 * The Pegatron Lucid has no physical leds, but all methods are 678 * The Pegatron Lucid has no physical leds, but all methods are
@@ -661,6 +691,16 @@ static int asus_led_init(struct asus_laptop *asus)
661 if (!asus->led_workqueue) 691 if (!asus->led_workqueue)
662 return -ENOMEM; 692 return -ENOMEM;
663 693
694 if (asus->wled_type == TYPE_LED)
695 r = asus_led_register(asus, &asus->wled, "asus::wlan",
696 METHOD_WLAN);
697 if (r)
698 goto error;
699 if (asus->bled_type == TYPE_LED)
700 r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
701 METHOD_BLUETOOTH);
702 if (r)
703 goto error;
664 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED); 704 r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
665 if (r) 705 if (r)
666 goto error; 706 goto error;
@@ -963,7 +1003,7 @@ static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
963 return sysfs_acpi_set(asus, buf, count, METHOD_WLAN); 1003 return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
964} 1004}
965 1005
966/* 1006/*e
967 * Bluetooth 1007 * Bluetooth
968 */ 1008 */
969static int asus_bluetooth_set(struct asus_laptop *asus, int status) 1009static int asus_bluetooth_set(struct asus_laptop *asus, int status)
@@ -1228,7 +1268,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
1228 ret = asus_gps_switch(asus, !!value); 1268 ret = asus_gps_switch(asus, !!value);
1229 if (ret) 1269 if (ret)
1230 return ret; 1270 return ret;
1231 rfkill_set_sw_state(asus->gps_rfkill, !value); 1271 rfkill_set_sw_state(asus->gps.rfkill, !value);
1232 return rv; 1272 return rv;
1233} 1273}
1234 1274
@@ -1246,90 +1286,139 @@ static const struct rfkill_ops asus_gps_rfkill_ops = {
1246 .set_block = asus_gps_rfkill_set, 1286 .set_block = asus_gps_rfkill_set,
1247}; 1287};
1248 1288
1289static int asus_rfkill_set(void *data, bool blocked)
1290{
1291 struct asus_rfkill *rfk = data;
1292 struct asus_laptop *asus = rfk->asus;
1293
1294 if (rfk->control_id == WL_RSTS)
1295 return asus_wlan_set(asus, !blocked);
1296 else if (rfk->control_id == BT_RSTS)
1297 return asus_bluetooth_set(asus, !blocked);
1298 else if (rfk->control_id == WM_RSTS)
1299 return asus_wimax_set(asus, !blocked);
1300 else if (rfk->control_id == WW_RSTS)
1301 return asus_wwan_set(asus, !blocked);
1302
1303 return -EINVAL;
1304}
1305
1306static const struct rfkill_ops asus_rfkill_ops = {
1307 .set_block = asus_rfkill_set,
1308};
1309
1310static void asus_rfkill_terminate(struct asus_rfkill *rfk)
1311{
1312 if (!rfk->rfkill)
1313 return ;
1314
1315 rfkill_unregister(rfk->rfkill);
1316 rfkill_destroy(rfk->rfkill);
1317 rfk->rfkill = NULL;
1318}
1319
1249static void asus_rfkill_exit(struct asus_laptop *asus) 1320static void asus_rfkill_exit(struct asus_laptop *asus)
1250{ 1321{
1251 if (asus->gps_rfkill) { 1322 asus_rfkill_terminate(&asus->wwan);
1252 rfkill_unregister(asus->gps_rfkill); 1323 asus_rfkill_terminate(&asus->bluetooth);
1253 rfkill_destroy(asus->gps_rfkill); 1324 asus_rfkill_terminate(&asus->wlan);
1254 asus->gps_rfkill = NULL; 1325 asus_rfkill_terminate(&asus->gps);
1255 }
1256} 1326}
1257 1327
1258static int asus_rfkill_init(struct asus_laptop *asus) 1328static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
1329 const char *name, int control_id, int type,
1330 const struct rfkill_ops *ops)
1259{ 1331{
1260 int result; 1332 int result;
1261 1333
1262 if (acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) || 1334 rfk->control_id = control_id;
1263 acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) || 1335 rfk->asus = asus;
1264 acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL)) 1336 rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
1265 return 0; 1337 type, ops, rfk);
1266 1338 if (!rfk->rfkill)
1267 asus->gps_rfkill = rfkill_alloc("asus-gps", &asus->platform_device->dev,
1268 RFKILL_TYPE_GPS,
1269 &asus_gps_rfkill_ops, asus);
1270 if (!asus->gps_rfkill)
1271 return -EINVAL; 1339 return -EINVAL;
1272 1340
1273 result = rfkill_register(asus->gps_rfkill); 1341 result = rfkill_register(rfk->rfkill);
1274 if (result) { 1342 if (result) {
1275 rfkill_destroy(asus->gps_rfkill); 1343 rfkill_destroy(rfk->rfkill);
1276 asus->gps_rfkill = NULL; 1344 rfk->rfkill = NULL;
1277 } 1345 }
1278 1346
1279 return result; 1347 return result;
1280} 1348}
1281 1349
1282static int pega_rfkill_set(void *data, bool blocked) 1350static int asus_rfkill_init(struct asus_laptop *asus)
1283{ 1351{
1284 struct asus_pega_rfkill *pega_rfk = data; 1352 int result = 0;
1285 1353
1286 int ret = asus_pega_lucid_set(pega_rfk->asus, pega_rfk->control_id, !blocked); 1354 if (asus->is_pega_lucid)
1287 pr_warn("Setting rfkill %d, to %d; returned %d\n", pega_rfk->control_id, !blocked, ret); 1355 return -ENODEV;
1288 1356
1289 return ret; 1357 if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
1290} 1358 !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
1359 !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
1360 result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
1361 -1, RFKILL_TYPE_GPS,
1362 &asus_gps_rfkill_ops);
1363 if (result)
1364 goto exit;
1291 1365
1292static const struct rfkill_ops pega_rfkill_ops = {
1293 .set_block = pega_rfkill_set,
1294};
1295 1366
1296static void pega_rfkill_terminate(struct asus_pega_rfkill *pega_rfk) 1367 if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
1297{ 1368 asus->wled_type == TYPE_RFKILL)
1298 pr_warn("Terminating %d\n", pega_rfk->control_id); 1369 result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
1299 if (pega_rfk->rfkill) { 1370 WL_RSTS, RFKILL_TYPE_WLAN,
1300 rfkill_unregister(pega_rfk->rfkill); 1371 &asus_rfkill_ops);
1301 rfkill_destroy(pega_rfk->rfkill); 1372 if (result)
1302 pega_rfk->rfkill = NULL; 1373 goto exit;
1303 }
1304}
1305 1374
1306static void pega_rfkill_exit(struct asus_laptop *asus) 1375 if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
1307{ 1376 asus->bled_type == TYPE_RFKILL)
1308 pega_rfkill_terminate(&asus->wwanrfk); 1377 result = asus_rfkill_setup(asus, &asus->bluetooth,
1309 pega_rfkill_terminate(&asus->btrfk); 1378 "asus-bluetooth", BT_RSTS,
1310 pega_rfkill_terminate(&asus->wlanrfk); 1379 RFKILL_TYPE_BLUETOOTH,
1380 &asus_rfkill_ops);
1381 if (result)
1382 goto exit;
1383
1384 if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
1385 result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
1386 WW_RSTS, RFKILL_TYPE_WWAN,
1387 &asus_rfkill_ops);
1388 if (result)
1389 goto exit;
1390
1391 if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
1392 result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
1393 WM_RSTS, RFKILL_TYPE_WIMAX,
1394 &asus_rfkill_ops);
1395 if (result)
1396 goto exit;
1397
1398exit:
1399 if (result)
1400 asus_rfkill_exit(asus);
1401
1402 return result;
1311} 1403}
1312 1404
1313static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_pega_rfkill *pega_rfk, 1405static int pega_rfkill_set(void *data, bool blocked)
1314 const char *name, int controlid, int rfkill_type)
1315{ 1406{
1316 int result; 1407 struct asus_rfkill *rfk = data;
1317 1408
1318 pr_warn("Setting up rfk %s, control %d, type %d\n", name, controlid, rfkill_type); 1409 int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
1319 pega_rfk->control_id = controlid; 1410 return ret;
1320 pega_rfk->asus = asus; 1411}
1321 pega_rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
1322 rfkill_type, &pega_rfkill_ops, pega_rfk);
1323 if (!pega_rfk->rfkill)
1324 return -EINVAL;
1325 1412
1326 result = rfkill_register(pega_rfk->rfkill); 1413static const struct rfkill_ops pega_rfkill_ops = {
1327 if (result) { 1414 .set_block = pega_rfkill_set,
1328 rfkill_destroy(pega_rfk->rfkill); 1415};
1329 pega_rfk->rfkill = NULL;
1330 }
1331 1416
1332 return result; 1417static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
1418 const char *name, int controlid, int rfkill_type)
1419{
1420 return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
1421 &pega_rfkill_ops);
1333} 1422}
1334 1423
1335static int pega_rfkill_init(struct asus_laptop *asus) 1424static int pega_rfkill_init(struct asus_laptop *asus)
@@ -1339,22 +1428,22 @@ static int pega_rfkill_init(struct asus_laptop *asus)
1339 if(!asus->is_pega_lucid) 1428 if(!asus->is_pega_lucid)
1340 return -ENODEV; 1429 return -ENODEV;
1341 1430
1342 ret = pega_rfkill_setup(asus, &asus->wlanrfk, "pega-wlan", PEGA_WLAN, RFKILL_TYPE_WLAN); 1431 ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
1343 if(ret) 1432 PEGA_WLAN, RFKILL_TYPE_WLAN);
1344 return ret;
1345 ret = pega_rfkill_setup(asus, &asus->btrfk, "pega-bt", PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
1346 if(ret) 1433 if(ret)
1347 goto err_btrfk; 1434 goto exit;
1348 ret = pega_rfkill_setup(asus, &asus->wwanrfk, "pega-wwan", PEGA_WWAN, RFKILL_TYPE_WWAN); 1435
1436 ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
1437 PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
1349 if(ret) 1438 if(ret)
1350 goto err_wwanrfk; 1439 goto exit;
1351 1440
1352 pr_warn("Pega rfkill init succeeded\n"); 1441 ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
1353 return 0; 1442 PEGA_WWAN, RFKILL_TYPE_WWAN);
1354err_wwanrfk: 1443
1355 pega_rfkill_terminate(&asus->btrfk); 1444exit:
1356err_btrfk: 1445 if (ret)
1357 pega_rfkill_terminate(&asus->wlanrfk); 1446 asus_rfkill_exit(asus);
1358 1447
1359 return ret; 1448 return ret;
1360} 1449}
@@ -1364,8 +1453,10 @@ err_btrfk:
1364 */ 1453 */
1365static void asus_input_notify(struct asus_laptop *asus, int event) 1454static void asus_input_notify(struct asus_laptop *asus, int event)
1366{ 1455{
1367 if (asus->inputdev) 1456 if (!asus->inputdev)
1368 sparse_keymap_report_event(asus->inputdev, event, 1, true); 1457 return ;
1458 if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
1459 pr_info("Unknown key %x pressed\n", event);
1369} 1460}
1370 1461
1371static int asus_input_init(struct asus_laptop *asus) 1462static int asus_input_init(struct asus_laptop *asus)
@@ -1375,7 +1466,7 @@ static int asus_input_init(struct asus_laptop *asus)
1375 1466
1376 input = input_allocate_device(); 1467 input = input_allocate_device();
1377 if (!input) { 1468 if (!input) {
1378 pr_info("Unable to allocate input device\n"); 1469 pr_warn("Unable to allocate input device\n");
1379 return -ENOMEM; 1470 return -ENOMEM;
1380 } 1471 }
1381 input->name = "Asus Laptop extra buttons"; 1472 input->name = "Asus Laptop extra buttons";
@@ -1390,7 +1481,7 @@ static int asus_input_init(struct asus_laptop *asus)
1390 } 1481 }
1391 error = input_register_device(input); 1482 error = input_register_device(input);
1392 if (error) { 1483 if (error) {
1393 pr_info("Unable to register input device\n"); 1484 pr_warn("Unable to register input device\n");
1394 goto err_free_keymap; 1485 goto err_free_keymap;
1395 } 1486 }
1396 1487
@@ -1688,7 +1779,16 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
1688 if (result) 1779 if (result)
1689 return result; 1780 return result;
1690 1781
1691 /* WLED and BLED are on by default */ 1782 if (!strcmp(bled_type, "led"))
1783 asus->bled_type = TYPE_LED;
1784 else if (!strcmp(bled_type, "rfkill"))
1785 asus->bled_type = TYPE_RFKILL;
1786
1787 if (!strcmp(wled_type, "led"))
1788 asus->wled_type = TYPE_LED;
1789 else if (!strcmp(wled_type, "rfkill"))
1790 asus->wled_type = TYPE_RFKILL;
1791
1692 if (bluetooth_status >= 0) 1792 if (bluetooth_status >= 0)
1693 asus_bluetooth_set(asus, !!bluetooth_status); 1793 asus_bluetooth_set(asus, !!bluetooth_status);
1694 1794
@@ -1786,7 +1886,7 @@ static int __devinit asus_acpi_add(struct acpi_device *device)
1786 goto fail_led; 1886 goto fail_led;
1787 1887
1788 result = asus_rfkill_init(asus); 1888 result = asus_rfkill_init(asus);
1789 if (result) 1889 if (result && result != -ENODEV)
1790 goto fail_rfkill; 1890 goto fail_rfkill;
1791 1891
1792 result = pega_accel_init(asus); 1892 result = pega_accel_init(asus);
@@ -1828,7 +1928,6 @@ static int asus_acpi_remove(struct acpi_device *device, int type)
1828 asus_led_exit(asus); 1928 asus_led_exit(asus);
1829 asus_input_exit(asus); 1929 asus_input_exit(asus);
1830 pega_accel_exit(asus); 1930 pega_accel_exit(asus);
1831 pega_rfkill_exit(asus);
1832 asus_platform_exit(asus); 1931 asus_platform_exit(asus);
1833 1932
1834 kfree(asus->name); 1933 kfree(asus->name);
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index b0859d4183e8..99a30b513137 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -25,6 +25,7 @@
25#include <linux/init.h> 25#include <linux/init.h>
26#include <linux/input.h> 26#include <linux/input.h>
27#include <linux/input/sparse-keymap.h> 27#include <linux/input/sparse-keymap.h>
28#include <linux/fb.h>
28 29
29#include "asus-wmi.h" 30#include "asus-wmi.h"
30 31
@@ -51,9 +52,14 @@ static uint wapf;
51module_param(wapf, uint, 0444); 52module_param(wapf, uint, 0444);
52MODULE_PARM_DESC(wapf, "WAPF value"); 53MODULE_PARM_DESC(wapf, "WAPF value");
53 54
55static struct quirk_entry quirk_asus_unknown = {
56};
57
54static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver) 58static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
55{ 59{
56 driver->wapf = wapf; 60 driver->quirks = &quirk_asus_unknown;
61 driver->quirks->wapf = wapf;
62 driver->panel_power = FB_BLANK_UNBLANK;
57} 63}
58 64
59static const struct key_entry asus_nb_wmi_keymap[] = { 65static const struct key_entry asus_nb_wmi_keymap[] = {
@@ -70,6 +76,8 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
70 { KE_KEY, 0x50, { KEY_EMAIL } }, 76 { KE_KEY, 0x50, { KEY_EMAIL } },
71 { KE_KEY, 0x51, { KEY_WWW } }, 77 { KE_KEY, 0x51, { KEY_WWW } },
72 { KE_KEY, 0x55, { KEY_CALC } }, 78 { KE_KEY, 0x55, { KEY_CALC } },
79 { KE_IGNORE, 0x57, }, /* Battery mode */
80 { KE_IGNORE, 0x58, }, /* AC mode */
73 { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ 81 { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */
74 { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */ 82 { KE_KEY, 0x5D, { KEY_WLAN } }, /* Wireless console Toggle */
75 { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */ 83 { KE_KEY, 0x5E, { KEY_WLAN } }, /* Wireless console Enable */
@@ -99,7 +107,7 @@ static struct asus_wmi_driver asus_nb_wmi_driver = {
99 .keymap = asus_nb_wmi_keymap, 107 .keymap = asus_nb_wmi_keymap,
100 .input_name = "Asus WMI hotkeys", 108 .input_name = "Asus WMI hotkeys",
101 .input_phys = ASUS_NB_WMI_FILE "/input0", 109 .input_phys = ASUS_NB_WMI_FILE "/input0",
102 .quirks = asus_nb_wmi_quirks, 110 .detect_quirks = asus_nb_wmi_quirks,
103}; 111};
104 112
105 113
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 72d731c21d45..77aadde5281c 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -411,7 +411,7 @@ static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
411 411
412 if (retval >= 0) { 412 if (retval >= 0) {
413 if (level) 413 if (level)
414 *level = retval & 0x80 ? retval & 0x7F : 0; 414 *level = retval & 0x7F;
415 if (env) 415 if (env)
416 *env = (retval >> 8) & 0x7F; 416 *env = (retval >> 8) & 0x7F;
417 retval = 0; 417 retval = 0;
@@ -571,7 +571,7 @@ static void asus_rfkill_hotplug(struct asus_wmi *asus)
571 } else { 571 } else {
572 dev = pci_get_slot(bus, 0); 572 dev = pci_get_slot(bus, 0);
573 if (dev) { 573 if (dev) {
574 pci_remove_bus_device(dev); 574 pci_stop_and_remove_bus_device(dev);
575 pci_dev_put(dev); 575 pci_dev_put(dev);
576 } 576 }
577 } 577 }
@@ -784,7 +784,8 @@ static int asus_new_rfkill(struct asus_wmi *asus,
784 arfkill->dev_id = dev_id; 784 arfkill->dev_id = dev_id;
785 arfkill->asus = asus; 785 arfkill->asus = asus;
786 786
787 if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless) 787 if (dev_id == ASUS_WMI_DEVID_WLAN &&
788 asus->driver->quirks->hotplug_wireless)
788 *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, 789 *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
789 &asus_rfkill_wlan_ops, arfkill); 790 &asus_rfkill_wlan_ops, arfkill);
790 else 791 else
@@ -895,7 +896,7 @@ static int asus_wmi_rfkill_init(struct asus_wmi *asus)
895 if (result && result != -ENODEV) 896 if (result && result != -ENODEV)
896 goto exit; 897 goto exit;
897 898
898 if (!asus->driver->hotplug_wireless) 899 if (!asus->driver->quirks->hotplug_wireless)
899 goto exit; 900 goto exit;
900 901
901 result = asus_setup_pci_hotplug(asus); 902 result = asus_setup_pci_hotplug(asus);
@@ -1075,7 +1076,12 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
1075 */ 1076 */
1076static int read_backlight_power(struct asus_wmi *asus) 1077static int read_backlight_power(struct asus_wmi *asus)
1077{ 1078{
1078 int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT); 1079 int ret;
1080 if (asus->driver->quirks->store_backlight_power)
1081 ret = !asus->driver->panel_power;
1082 else
1083 ret = asus_wmi_get_devstate_simple(asus,
1084 ASUS_WMI_DEVID_BACKLIGHT);
1079 1085
1080 if (ret < 0) 1086 if (ret < 0)
1081 return ret; 1087 return ret;
@@ -1116,26 +1122,51 @@ static int read_brightness(struct backlight_device *bd)
1116 return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; 1122 return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
1117} 1123}
1118 1124
1119static int update_bl_status(struct backlight_device *bd) 1125static u32 get_scalar_command(struct backlight_device *bd)
1120{ 1126{
1121 struct asus_wmi *asus = bl_get_data(bd); 1127 struct asus_wmi *asus = bl_get_data(bd);
1122 u32 ctrl_param; 1128 u32 ctrl_param = 0;
1123 int power, err;
1124 1129
1125 ctrl_param = bd->props.brightness; 1130 if ((asus->driver->brightness < bd->props.brightness) ||
1131 bd->props.brightness == bd->props.max_brightness)
1132 ctrl_param = 0x00008001;
1133 else if ((asus->driver->brightness > bd->props.brightness) ||
1134 bd->props.brightness == 0)
1135 ctrl_param = 0x00008000;
1126 1136
1127 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, 1137 asus->driver->brightness = bd->props.brightness;
1128 ctrl_param, NULL);
1129 1138
1130 if (err < 0) 1139 return ctrl_param;
1131 return err; 1140}
1141
1142static int update_bl_status(struct backlight_device *bd)
1143{
1144 struct asus_wmi *asus = bl_get_data(bd);
1145 u32 ctrl_param;
1146 int power, err = 0;
1132 1147
1133 power = read_backlight_power(asus); 1148 power = read_backlight_power(asus);
1134 if (power != -ENODEV && bd->props.power != power) { 1149 if (power != -ENODEV && bd->props.power != power) {
1135 ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); 1150 ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
1136 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 1151 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
1137 ctrl_param, NULL); 1152 ctrl_param, NULL);
1153 if (asus->driver->quirks->store_backlight_power)
1154 asus->driver->panel_power = bd->props.power;
1155
1156 /* When using scalar brightness, updating the brightness
1157 * will mess with the backlight power */
1158 if (asus->driver->quirks->scalar_panel_brightness)
1159 return err;
1138 } 1160 }
1161
1162 if (asus->driver->quirks->scalar_panel_brightness)
1163 ctrl_param = get_scalar_command(bd);
1164 else
1165 ctrl_param = bd->props.brightness;
1166
1167 err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
1168 ctrl_param, NULL);
1169
1139 return err; 1170 return err;
1140} 1171}
1141 1172
@@ -1196,10 +1227,15 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
1196 1227
1197 asus->backlight_device = bd; 1228 asus->backlight_device = bd;
1198 1229
1230 if (asus->driver->quirks->store_backlight_power)
1231 asus->driver->panel_power = power;
1232
1199 bd->props.brightness = read_brightness(bd); 1233 bd->props.brightness = read_brightness(bd);
1200 bd->props.power = power; 1234 bd->props.power = power;
1201 backlight_update_status(bd); 1235 backlight_update_status(bd);
1202 1236
1237 asus->driver->brightness = bd->props.brightness;
1238
1203 return 0; 1239 return 0;
1204} 1240}
1205 1241
@@ -1441,9 +1477,9 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
1441 1477
1442 /* CWAP allow to define the behavior of the Fn+F2 key, 1478 /* CWAP allow to define the behavior of the Fn+F2 key,
1443 * this method doesn't seems to be present on Eee PCs */ 1479 * this method doesn't seems to be present on Eee PCs */
1444 if (asus->driver->wapf >= 0) 1480 if (asus->driver->quirks->wapf >= 0)
1445 asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP, 1481 asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
1446 asus->driver->wapf, NULL); 1482 asus->driver->quirks->wapf, NULL);
1447 1483
1448 return asus_wmi_sysfs_init(asus->platform_device); 1484 return asus_wmi_sysfs_init(asus->platform_device);
1449} 1485}
@@ -1622,8 +1658,8 @@ static int asus_wmi_add(struct platform_device *pdev)
1622 wdrv->platform_device = pdev; 1658 wdrv->platform_device = pdev;
1623 platform_set_drvdata(asus->platform_device, asus); 1659 platform_set_drvdata(asus->platform_device, asus);
1624 1660
1625 if (wdrv->quirks) 1661 if (wdrv->detect_quirks)
1626 wdrv->quirks(asus->driver); 1662 wdrv->detect_quirks(asus->driver);
1627 1663
1628 err = asus_wmi_platform_init(asus); 1664 err = asus_wmi_platform_init(asus);
1629 if (err) 1665 if (err)
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 8147c10161cc..d43b66742004 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -35,9 +35,16 @@ struct module;
35struct key_entry; 35struct key_entry;
36struct asus_wmi; 36struct asus_wmi;
37 37
38struct quirk_entry {
39 bool hotplug_wireless;
40 bool scalar_panel_brightness;
41 bool store_backlight_power;
42 int wapf;
43};
44
38struct asus_wmi_driver { 45struct asus_wmi_driver {
39 bool hotplug_wireless; 46 int brightness;
40 int wapf; 47 int panel_power;
41 48
42 const char *name; 49 const char *name;
43 struct module *owner; 50 struct module *owner;
@@ -47,13 +54,14 @@ struct asus_wmi_driver {
47 const struct key_entry *keymap; 54 const struct key_entry *keymap;
48 const char *input_name; 55 const char *input_name;
49 const char *input_phys; 56 const char *input_phys;
57 struct quirk_entry *quirks;
50 /* Returns new code, value, and autorelease values in arguments. 58 /* Returns new code, value, and autorelease values in arguments.
51 * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */ 59 * Return ASUS_WMI_KEY_IGNORE in code if event should be ignored. */
52 void (*key_filter) (struct asus_wmi_driver *driver, int *code, 60 void (*key_filter) (struct asus_wmi_driver *driver, int *code,
53 unsigned int *value, bool *autorelease); 61 unsigned int *value, bool *autorelease);
54 62
55 int (*probe) (struct platform_device *device); 63 int (*probe) (struct platform_device *device);
56 void (*quirks) (struct asus_wmi_driver *driver); 64 void (*detect_quirks) (struct asus_wmi_driver *driver);
57 65
58 struct platform_driver platform_driver; 66 struct platform_driver platform_driver;
59 struct platform_device *platform_device; 67 struct platform_device *platform_device;
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
deleted file mode 100644
index 6f966d6c062b..000000000000
--- a/drivers/platform/x86/asus_acpi.c
+++ /dev/null
@@ -1,1513 +0,0 @@
1/*
2 * asus_acpi.c - Asus Laptop ACPI Extras
3 *
4 *
5 * Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
6 *
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
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 *
22 * The development page for this driver is located at
23 * http://sourceforge.net/projects/acpi4asus/
24 *
25 * Credits:
26 * Pontus Fuchs - Helper functions, cleanup
27 * Johann Wiesner - Small compile fixes
28 * John Belmonte - ACPI code for Toshiba laptop was a good starting point.
29 * �ic Burghard - LED display support for W1N
30 *
31 */
32
33#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34
35#include <linux/kernel.h>
36#include <linux/module.h>
37#include <linux/slab.h>
38#include <linux/init.h>
39#include <linux/types.h>
40#include <linux/proc_fs.h>
41#include <linux/seq_file.h>
42#include <linux/backlight.h>
43#include <acpi/acpi_drivers.h>
44#include <acpi/acpi_bus.h>
45#include <asm/uaccess.h>
46
47#define ASUS_ACPI_VERSION "0.30"
48
49#define PROC_ASUS "asus" /* The directory */
50#define PROC_MLED "mled"
51#define PROC_WLED "wled"
52#define PROC_TLED "tled"
53#define PROC_BT "bluetooth"
54#define PROC_LEDD "ledd"
55#define PROC_INFO "info"
56#define PROC_LCD "lcd"
57#define PROC_BRN "brn"
58#define PROC_DISP "disp"
59
60#define ACPI_HOTK_NAME "Asus Laptop ACPI Extras Driver"
61#define ACPI_HOTK_CLASS "hotkey"
62#define ACPI_HOTK_DEVICE_NAME "Hotkey"
63
64/*
65 * Some events we use, same for all Asus
66 */
67#define BR_UP 0x10
68#define BR_DOWN 0x20
69
70/*
71 * Flags for hotk status
72 */
73#define MLED_ON 0x01 /* Mail LED */
74#define WLED_ON 0x02 /* Wireless LED */
75#define TLED_ON 0x04 /* Touchpad LED */
76#define BT_ON 0x08 /* Internal Bluetooth */
77
78MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
79MODULE_DESCRIPTION(ACPI_HOTK_NAME);
80MODULE_LICENSE("GPL");
81
82static uid_t asus_uid;
83static gid_t asus_gid;
84module_param(asus_uid, uint, 0);
85MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
86module_param(asus_gid, uint, 0);
87MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
88
89/* For each model, all features implemented,
90 * those marked with R are relative to HOTK, A for absolute */
91struct model_data {
92 char *name; /* name of the laptop________________A */
93 char *mt_mled; /* method to handle mled_____________R */
94 char *mled_status; /* node to handle mled reading_______A */
95 char *mt_wled; /* method to handle wled_____________R */
96 char *wled_status; /* node to handle wled reading_______A */
97 char *mt_tled; /* method to handle tled_____________R */
98 char *tled_status; /* node to handle tled reading_______A */
99 char *mt_ledd; /* method to handle LED display______R */
100 char *mt_bt_switch; /* method to switch Bluetooth on/off_R */
101 char *bt_status; /* no model currently supports this__? */
102 char *mt_lcd_switch; /* method to turn LCD on/off_________A */
103 char *lcd_status; /* node to read LCD panel state______A */
104 char *brightness_up; /* method to set brightness up_______A */
105 char *brightness_down; /* method to set brightness down ____A */
106 char *brightness_set; /* method to set absolute brightness_R */
107 char *brightness_get; /* method to get absolute brightness_R */
108 char *brightness_status;/* node to get brightness____________A */
109 char *display_set; /* method to set video output________R */
110 char *display_get; /* method to get video output________R */
111};
112
113/*
114 * This is the main structure, we can use it to store anything interesting
115 * about the hotk device
116 */
117struct asus_hotk {
118 struct acpi_device *device; /* the device we are in */
119 acpi_handle handle; /* the handle of the hotk device */
120 char status; /* status of the hotk, for LEDs */
121 u32 ledd_status; /* status of the LED display */
122 struct model_data *methods; /* methods available on the laptop */
123 u8 brightness; /* brightness level */
124 enum {
125 A1x = 0, /* A1340D, A1300F */
126 A2x, /* A2500H */
127 A4G, /* A4700G */
128 D1x, /* D1 */
129 L2D, /* L2000D */
130 L3C, /* L3800C */
131 L3D, /* L3400D */
132 L3H, /* L3H, L2000E, L5D */
133 L4R, /* L4500R */
134 L5x, /* L5800C */
135 L8L, /* L8400L */
136 M1A, /* M1300A */
137 M2E, /* M2400E, L4400L */
138 M6N, /* M6800N, W3400N */
139 M6R, /* M6700R, A3000G */
140 P30, /* Samsung P30 */
141 S1x, /* S1300A, but also L1400B and M2400A (L84F) */
142 S2x, /* S200 (J1 reported), Victor MP-XP7210 */
143 W1N, /* W1000N */
144 W5A, /* W5A */
145 W3V, /* W3030V */
146 xxN, /* M2400N, M3700N, M5200N, M6800N,
147 S1300N, S5200N*/
148 A4S, /* Z81sp */
149 F3Sa, /* (Centrino) */
150 R1F,
151 END_MODEL
152 } model; /* Models currently supported */
153 u16 event_count[128]; /* Count for each event TODO make this better */
154};
155
156/* Here we go */
157#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
158#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
159#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
160#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
161#define S1x_PREFIX "\\_SB.PCI0.PX40."
162#define S2x_PREFIX A1x_PREFIX
163#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
164
165static struct model_data model_conf[END_MODEL] = {
166 /*
167 * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
168 * it seems to be a kind of switch, but what for ?
169 */
170
171 {
172 .name = "A1x",
173 .mt_mled = "MLED",
174 .mled_status = "\\MAIL",
175 .mt_lcd_switch = A1x_PREFIX "_Q10",
176 .lcd_status = "\\BKLI",
177 .brightness_up = A1x_PREFIX "_Q0E",
178 .brightness_down = A1x_PREFIX "_Q0F"},
179
180 {
181 .name = "A2x",
182 .mt_mled = "MLED",
183 .mt_wled = "WLED",
184 .wled_status = "\\SG66",
185 .mt_lcd_switch = "\\Q10",
186 .lcd_status = "\\BAOF",
187 .brightness_set = "SPLV",
188 .brightness_get = "GPLV",
189 .display_set = "SDSP",
190 .display_get = "\\INFB"},
191
192 {
193 .name = "A4G",
194 .mt_mled = "MLED",
195/* WLED present, but not controlled by ACPI */
196 .mt_lcd_switch = xxN_PREFIX "_Q10",
197 .brightness_set = "SPLV",
198 .brightness_get = "GPLV",
199 .display_set = "SDSP",
200 .display_get = "\\ADVG"},
201
202 {
203 .name = "D1x",
204 .mt_mled = "MLED",
205 .mt_lcd_switch = "\\Q0D",
206 .lcd_status = "\\GP11",
207 .brightness_up = "\\Q0C",
208 .brightness_down = "\\Q0B",
209 .brightness_status = "\\BLVL",
210 .display_set = "SDSP",
211 .display_get = "\\INFB"},
212
213 {
214 .name = "L2D",
215 .mt_mled = "MLED",
216 .mled_status = "\\SGP6",
217 .mt_wled = "WLED",
218 .wled_status = "\\RCP3",
219 .mt_lcd_switch = "\\Q10",
220 .lcd_status = "\\SGP0",
221 .brightness_up = "\\Q0E",
222 .brightness_down = "\\Q0F",
223 .display_set = "SDSP",
224 .display_get = "\\INFB"},
225
226 {
227 .name = "L3C",
228 .mt_mled = "MLED",
229 .mt_wled = "WLED",
230 .mt_lcd_switch = L3C_PREFIX "_Q10",
231 .lcd_status = "\\GL32",
232 .brightness_set = "SPLV",
233 .brightness_get = "GPLV",
234 .display_set = "SDSP",
235 .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP"},
236
237 {
238 .name = "L3D",
239 .mt_mled = "MLED",
240 .mled_status = "\\MALD",
241 .mt_wled = "WLED",
242 .mt_lcd_switch = "\\Q10",
243 .lcd_status = "\\BKLG",
244 .brightness_set = "SPLV",
245 .brightness_get = "GPLV",
246 .display_set = "SDSP",
247 .display_get = "\\INFB"},
248
249 {
250 .name = "L3H",
251 .mt_mled = "MLED",
252 .mt_wled = "WLED",
253 .mt_lcd_switch = "EHK",
254 .lcd_status = "\\_SB.PCI0.PM.PBC",
255 .brightness_set = "SPLV",
256 .brightness_get = "GPLV",
257 .display_set = "SDSP",
258 .display_get = "\\INFB"},
259
260 {
261 .name = "L4R",
262 .mt_mled = "MLED",
263 .mt_wled = "WLED",
264 .wled_status = "\\_SB.PCI0.SBRG.SG13",
265 .mt_lcd_switch = xxN_PREFIX "_Q10",
266 .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
267 .brightness_set = "SPLV",
268 .brightness_get = "GPLV",
269 .display_set = "SDSP",
270 .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
271
272 {
273 .name = "L5x",
274 .mt_mled = "MLED",
275/* WLED present, but not controlled by ACPI */
276 .mt_tled = "TLED",
277 .mt_lcd_switch = "\\Q0D",
278 .lcd_status = "\\BAOF",
279 .brightness_set = "SPLV",
280 .brightness_get = "GPLV",
281 .display_set = "SDSP",
282 .display_get = "\\INFB"},
283
284 {
285 .name = "L8L"
286/* No features, but at least support the hotkeys */
287 },
288
289 {
290 .name = "M1A",
291 .mt_mled = "MLED",
292 .mt_lcd_switch = M1A_PREFIX "Q10",
293 .lcd_status = "\\PNOF",
294 .brightness_up = M1A_PREFIX "Q0E",
295 .brightness_down = M1A_PREFIX "Q0F",
296 .brightness_status = "\\BRIT",
297 .display_set = "SDSP",
298 .display_get = "\\INFB"},
299
300 {
301 .name = "M2E",
302 .mt_mled = "MLED",
303 .mt_wled = "WLED",
304 .mt_lcd_switch = "\\Q10",
305 .lcd_status = "\\GP06",
306 .brightness_set = "SPLV",
307 .brightness_get = "GPLV",
308 .display_set = "SDSP",
309 .display_get = "\\INFB"},
310
311 {
312 .name = "M6N",
313 .mt_mled = "MLED",
314 .mt_wled = "WLED",
315 .wled_status = "\\_SB.PCI0.SBRG.SG13",
316 .mt_lcd_switch = xxN_PREFIX "_Q10",
317 .lcd_status = "\\_SB.BKLT",
318 .brightness_set = "SPLV",
319 .brightness_get = "GPLV",
320 .display_set = "SDSP",
321 .display_get = "\\SSTE"},
322
323 {
324 .name = "M6R",
325 .mt_mled = "MLED",
326 .mt_wled = "WLED",
327 .mt_lcd_switch = xxN_PREFIX "_Q10",
328 .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
329 .brightness_set = "SPLV",
330 .brightness_get = "GPLV",
331 .display_set = "SDSP",
332 .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
333
334 {
335 .name = "P30",
336 .mt_wled = "WLED",
337 .mt_lcd_switch = P30_PREFIX "_Q0E",
338 .lcd_status = "\\BKLT",
339 .brightness_up = P30_PREFIX "_Q68",
340 .brightness_down = P30_PREFIX "_Q69",
341 .brightness_get = "GPLV",
342 .display_set = "SDSP",
343 .display_get = "\\DNXT"},
344
345 {
346 .name = "S1x",
347 .mt_mled = "MLED",
348 .mled_status = "\\EMLE",
349 .mt_wled = "WLED",
350 .mt_lcd_switch = S1x_PREFIX "Q10",
351 .lcd_status = "\\PNOF",
352 .brightness_set = "SPLV",
353 .brightness_get = "GPLV"},
354
355 {
356 .name = "S2x",
357 .mt_mled = "MLED",
358 .mled_status = "\\MAIL",
359 .mt_lcd_switch = S2x_PREFIX "_Q10",
360 .lcd_status = "\\BKLI",
361 .brightness_up = S2x_PREFIX "_Q0B",
362 .brightness_down = S2x_PREFIX "_Q0A"},
363
364 {
365 .name = "W1N",
366 .mt_mled = "MLED",
367 .mt_wled = "WLED",
368 .mt_ledd = "SLCM",
369 .mt_lcd_switch = xxN_PREFIX "_Q10",
370 .lcd_status = "\\BKLT",
371 .brightness_set = "SPLV",
372 .brightness_get = "GPLV",
373 .display_set = "SDSP",
374 .display_get = "\\ADVG"},
375
376 {
377 .name = "W5A",
378 .mt_bt_switch = "BLED",
379 .mt_wled = "WLED",
380 .mt_lcd_switch = xxN_PREFIX "_Q10",
381 .brightness_set = "SPLV",
382 .brightness_get = "GPLV",
383 .display_set = "SDSP",
384 .display_get = "\\ADVG"},
385
386 {
387 .name = "W3V",
388 .mt_mled = "MLED",
389 .mt_wled = "WLED",
390 .mt_lcd_switch = xxN_PREFIX "_Q10",
391 .lcd_status = "\\BKLT",
392 .brightness_set = "SPLV",
393 .brightness_get = "GPLV",
394 .display_set = "SDSP",
395 .display_get = "\\INFB"},
396
397 {
398 .name = "xxN",
399 .mt_mled = "MLED",
400/* WLED present, but not controlled by ACPI */
401 .mt_lcd_switch = xxN_PREFIX "_Q10",
402 .lcd_status = "\\BKLT",
403 .brightness_set = "SPLV",
404 .brightness_get = "GPLV",
405 .display_set = "SDSP",
406 .display_get = "\\ADVG"},
407
408 {
409 .name = "A4S",
410 .brightness_set = "SPLV",
411 .brightness_get = "GPLV",
412 .mt_bt_switch = "BLED",
413 .mt_wled = "WLED"
414 },
415
416 {
417 .name = "F3Sa",
418 .mt_bt_switch = "BLED",
419 .mt_wled = "WLED",
420 .mt_mled = "MLED",
421 .brightness_get = "GPLV",
422 .brightness_set = "SPLV",
423 .mt_lcd_switch = "\\_SB.PCI0.SBRG.EC0._Q10",
424 .lcd_status = "\\_SB.PCI0.SBRG.EC0.RPIN",
425 .display_get = "\\ADVG",
426 .display_set = "SDSP",
427 },
428 {
429 .name = "R1F",
430 .mt_bt_switch = "BLED",
431 .mt_mled = "MLED",
432 .mt_wled = "WLED",
433 .mt_lcd_switch = "\\Q10",
434 .lcd_status = "\\GP06",
435 .brightness_set = "SPLV",
436 .brightness_get = "GPLV",
437 .display_set = "SDSP",
438 .display_get = "\\INFB"
439 }
440};
441
442/* procdir we use */
443static struct proc_dir_entry *asus_proc_dir;
444
445static struct backlight_device *asus_backlight_device;
446
447/*
448 * This header is made available to allow proper configuration given model,
449 * revision number , ... this info cannot go in struct asus_hotk because it is
450 * available before the hotk
451 */
452static struct acpi_table_header *asus_info;
453
454/* The actual device the driver binds to */
455static struct asus_hotk *hotk;
456
457/*
458 * The hotkey driver and autoloading declaration
459 */
460static int asus_hotk_add(struct acpi_device *device);
461static int asus_hotk_remove(struct acpi_device *device, int type);
462static void asus_hotk_notify(struct acpi_device *device, u32 event);
463
464static const struct acpi_device_id asus_device_ids[] = {
465 {"ATK0100", 0},
466 {"", 0},
467};
468MODULE_DEVICE_TABLE(acpi, asus_device_ids);
469
470static struct acpi_driver asus_hotk_driver = {
471 .name = "asus_acpi",
472 .class = ACPI_HOTK_CLASS,
473 .owner = THIS_MODULE,
474 .ids = asus_device_ids,
475 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
476 .ops = {
477 .add = asus_hotk_add,
478 .remove = asus_hotk_remove,
479 .notify = asus_hotk_notify,
480 },
481};
482
483/*
484 * This function evaluates an ACPI method, given an int as parameter, the
485 * method is searched within the scope of the handle, can be NULL. The output
486 * of the method is written is output, which can also be NULL
487 *
488 * returns 1 if write is successful, 0 else.
489 */
490static int write_acpi_int(acpi_handle handle, const char *method, int val,
491 struct acpi_buffer *output)
492{
493 struct acpi_object_list params; /* list of input parameters (int) */
494 union acpi_object in_obj; /* the only param we use */
495 acpi_status status;
496
497 params.count = 1;
498 params.pointer = &in_obj;
499 in_obj.type = ACPI_TYPE_INTEGER;
500 in_obj.integer.value = val;
501
502 status = acpi_evaluate_object(handle, (char *)method, &params, output);
503 return (status == AE_OK);
504}
505
506static int read_acpi_int(acpi_handle handle, const char *method, int *val)
507{
508 struct acpi_buffer output;
509 union acpi_object out_obj;
510 acpi_status status;
511
512 output.length = sizeof(out_obj);
513 output.pointer = &out_obj;
514
515 status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
516 *val = out_obj.integer.value;
517 return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
518}
519
520static int asus_info_proc_show(struct seq_file *m, void *v)
521{
522 int temp;
523
524 seq_printf(m, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
525 seq_printf(m, "Model reference : %s\n", hotk->methods->name);
526 /*
527 * The SFUN method probably allows the original driver to get the list
528 * of features supported by a given model. For now, 0x0100 or 0x0800
529 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
530 * The significance of others is yet to be found.
531 */
532 if (read_acpi_int(hotk->handle, "SFUN", &temp))
533 seq_printf(m, "SFUN value : 0x%04x\n", temp);
534 /*
535 * Another value for userspace: the ASYM method returns 0x02 for
536 * battery low and 0x04 for battery critical, its readings tend to be
537 * more accurate than those provided by _BST.
538 * Note: since not all the laptops provide this method, errors are
539 * silently ignored.
540 */
541 if (read_acpi_int(hotk->handle, "ASYM", &temp))
542 seq_printf(m, "ASYM value : 0x%04x\n", temp);
543 if (asus_info) {
544 seq_printf(m, "DSDT length : %d\n", asus_info->length);
545 seq_printf(m, "DSDT checksum : %d\n", asus_info->checksum);
546 seq_printf(m, "DSDT revision : %d\n", asus_info->revision);
547 seq_printf(m, "OEM id : %.*s\n", ACPI_OEM_ID_SIZE, asus_info->oem_id);
548 seq_printf(m, "OEM table id : %.*s\n", ACPI_OEM_TABLE_ID_SIZE, asus_info->oem_table_id);
549 seq_printf(m, "OEM revision : 0x%x\n", asus_info->oem_revision);
550 seq_printf(m, "ASL comp vendor id : %.*s\n", ACPI_NAME_SIZE, asus_info->asl_compiler_id);
551 seq_printf(m, "ASL comp revision : 0x%x\n", asus_info->asl_compiler_revision);
552 }
553
554 return 0;
555}
556
557static int asus_info_proc_open(struct inode *inode, struct file *file)
558{
559 return single_open(file, asus_info_proc_show, NULL);
560}
561
562static const struct file_operations asus_info_proc_fops = {
563 .owner = THIS_MODULE,
564 .open = asus_info_proc_open,
565 .read = seq_read,
566 .llseek = seq_lseek,
567 .release = single_release,
568};
569
570/*
571 * /proc handlers
572 * We write our info in page, we begin at offset off and cannot write more
573 * than count bytes. We set eof to 1 if we handle those 2 values. We return the
574 * number of bytes written in page
575 */
576
577/* Generic LED functions */
578static int read_led(const char *ledname, int ledmask)
579{
580 if (ledname) {
581 int led_status;
582
583 if (read_acpi_int(NULL, ledname, &led_status))
584 return led_status;
585 else
586 pr_warn("Error reading LED status\n");
587 }
588 return (hotk->status & ledmask) ? 1 : 0;
589}
590
591static int parse_arg(const char __user *buf, unsigned long count, int *val)
592{
593 char s[32];
594 if (!count)
595 return 0;
596 if (count > 31)
597 return -EINVAL;
598 if (copy_from_user(s, buf, count))
599 return -EFAULT;
600 s[count] = 0;
601 if (sscanf(s, "%i", val) != 1)
602 return -EINVAL;
603 return count;
604}
605
606/* FIXME: kill extraneous args so it can be called independently */
607static int
608write_led(const char __user *buffer, unsigned long count,
609 char *ledname, int ledmask, int invert)
610{
611 int rv, value;
612 int led_out = 0;
613
614 rv = parse_arg(buffer, count, &value);
615 if (rv > 0)
616 led_out = value ? 1 : 0;
617
618 hotk->status =
619 (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask);
620
621 if (invert) /* invert target value */
622 led_out = !led_out;
623
624 if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
625 pr_warn("LED (%s) write failed\n", ledname);
626
627 return rv;
628}
629
630/*
631 * Proc handlers for MLED
632 */
633static int mled_proc_show(struct seq_file *m, void *v)
634{
635 seq_printf(m, "%d\n", read_led(hotk->methods->mled_status, MLED_ON));
636 return 0;
637}
638
639static int mled_proc_open(struct inode *inode, struct file *file)
640{
641 return single_open(file, mled_proc_show, NULL);
642}
643
644static ssize_t mled_proc_write(struct file *file, const char __user *buffer,
645 size_t count, loff_t *pos)
646{
647 return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
648}
649
650static const struct file_operations mled_proc_fops = {
651 .owner = THIS_MODULE,
652 .open = mled_proc_open,
653 .read = seq_read,
654 .llseek = seq_lseek,
655 .release = single_release,
656 .write = mled_proc_write,
657};
658
659/*
660 * Proc handlers for LED display
661 */
662static int ledd_proc_show(struct seq_file *m, void *v)
663{
664 seq_printf(m, "0x%08x\n", hotk->ledd_status);
665 return 0;
666}
667
668static int ledd_proc_open(struct inode *inode, struct file *file)
669{
670 return single_open(file, ledd_proc_show, NULL);
671}
672
673static ssize_t ledd_proc_write(struct file *file, const char __user *buffer,
674 size_t count, loff_t *pos)
675{
676 int rv, value;
677
678 rv = parse_arg(buffer, count, &value);
679 if (rv > 0) {
680 if (!write_acpi_int
681 (hotk->handle, hotk->methods->mt_ledd, value, NULL))
682 pr_warn("LED display write failed\n");
683 else
684 hotk->ledd_status = (u32) value;
685 }
686 return rv;
687}
688
689static const struct file_operations ledd_proc_fops = {
690 .owner = THIS_MODULE,
691 .open = ledd_proc_open,
692 .read = seq_read,
693 .llseek = seq_lseek,
694 .release = single_release,
695 .write = ledd_proc_write,
696};
697
698/*
699 * Proc handlers for WLED
700 */
701static int wled_proc_show(struct seq_file *m, void *v)
702{
703 seq_printf(m, "%d\n", read_led(hotk->methods->wled_status, WLED_ON));
704 return 0;
705}
706
707static int wled_proc_open(struct inode *inode, struct file *file)
708{
709 return single_open(file, wled_proc_show, NULL);
710}
711
712static ssize_t wled_proc_write(struct file *file, const char __user *buffer,
713 size_t count, loff_t *pos)
714{
715 return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
716}
717
718static const struct file_operations wled_proc_fops = {
719 .owner = THIS_MODULE,
720 .open = wled_proc_open,
721 .read = seq_read,
722 .llseek = seq_lseek,
723 .release = single_release,
724 .write = wled_proc_write,
725};
726
727/*
728 * Proc handlers for Bluetooth
729 */
730static int bluetooth_proc_show(struct seq_file *m, void *v)
731{
732 seq_printf(m, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
733 return 0;
734}
735
736static int bluetooth_proc_open(struct inode *inode, struct file *file)
737{
738 return single_open(file, bluetooth_proc_show, NULL);
739}
740
741static ssize_t bluetooth_proc_write(struct file *file,
742 const char __user *buffer, size_t count, loff_t *pos)
743{
744 /* Note: mt_bt_switch controls both internal Bluetooth adapter's
745 presence and its LED */
746 return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
747}
748
749static const struct file_operations bluetooth_proc_fops = {
750 .owner = THIS_MODULE,
751 .open = bluetooth_proc_open,
752 .read = seq_read,
753 .llseek = seq_lseek,
754 .release = single_release,
755 .write = bluetooth_proc_write,
756};
757
758/*
759 * Proc handlers for TLED
760 */
761static int tled_proc_show(struct seq_file *m, void *v)
762{
763 seq_printf(m, "%d\n", read_led(hotk->methods->tled_status, TLED_ON));
764 return 0;
765}
766
767static int tled_proc_open(struct inode *inode, struct file *file)
768{
769 return single_open(file, tled_proc_show, NULL);
770}
771
772static ssize_t tled_proc_write(struct file *file, const char __user *buffer,
773 size_t count, loff_t *pos)
774{
775 return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
776}
777
778static const struct file_operations tled_proc_fops = {
779 .owner = THIS_MODULE,
780 .open = tled_proc_open,
781 .read = seq_read,
782 .llseek = seq_lseek,
783 .release = single_release,
784 .write = tled_proc_write,
785};
786
787static int get_lcd_state(void)
788{
789 int lcd = 0;
790
791 if (hotk->model == L3H) {
792 /* L3H and the like have to be handled differently */
793 acpi_status status = 0;
794 struct acpi_object_list input;
795 union acpi_object mt_params[2];
796 struct acpi_buffer output;
797 union acpi_object out_obj;
798
799 input.count = 2;
800 input.pointer = mt_params;
801 /* Note: the following values are partly guessed up, but
802 otherwise they seem to work */
803 mt_params[0].type = ACPI_TYPE_INTEGER;
804 mt_params[0].integer.value = 0x02;
805 mt_params[1].type = ACPI_TYPE_INTEGER;
806 mt_params[1].integer.value = 0x02;
807
808 output.length = sizeof(out_obj);
809 output.pointer = &out_obj;
810
811 status =
812 acpi_evaluate_object(NULL, hotk->methods->lcd_status,
813 &input, &output);
814 if (status != AE_OK)
815 return -1;
816 if (out_obj.type == ACPI_TYPE_INTEGER)
817 /* That's what the AML code does */
818 lcd = out_obj.integer.value >> 8;
819 } else if (hotk->model == F3Sa) {
820 unsigned long long tmp;
821 union acpi_object param;
822 struct acpi_object_list input;
823 acpi_status status;
824
825 /* Read pin 11 */
826 param.type = ACPI_TYPE_INTEGER;
827 param.integer.value = 0x11;
828 input.count = 1;
829 input.pointer = &param;
830
831 status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
832 &input, &tmp);
833 if (status != AE_OK)
834 return -1;
835
836 lcd = tmp;
837 } else {
838 /* We don't have to check anything if we are here */
839 if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
840 pr_warn("Error reading LCD status\n");
841
842 if (hotk->model == L2D)
843 lcd = ~lcd;
844 }
845
846 return (lcd & 1);
847}
848
849static int set_lcd_state(int value)
850{
851 int lcd = 0;
852 acpi_status status = 0;
853
854 lcd = value ? 1 : 0;
855 if (lcd != get_lcd_state()) {
856 /* switch */
857 if (hotk->model != L3H) {
858 status =
859 acpi_evaluate_object(NULL,
860 hotk->methods->mt_lcd_switch,
861 NULL, NULL);
862 } else {
863 /* L3H and the like must be handled differently */
864 if (!write_acpi_int
865 (hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
866 NULL))
867 status = AE_ERROR;
868 /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
869 the exact behaviour is simulated here */
870 }
871 if (ACPI_FAILURE(status))
872 pr_warn("Error switching LCD\n");
873 }
874 return 0;
875
876}
877
878static int lcd_proc_show(struct seq_file *m, void *v)
879{
880 seq_printf(m, "%d\n", get_lcd_state());
881 return 0;
882}
883
884static int lcd_proc_open(struct inode *inode, struct file *file)
885{
886 return single_open(file, lcd_proc_show, NULL);
887}
888
889static ssize_t lcd_proc_write(struct file *file, const char __user *buffer,
890 size_t count, loff_t *pos)
891{
892 int rv, value;
893
894 rv = parse_arg(buffer, count, &value);
895 if (rv > 0)
896 set_lcd_state(value);
897 return rv;
898}
899
900static const struct file_operations lcd_proc_fops = {
901 .owner = THIS_MODULE,
902 .open = lcd_proc_open,
903 .read = seq_read,
904 .llseek = seq_lseek,
905 .release = single_release,
906 .write = lcd_proc_write,
907};
908
909static int read_brightness(struct backlight_device *bd)
910{
911 int value;
912
913 if (hotk->methods->brightness_get) { /* SPLV/GPLV laptop */
914 if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
915 &value))
916 pr_warn("Error reading brightness\n");
917 } else if (hotk->methods->brightness_status) { /* For D1 for example */
918 if (!read_acpi_int(NULL, hotk->methods->brightness_status,
919 &value))
920 pr_warn("Error reading brightness\n");
921 } else /* No GPLV method */
922 value = hotk->brightness;
923 return value;
924}
925
926/*
927 * Change the brightness level
928 */
929static int set_brightness(int value)
930{
931 acpi_status status = 0;
932 int ret = 0;
933
934 /* SPLV laptop */
935 if (hotk->methods->brightness_set) {
936 if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
937 value, NULL)) {
938 pr_warn("Error changing brightness\n");
939 ret = -EIO;
940 }
941 goto out;
942 }
943
944 /* No SPLV method if we are here, act as appropriate */
945 value -= read_brightness(NULL);
946 while (value != 0) {
947 status = acpi_evaluate_object(NULL, (value > 0) ?
948 hotk->methods->brightness_up :
949 hotk->methods->brightness_down,
950 NULL, NULL);
951 (value > 0) ? value-- : value++;
952 if (ACPI_FAILURE(status)) {
953 pr_warn("Error changing brightness\n");
954 ret = -EIO;
955 }
956 }
957out:
958 return ret;
959}
960
961static int set_brightness_status(struct backlight_device *bd)
962{
963 return set_brightness(bd->props.brightness);
964}
965
966static int brn_proc_show(struct seq_file *m, void *v)
967{
968 seq_printf(m, "%d\n", read_brightness(NULL));
969 return 0;
970}
971
972static int brn_proc_open(struct inode *inode, struct file *file)
973{
974 return single_open(file, brn_proc_show, NULL);
975}
976
977static ssize_t brn_proc_write(struct file *file, const char __user *buffer,
978 size_t count, loff_t *pos)
979{
980 int rv, value;
981
982 rv = parse_arg(buffer, count, &value);
983 if (rv > 0) {
984 value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
985 /* 0 <= value <= 15 */
986 set_brightness(value);
987 }
988 return rv;
989}
990
991static const struct file_operations brn_proc_fops = {
992 .owner = THIS_MODULE,
993 .open = brn_proc_open,
994 .read = seq_read,
995 .llseek = seq_lseek,
996 .release = single_release,
997 .write = brn_proc_write,
998};
999
1000static void set_display(int value)
1001{
1002 /* no sanity check needed for now */
1003 if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
1004 value, NULL))
1005 pr_warn("Error setting display\n");
1006 return;
1007}
1008
1009/*
1010 * Now, *this* one could be more user-friendly, but so far, no-one has
1011 * complained. The significance of bits is the same as in proc_write_disp()
1012 */
1013static int disp_proc_show(struct seq_file *m, void *v)
1014{
1015 int value = 0;
1016
1017 if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
1018 pr_warn("Error reading display status\n");
1019 value &= 0x07; /* needed for some models, shouldn't hurt others */
1020 seq_printf(m, "%d\n", value);
1021 return 0;
1022}
1023
1024static int disp_proc_open(struct inode *inode, struct file *file)
1025{
1026 return single_open(file, disp_proc_show, NULL);
1027}
1028
1029/*
1030 * Experimental support for display switching. As of now: 1 should activate
1031 * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
1032 * (bitwise) of these will suffice. I never actually tested 3 displays hooked
1033 * up simultaneously, so be warned. See the acpi4asus README for more info.
1034 */
1035static ssize_t disp_proc_write(struct file *file, const char __user *buffer,
1036 size_t count, loff_t *pos)
1037{
1038 int rv, value;
1039
1040 rv = parse_arg(buffer, count, &value);
1041 if (rv > 0)
1042 set_display(value);
1043 return rv;
1044}
1045
1046static const struct file_operations disp_proc_fops = {
1047 .owner = THIS_MODULE,
1048 .open = disp_proc_open,
1049 .read = seq_read,
1050 .llseek = seq_lseek,
1051 .release = single_release,
1052 .write = disp_proc_write,
1053};
1054
1055static int
1056asus_proc_add(char *name, const struct file_operations *proc_fops, umode_t mode,
1057 struct acpi_device *device)
1058{
1059 struct proc_dir_entry *proc;
1060
1061 proc = proc_create_data(name, mode, acpi_device_dir(device),
1062 proc_fops, acpi_driver_data(device));
1063 if (!proc) {
1064 pr_warn(" Unable to create %s fs entry\n", name);
1065 return -1;
1066 }
1067 proc->uid = asus_uid;
1068 proc->gid = asus_gid;
1069 return 0;
1070}
1071
1072static int asus_hotk_add_fs(struct acpi_device *device)
1073{
1074 struct proc_dir_entry *proc;
1075 umode_t mode;
1076
1077 if ((asus_uid == 0) && (asus_gid == 0)) {
1078 mode = S_IFREG | S_IRUGO | S_IWUSR | S_IWGRP;
1079 } else {
1080 mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
1081 pr_warn(" asus_uid and asus_gid parameters are "
1082 "deprecated, use chown and chmod instead!\n");
1083 }
1084
1085 acpi_device_dir(device) = asus_proc_dir;
1086 if (!acpi_device_dir(device))
1087 return -ENODEV;
1088
1089 proc = proc_create(PROC_INFO, mode, acpi_device_dir(device),
1090 &asus_info_proc_fops);
1091 if (proc) {
1092 proc->uid = asus_uid;
1093 proc->gid = asus_gid;
1094 } else {
1095 pr_warn(" Unable to create " PROC_INFO " fs entry\n");
1096 }
1097
1098 if (hotk->methods->mt_wled) {
1099 asus_proc_add(PROC_WLED, &wled_proc_fops, mode, device);
1100 }
1101
1102 if (hotk->methods->mt_ledd) {
1103 asus_proc_add(PROC_LEDD, &ledd_proc_fops, mode, device);
1104 }
1105
1106 if (hotk->methods->mt_mled) {
1107 asus_proc_add(PROC_MLED, &mled_proc_fops, mode, device);
1108 }
1109
1110 if (hotk->methods->mt_tled) {
1111 asus_proc_add(PROC_TLED, &tled_proc_fops, mode, device);
1112 }
1113
1114 if (hotk->methods->mt_bt_switch) {
1115 asus_proc_add(PROC_BT, &bluetooth_proc_fops, mode, device);
1116 }
1117
1118 /*
1119 * We need both read node and write method as LCD switch is also
1120 * accessible from the keyboard
1121 */
1122 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
1123 asus_proc_add(PROC_LCD, &lcd_proc_fops, mode, device);
1124 }
1125
1126 if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
1127 (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
1128 asus_proc_add(PROC_BRN, &brn_proc_fops, mode, device);
1129 }
1130
1131 if (hotk->methods->display_set) {
1132 asus_proc_add(PROC_DISP, &disp_proc_fops, mode, device);
1133 }
1134
1135 return 0;
1136}
1137
1138static int asus_hotk_remove_fs(struct acpi_device *device)
1139{
1140 if (acpi_device_dir(device)) {
1141 remove_proc_entry(PROC_INFO, acpi_device_dir(device));
1142 if (hotk->methods->mt_wled)
1143 remove_proc_entry(PROC_WLED, acpi_device_dir(device));
1144 if (hotk->methods->mt_mled)
1145 remove_proc_entry(PROC_MLED, acpi_device_dir(device));
1146 if (hotk->methods->mt_tled)
1147 remove_proc_entry(PROC_TLED, acpi_device_dir(device));
1148 if (hotk->methods->mt_ledd)
1149 remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
1150 if (hotk->methods->mt_bt_switch)
1151 remove_proc_entry(PROC_BT, acpi_device_dir(device));
1152 if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
1153 remove_proc_entry(PROC_LCD, acpi_device_dir(device));
1154 if ((hotk->methods->brightness_up
1155 && hotk->methods->brightness_down)
1156 || (hotk->methods->brightness_get
1157 && hotk->methods->brightness_set))
1158 remove_proc_entry(PROC_BRN, acpi_device_dir(device));
1159 if (hotk->methods->display_set)
1160 remove_proc_entry(PROC_DISP, acpi_device_dir(device));
1161 }
1162 return 0;
1163}
1164
1165static void asus_hotk_notify(struct acpi_device *device, u32 event)
1166{
1167 /* TODO Find a better way to handle events count. */
1168 if (!hotk)
1169 return;
1170
1171 /*
1172 * The BIOS *should* be sending us device events, but apparently
1173 * Asus uses system events instead, so just ignore any device
1174 * events we get.
1175 */
1176 if (event > ACPI_MAX_SYS_NOTIFY)
1177 return;
1178
1179 if ((event & ~((u32) BR_UP)) < 16)
1180 hotk->brightness = (event & ~((u32) BR_UP));
1181 else if ((event & ~((u32) BR_DOWN)) < 16)
1182 hotk->brightness = (event & ~((u32) BR_DOWN));
1183
1184 acpi_bus_generate_proc_event(hotk->device, event,
1185 hotk->event_count[event % 128]++);
1186
1187 return;
1188}
1189
1190/*
1191 * Match the model string to the list of supported models. Return END_MODEL if
1192 * no match or model is NULL.
1193 */
1194static int asus_model_match(char *model)
1195{
1196 if (model == NULL)
1197 return END_MODEL;
1198
1199 if (strncmp(model, "L3D", 3) == 0)
1200 return L3D;
1201 else if (strncmp(model, "L2E", 3) == 0 ||
1202 strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
1203 return L3H;
1204 else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
1205 return L3C;
1206 else if (strncmp(model, "L8L", 3) == 0)
1207 return L8L;
1208 else if (strncmp(model, "L4R", 3) == 0)
1209 return L4R;
1210 else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
1211 return M6N;
1212 else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
1213 return M6R;
1214 else if (strncmp(model, "M2N", 3) == 0 ||
1215 strncmp(model, "M3N", 3) == 0 ||
1216 strncmp(model, "M5N", 3) == 0 ||
1217 strncmp(model, "S1N", 3) == 0 ||
1218 strncmp(model, "S5N", 3) == 0)
1219 return xxN;
1220 else if (strncmp(model, "M1", 2) == 0)
1221 return M1A;
1222 else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
1223 return M2E;
1224 else if (strncmp(model, "L2", 2) == 0)
1225 return L2D;
1226 else if (strncmp(model, "L8", 2) == 0)
1227 return S1x;
1228 else if (strncmp(model, "D1", 2) == 0)
1229 return D1x;
1230 else if (strncmp(model, "A1", 2) == 0)
1231 return A1x;
1232 else if (strncmp(model, "A2", 2) == 0)
1233 return A2x;
1234 else if (strncmp(model, "J1", 2) == 0)
1235 return S2x;
1236 else if (strncmp(model, "L5", 2) == 0)
1237 return L5x;
1238 else if (strncmp(model, "A4G", 3) == 0)
1239 return A4G;
1240 else if (strncmp(model, "W1N", 3) == 0)
1241 return W1N;
1242 else if (strncmp(model, "W3V", 3) == 0)
1243 return W3V;
1244 else if (strncmp(model, "W5A", 3) == 0)
1245 return W5A;
1246 else if (strncmp(model, "R1F", 3) == 0)
1247 return R1F;
1248 else if (strncmp(model, "A4S", 3) == 0)
1249 return A4S;
1250 else if (strncmp(model, "F3Sa", 4) == 0)
1251 return F3Sa;
1252 else
1253 return END_MODEL;
1254}
1255
1256/*
1257 * This function is used to initialize the hotk with right values. In this
1258 * method, we can make all the detection we want, and modify the hotk struct
1259 */
1260static int asus_hotk_get_info(void)
1261{
1262 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1263 union acpi_object *model = NULL;
1264 int bsts_result;
1265 char *string = NULL;
1266 acpi_status status;
1267
1268 /*
1269 * Get DSDT headers early enough to allow for differentiating between
1270 * models, but late enough to allow acpi_bus_register_driver() to fail
1271 * before doing anything ACPI-specific. Should we encounter a machine,
1272 * which needs special handling (i.e. its hotkey device has a different
1273 * HID), this bit will be moved. A global variable asus_info contains
1274 * the DSDT header.
1275 */
1276 status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
1277 if (ACPI_FAILURE(status))
1278 pr_warn(" Couldn't get the DSDT table header\n");
1279
1280 /* We have to write 0 on init this far for all ASUS models */
1281 if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
1282 pr_err(" Hotkey initialization failed\n");
1283 return -ENODEV;
1284 }
1285
1286 /* This needs to be called for some laptops to init properly */
1287 if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
1288 pr_warn(" Error calling BSTS\n");
1289 else if (bsts_result)
1290 pr_notice(" BSTS called, 0x%02x returned\n", bsts_result);
1291
1292 /*
1293 * Try to match the object returned by INIT to the specific model.
1294 * Handle every possible object (or the lack of thereof) the DSDT
1295 * writers might throw at us. When in trouble, we pass NULL to
1296 * asus_model_match() and try something completely different.
1297 */
1298 if (buffer.pointer) {
1299 model = buffer.pointer;
1300 switch (model->type) {
1301 case ACPI_TYPE_STRING:
1302 string = model->string.pointer;
1303 break;
1304 case ACPI_TYPE_BUFFER:
1305 string = model->buffer.pointer;
1306 break;
1307 default:
1308 kfree(model);
1309 model = NULL;
1310 break;
1311 }
1312 }
1313 hotk->model = asus_model_match(string);
1314 if (hotk->model == END_MODEL) { /* match failed */
1315 if (asus_info &&
1316 strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
1317 hotk->model = P30;
1318 pr_notice(" Samsung P30 detected, supported\n");
1319 hotk->methods = &model_conf[hotk->model];
1320 kfree(model);
1321 return 0;
1322 } else {
1323 hotk->model = M2E;
1324 pr_notice(" unsupported model %s, trying default values\n",
1325 string);
1326 pr_notice(" send /proc/acpi/dsdt to the developers\n");
1327 kfree(model);
1328 return -ENODEV;
1329 }
1330 }
1331 hotk->methods = &model_conf[hotk->model];
1332 pr_notice(" %s model detected, supported\n", string);
1333
1334 /* Sort of per-model blacklist */
1335 if (strncmp(string, "L2B", 3) == 0)
1336 hotk->methods->lcd_status = NULL;
1337 /* L2B is similar enough to L3C to use its settings, with this only
1338 exception */
1339 else if (strncmp(string, "A3G", 3) == 0)
1340 hotk->methods->lcd_status = "\\BLFG";
1341 /* A3G is like M6R */
1342 else if (strncmp(string, "S5N", 3) == 0 ||
1343 strncmp(string, "M5N", 3) == 0 ||
1344 strncmp(string, "W3N", 3) == 0)
1345 hotk->methods->mt_mled = NULL;
1346 /* S5N, M5N and W3N have no MLED */
1347 else if (strncmp(string, "L5D", 3) == 0)
1348 hotk->methods->mt_wled = NULL;
1349 /* L5D's WLED is not controlled by ACPI */
1350 else if (strncmp(string, "M2N", 3) == 0 ||
1351 strncmp(string, "W3V", 3) == 0 ||
1352 strncmp(string, "S1N", 3) == 0)
1353 hotk->methods->mt_wled = "WLED";
1354 /* M2N, S1N and W3V have a usable WLED */
1355 else if (asus_info) {
1356 if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
1357 hotk->methods->mled_status = NULL;
1358 /* S1300A reports L84F, but L1400B too, account for that */
1359 }
1360
1361 kfree(model);
1362
1363 return 0;
1364}
1365
1366static int asus_hotk_check(void)
1367{
1368 int result = 0;
1369
1370 result = acpi_bus_get_status(hotk->device);
1371 if (result)
1372 return result;
1373
1374 if (hotk->device->status.present) {
1375 result = asus_hotk_get_info();
1376 } else {
1377 pr_err(" Hotkey device not present, aborting\n");
1378 return -EINVAL;
1379 }
1380
1381 return result;
1382}
1383
1384static int asus_hotk_found;
1385
1386static int asus_hotk_add(struct acpi_device *device)
1387{
1388 acpi_status status = AE_OK;
1389 int result;
1390
1391 pr_notice("Asus Laptop ACPI Extras version %s\n", ASUS_ACPI_VERSION);
1392
1393 hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
1394 if (!hotk)
1395 return -ENOMEM;
1396
1397 hotk->handle = device->handle;
1398 strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
1399 strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
1400 device->driver_data = hotk;
1401 hotk->device = device;
1402
1403 result = asus_hotk_check();
1404 if (result)
1405 goto end;
1406
1407 result = asus_hotk_add_fs(device);
1408 if (result)
1409 goto end;
1410
1411 /* For laptops without GPLV: init the hotk->brightness value */
1412 if ((!hotk->methods->brightness_get)
1413 && (!hotk->methods->brightness_status)
1414 && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
1415 status =
1416 acpi_evaluate_object(NULL, hotk->methods->brightness_down,
1417 NULL, NULL);
1418 if (ACPI_FAILURE(status))
1419 pr_warn(" Error changing brightness\n");
1420 else {
1421 status =
1422 acpi_evaluate_object(NULL,
1423 hotk->methods->brightness_up,
1424 NULL, NULL);
1425 if (ACPI_FAILURE(status))
1426 pr_warn(" Strange, error changing brightness\n");
1427 }
1428 }
1429
1430 asus_hotk_found = 1;
1431
1432 /* LED display is off by default */
1433 hotk->ledd_status = 0xFFF;
1434
1435end:
1436 if (result)
1437 kfree(hotk);
1438
1439 return result;
1440}
1441
1442static int asus_hotk_remove(struct acpi_device *device, int type)
1443{
1444 asus_hotk_remove_fs(device);
1445
1446 kfree(hotk);
1447
1448 return 0;
1449}
1450
1451static const struct backlight_ops asus_backlight_data = {
1452 .get_brightness = read_brightness,
1453 .update_status = set_brightness_status,
1454};
1455
1456static void asus_acpi_exit(void)
1457{
1458 if (asus_backlight_device)
1459 backlight_device_unregister(asus_backlight_device);
1460
1461 acpi_bus_unregister_driver(&asus_hotk_driver);
1462 remove_proc_entry(PROC_ASUS, acpi_root_dir);
1463
1464 return;
1465}
1466
1467static int __init asus_acpi_init(void)
1468{
1469 struct backlight_properties props;
1470 int result;
1471
1472 result = acpi_bus_register_driver(&asus_hotk_driver);
1473 if (result < 0)
1474 return result;
1475
1476 asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
1477 if (!asus_proc_dir) {
1478 pr_err("Unable to create /proc entry\n");
1479 acpi_bus_unregister_driver(&asus_hotk_driver);
1480 return -ENODEV;
1481 }
1482
1483 /*
1484 * This is a bit of a kludge. We only want this module loaded
1485 * for ASUS systems, but there's currently no way to probe the
1486 * ACPI namespace for ASUS HIDs. So we just return failure if
1487 * we didn't find one, which will cause the module to be
1488 * unloaded.
1489 */
1490 if (!asus_hotk_found) {
1491 acpi_bus_unregister_driver(&asus_hotk_driver);
1492 remove_proc_entry(PROC_ASUS, acpi_root_dir);
1493 return -ENODEV;
1494 }
1495
1496 memset(&props, 0, sizeof(struct backlight_properties));
1497 props.type = BACKLIGHT_PLATFORM;
1498 props.max_brightness = 15;
1499 asus_backlight_device = backlight_device_register("asus", NULL, NULL,
1500 &asus_backlight_data,
1501 &props);
1502 if (IS_ERR(asus_backlight_device)) {
1503 pr_err("Could not register asus backlight device\n");
1504 asus_backlight_device = NULL;
1505 asus_acpi_exit();
1506 return -ENODEV;
1507 }
1508
1509 return 0;
1510}
1511
1512module_init(asus_acpi_init);
1513module_exit(asus_acpi_exit);
diff --git a/drivers/platform/x86/compal-laptop.c b/drivers/platform/x86/compal-laptop.c
index d96734478324..1887e2f166a4 100644
--- a/drivers/platform/x86/compal-laptop.c
+++ b/drivers/platform/x86/compal-laptop.c
@@ -882,6 +882,7 @@ static struct dmi_system_id __initdata compal_dmi_table[] = {
882 }, 882 },
883 { } 883 { }
884}; 884};
885MODULE_DEVICE_TABLE(dmi, compal_dmi_table);
885 886
886static void initialize_power_supply_data(struct compal_data *data) 887static void initialize_power_supply_data(struct compal_data *data)
887{ 888{
@@ -1097,16 +1098,3 @@ MODULE_AUTHOR("Roald Frederickx (roald.frederickx@gmail.com)");
1097MODULE_DESCRIPTION("Compal Laptop Support"); 1098MODULE_DESCRIPTION("Compal Laptop Support");
1098MODULE_VERSION(DRIVER_VERSION); 1099MODULE_VERSION(DRIVER_VERSION);
1099MODULE_LICENSE("GPL"); 1100MODULE_LICENSE("GPL");
1100
1101MODULE_ALIAS("dmi:*:rnIFL90:rvrIFT00:*");
1102MODULE_ALIAS("dmi:*:rnIFL90:rvrREFERENCE:*");
1103MODULE_ALIAS("dmi:*:rnIFL91:rvrIFT00:*");
1104MODULE_ALIAS("dmi:*:rnJFL92:rvrIFT00:*");
1105MODULE_ALIAS("dmi:*:rnIFT00:rvrIFT00:*");
1106MODULE_ALIAS("dmi:*:rnJHL90:rvrREFERENCE:*");
1107MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron910:*");
1108MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1010:*");
1109MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1011:*");
1110MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1012:*");
1111MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1110:*");
1112MODULE_ALIAS("dmi:*:svnDellInc.:pnInspiron1210:*");
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index d93e962f2610..a05fc9c955d8 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -117,6 +117,7 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
117 }, 117 },
118 { } 118 { }
119}; 119};
120MODULE_DEVICE_TABLE(dmi, dell_device_table);
120 121
121static struct dmi_system_id __devinitdata dell_blacklist[] = { 122static struct dmi_system_id __devinitdata dell_blacklist[] = {
122 /* Supported by compal-laptop */ 123 /* Supported by compal-laptop */
@@ -184,6 +185,33 @@ static struct dmi_system_id __devinitdata dell_quirks[] = {
184 }, 185 },
185 .driver_data = &quirk_dell_vostro_v130, 186 .driver_data = &quirk_dell_vostro_v130,
186 }, 187 },
188 {
189 .callback = dmi_matched,
190 .ident = "Dell Vostro 3555",
191 .matches = {
192 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
193 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"),
194 },
195 .driver_data = &quirk_dell_vostro_v130,
196 },
197 {
198 .callback = dmi_matched,
199 .ident = "Dell Inspiron N311z",
200 .matches = {
201 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
202 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"),
203 },
204 .driver_data = &quirk_dell_vostro_v130,
205 },
206 {
207 .callback = dmi_matched,
208 .ident = "Dell Inspiron M5110",
209 .matches = {
210 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
211 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
212 },
213 .driver_data = &quirk_dell_vostro_v130,
214 },
187}; 215};
188 216
189static struct calling_interface_buffer *buffer; 217static struct calling_interface_buffer *buffer;
@@ -236,9 +264,7 @@ static void __init find_tokens(const struct dmi_header *dm, void *dummy)
236{ 264{
237 switch (dm->type) { 265 switch (dm->type) {
238 case 0xd4: /* Indexed IO */ 266 case 0xd4: /* Indexed IO */
239 break;
240 case 0xd5: /* Protected Area Type 1 */ 267 case 0xd5: /* Protected Area Type 1 */
241 break;
242 case 0xd6: /* Protected Area Type 2 */ 268 case 0xd6: /* Protected Area Type 2 */
243 break; 269 break;
244 case 0xda: /* Calling interface */ 270 case 0xda: /* Calling interface */
@@ -615,6 +641,7 @@ static void touchpad_led_set(struct led_classdev *led_cdev,
615static struct led_classdev touchpad_led = { 641static struct led_classdev touchpad_led = {
616 .name = "dell-laptop::touchpad", 642 .name = "dell-laptop::touchpad",
617 .brightness_set = touchpad_led_set, 643 .brightness_set = touchpad_led_set,
644 .flags = LED_CORE_SUSPENDRESUME,
618}; 645};
619 646
620static int __devinit touchpad_led_init(struct device *dev) 647static int __devinit touchpad_led_init(struct device *dev)
@@ -794,6 +821,3 @@ module_exit(dell_exit);
794MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); 821MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
795MODULE_DESCRIPTION("Dell laptop driver"); 822MODULE_DESCRIPTION("Dell laptop driver");
796MODULE_LICENSE("GPL"); 823MODULE_LICENSE("GPL");
797MODULE_ALIAS("dmi:*svnDellInc.:*:ct8:*");
798MODULE_ALIAS("dmi:*svnDellInc.:*:ct9:*");
799MODULE_ALIAS("dmi:*svnDellComputerCorporation.:*:ct8:*");
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index ea44abd8df48..dab91b48d22c 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -646,7 +646,7 @@ static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
646 } else { 646 } else {
647 dev = pci_get_slot(bus, 0); 647 dev = pci_get_slot(bus, 0);
648 if (dev) { 648 if (dev) {
649 pci_remove_bus_device(dev); 649 pci_stop_and_remove_bus_device(dev);
650 pci_dev_put(dev); 650 pci_dev_put(dev);
651 } 651 }
652 } 652 }
@@ -1251,6 +1251,14 @@ static void eeepc_input_exit(struct eeepc_laptop *eeepc)
1251/* 1251/*
1252 * ACPI driver 1252 * ACPI driver
1253 */ 1253 */
1254static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
1255{
1256 if (!eeepc->inputdev)
1257 return ;
1258 if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
1259 pr_info("Unknown key %x pressed\n", event);
1260}
1261
1254static void eeepc_acpi_notify(struct acpi_device *device, u32 event) 1262static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
1255{ 1263{
1256 struct eeepc_laptop *eeepc = acpi_driver_data(device); 1264 struct eeepc_laptop *eeepc = acpi_driver_data(device);
@@ -1287,12 +1295,11 @@ static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
1287 * event will be desired value (or else ignored) 1295 * event will be desired value (or else ignored)
1288 */ 1296 */
1289 } 1297 }
1290 sparse_keymap_report_event(eeepc->inputdev, event, 1298 eeepc_input_notify(eeepc, event);
1291 1, true);
1292 } 1299 }
1293 } else { 1300 } else {
1294 /* Everything else is a bona-fide keypress event */ 1301 /* Everything else is a bona-fide keypress event */
1295 sparse_keymap_report_event(eeepc->inputdev, event, 1, true); 1302 eeepc_input_notify(eeepc, event);
1296 } 1303 }
1297} 1304}
1298 1305
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 9f6e64302b45..656761380342 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -32,6 +32,7 @@
32#include <linux/input.h> 32#include <linux/input.h>
33#include <linux/input/sparse-keymap.h> 33#include <linux/input/sparse-keymap.h>
34#include <linux/dmi.h> 34#include <linux/dmi.h>
35#include <linux/fb.h>
35#include <acpi/acpi_bus.h> 36#include <acpi/acpi_bus.h>
36 37
37#include "asus-wmi.h" 38#include "asus-wmi.h"
@@ -84,9 +85,81 @@ static const struct key_entry eeepc_wmi_keymap[] = {
84 { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, 85 { KE_KEY, 0xed, { KEY_CAMERA_DOWN } },
85 { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, 86 { KE_KEY, 0xee, { KEY_CAMERA_LEFT } },
86 { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, 87 { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } },
88 { KE_KEY, 0xf3, { KEY_MENU } },
89 { KE_KEY, 0xf5, { KEY_HOMEPAGE } },
90 { KE_KEY, 0xf6, { KEY_ESC } },
87 { KE_END, 0}, 91 { KE_END, 0},
88}; 92};
89 93
94static struct quirk_entry quirk_asus_unknown = {
95};
96
97static struct quirk_entry quirk_asus_1000h = {
98 .hotplug_wireless = true,
99};
100
101static struct quirk_entry quirk_asus_et2012_type1 = {
102 .store_backlight_power = true,
103};
104
105static struct quirk_entry quirk_asus_et2012_type3 = {
106 .scalar_panel_brightness = true,
107 .store_backlight_power = true,
108};
109
110static struct quirk_entry *quirks;
111
112static void et2012_quirks(void)
113{
114 const struct dmi_device *dev = NULL;
115 char oemstring[30];
116
117 while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
118 if (sscanf(dev->name, "AEMS%24c", oemstring) == 1) {
119 if (oemstring[18] == '1')
120 quirks = &quirk_asus_et2012_type1;
121 else if (oemstring[18] == '3')
122 quirks = &quirk_asus_et2012_type3;
123 break;
124 }
125 }
126}
127
128static int dmi_matched(const struct dmi_system_id *dmi)
129{
130 char *model;
131
132 quirks = dmi->driver_data;
133
134 model = (char *)dmi->matches[1].substr;
135 if (unlikely(strncmp(model, "ET2012", 6) == 0))
136 et2012_quirks();
137
138 return 1;
139}
140
141static struct dmi_system_id asus_quirks[] = {
142 {
143 .callback = dmi_matched,
144 .ident = "ASUSTeK Computer INC. 1000H",
145 .matches = {
146 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
147 DMI_MATCH(DMI_PRODUCT_NAME, "1000H"),
148 },
149 .driver_data = &quirk_asus_1000h,
150 },
151 {
152 .callback = dmi_matched,
153 .ident = "ASUSTeK Computer INC. ET2012E/I",
154 .matches = {
155 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK Computer INC."),
156 DMI_MATCH(DMI_PRODUCT_NAME, "ET2012"),
157 },
158 .driver_data = &quirk_asus_unknown,
159 },
160 {},
161};
162
90static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code, 163static void eeepc_wmi_key_filter(struct asus_wmi_driver *asus_wmi, int *code,
91 unsigned int *value, bool *autorelease) 164 unsigned int *value, bool *autorelease)
92{ 165{
@@ -141,33 +214,16 @@ static int eeepc_wmi_probe(struct platform_device *pdev)
141 return 0; 214 return 0;
142} 215}
143 216
144static void eeepc_dmi_check(struct asus_wmi_driver *driver)
145{
146 const char *model;
147
148 model = dmi_get_system_info(DMI_PRODUCT_NAME);
149 if (!model)
150 return;
151
152 /*
153 * Whitelist for wlan hotplug
154 *
155 * Asus 1000H needs the current hotplug code to handle
156 * Fn+F2 correctly. We may add other Asus here later, but
157 * it seems that most of the laptops supported by asus-wmi
158 * don't need to be on this list
159 */
160 if (strcmp(model, "1000H") == 0) {
161 driver->hotplug_wireless = true;
162 pr_info("wlan hotplug enabled\n");
163 }
164}
165
166static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) 217static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
167{ 218{
168 driver->hotplug_wireless = hotplug_wireless; 219 quirks = &quirk_asus_unknown;
169 driver->wapf = -1; 220 quirks->hotplug_wireless = hotplug_wireless;
170 eeepc_dmi_check(driver); 221
222 dmi_check_system(asus_quirks);
223
224 driver->quirks = quirks;
225 driver->quirks->wapf = -1;
226 driver->panel_power = FB_BLANK_UNBLANK;
171} 227}
172 228
173static struct asus_wmi_driver asus_wmi_driver = { 229static struct asus_wmi_driver asus_wmi_driver = {
@@ -179,7 +235,7 @@ static struct asus_wmi_driver asus_wmi_driver = {
179 .input_phys = EEEPC_WMI_FILE "/input0", 235 .input_phys = EEEPC_WMI_FILE "/input0",
180 .key_filter = eeepc_wmi_key_filter, 236 .key_filter = eeepc_wmi_key_filter,
181 .probe = eeepc_wmi_probe, 237 .probe = eeepc_wmi_probe,
182 .quirks = eeepc_wmi_quirks, 238 .detect_quirks = eeepc_wmi_quirks,
183}; 239};
184 240
185 241
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c
index 5a34973dc164..7387f97a2941 100644
--- a/drivers/platform/x86/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -375,11 +375,11 @@ static ssize_t hdaps_variance_show(struct device *dev,
375static ssize_t hdaps_temp1_show(struct device *dev, 375static ssize_t hdaps_temp1_show(struct device *dev,
376 struct device_attribute *attr, char *buf) 376 struct device_attribute *attr, char *buf)
377{ 377{
378 u8 temp; 378 u8 uninitialized_var(temp);
379 int ret; 379 int ret;
380 380
381 ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp); 381 ret = hdaps_readb_one(HDAPS_PORT_TEMP1, &temp);
382 if (ret < 0) 382 if (ret)
383 return ret; 383 return ret;
384 384
385 return sprintf(buf, "%u\n", temp); 385 return sprintf(buf, "%u\n", temp);
@@ -388,11 +388,11 @@ static ssize_t hdaps_temp1_show(struct device *dev,
388static ssize_t hdaps_temp2_show(struct device *dev, 388static ssize_t hdaps_temp2_show(struct device *dev,
389 struct device_attribute *attr, char *buf) 389 struct device_attribute *attr, char *buf)
390{ 390{
391 u8 temp; 391 u8 uninitialized_var(temp);
392 int ret; 392 int ret;
393 393
394 ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp); 394 ret = hdaps_readb_one(HDAPS_PORT_TEMP2, &temp);
395 if (ret < 0) 395 if (ret)
396 return ret; 396 return ret;
397 397
398 return sprintf(buf, "%u\n", temp); 398 return sprintf(buf, "%u\n", temp);
diff --git a/drivers/platform/x86/intel_mid_powerbtn.c b/drivers/platform/x86/intel_mid_powerbtn.c
index f1ae5078b7ec..0a3594c7e912 100644
--- a/drivers/platform/x86/intel_mid_powerbtn.c
+++ b/drivers/platform/x86/intel_mid_powerbtn.c
@@ -23,21 +23,27 @@
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/input.h> 25#include <linux/input.h>
26 26#include <linux/mfd/intel_msic.h>
27#include <asm/intel_scu_ipc.h>
28 27
29#define DRIVER_NAME "msic_power_btn" 28#define DRIVER_NAME "msic_power_btn"
30 29
31#define MSIC_PB_STATUS 0x3f
32#define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ 30#define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */
33 31
32/*
33 * MSIC document ti_datasheet defines the 1st bit reg 0x21 is used to mask
34 * power button interrupt
35 */
36#define MSIC_PWRBTNM (1 << 0)
37
34static irqreturn_t mfld_pb_isr(int irq, void *dev_id) 38static irqreturn_t mfld_pb_isr(int irq, void *dev_id)
35{ 39{
36 struct input_dev *input = dev_id; 40 struct input_dev *input = dev_id;
37 int ret; 41 int ret;
38 u8 pbstat; 42 u8 pbstat;
39 43
40 ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat); 44 ret = intel_msic_reg_read(INTEL_MSIC_PBSTATUS, &pbstat);
45 dev_dbg(input->dev.parent, "PB_INT status= %d\n", pbstat);
46
41 if (ret < 0) { 47 if (ret < 0) {
42 dev_err(input->dev.parent, "Read error %d while reading" 48 dev_err(input->dev.parent, "Read error %d while reading"
43 " MSIC_PB_STATUS\n", ret); 49 " MSIC_PB_STATUS\n", ret);
@@ -88,6 +94,24 @@ static int __devinit mfld_pb_probe(struct platform_device *pdev)
88 } 94 }
89 95
90 platform_set_drvdata(pdev, input); 96 platform_set_drvdata(pdev, input);
97
98 /*
99 * SCU firmware might send power button interrupts to IA core before
100 * kernel boots and doesn't get EOI from IA core. The first bit of
101 * MSIC reg 0x21 is kept masked, and SCU firmware doesn't send new
102 * power interrupt to Android kernel. Unmask the bit when probing
103 * power button in kernel.
104 * There is a very narrow race between irq handler and power button
105 * initialization. The race happens rarely. So we needn't worry
106 * about it.
107 */
108 error = intel_msic_reg_update(INTEL_MSIC_IRQLVL1MSK, 0, MSIC_PWRBTNM);
109 if (error) {
110 dev_err(&pdev->dev, "Unable to clear power button interrupt, "
111 "error: %d\n", error);
112 goto err_free_irq;
113 }
114
91 return 0; 115 return 0;
92 116
93err_free_irq: 117err_free_irq:
@@ -118,17 +142,7 @@ static struct platform_driver mfld_pb_driver = {
118 .remove = __devexit_p(mfld_pb_remove), 142 .remove = __devexit_p(mfld_pb_remove),
119}; 143};
120 144
121static int __init mfld_pb_init(void) 145module_platform_driver(mfld_pb_driver);
122{
123 return platform_driver_register(&mfld_pb_driver);
124}
125module_init(mfld_pb_init);
126
127static void __exit mfld_pb_exit(void)
128{
129 platform_driver_unregister(&mfld_pb_driver);
130}
131module_exit(mfld_pb_exit);
132 146
133MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>"); 147MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>");
134MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); 148MODULE_DESCRIPTION("Intel Medfield Power Button Driver");
diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c
index ccd7b1f83519..5ae9cd9c7e6e 100644
--- a/drivers/platform/x86/intel_mid_thermal.c
+++ b/drivers/platform/x86/intel_mid_thermal.c
@@ -33,18 +33,15 @@
33#include <linux/slab.h> 33#include <linux/slab.h>
34#include <linux/pm.h> 34#include <linux/pm.h>
35#include <linux/thermal.h> 35#include <linux/thermal.h>
36 36#include <linux/mfd/intel_msic.h>
37#include <asm/intel_scu_ipc.h>
38 37
39/* Number of thermal sensors */ 38/* Number of thermal sensors */
40#define MSIC_THERMAL_SENSORS 4 39#define MSIC_THERMAL_SENSORS 4
41 40
42/* ADC1 - thermal registers */ 41/* ADC1 - thermal registers */
43#define MSIC_THERM_ADC1CNTL1 0x1C0
44#define MSIC_ADC_ENBL 0x10 42#define MSIC_ADC_ENBL 0x10
45#define MSIC_ADC_START 0x08 43#define MSIC_ADC_START 0x08
46 44
47#define MSIC_THERM_ADC1CNTL3 0x1C2
48#define MSIC_ADCTHERM_ENBL 0x04 45#define MSIC_ADCTHERM_ENBL 0x04
49#define MSIC_ADCRRDATA_ENBL 0x05 46#define MSIC_ADCRRDATA_ENBL 0x05
50#define MSIC_CHANL_MASK_VAL 0x0F 47#define MSIC_CHANL_MASK_VAL 0x0F
@@ -75,8 +72,8 @@
75#define ADC_VAL60C 315 72#define ADC_VAL60C 315
76 73
77/* ADC base addresses */ 74/* ADC base addresses */
78#define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ 75#define ADC_CHNL_START_ADDR INTEL_MSIC_ADC1ADDR0 /* increments by 1 */
79#define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ 76#define ADC_DATA_START_ADDR INTEL_MSIC_ADC1SNS0H /* increments by 2 */
80 77
81/* MSIC die attributes */ 78/* MSIC die attributes */
82#define MSIC_DIE_ADC_MIN 488 79#define MSIC_DIE_ADC_MIN 488
@@ -189,17 +186,17 @@ static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
189 addr = td_info->chnl_addr; 186 addr = td_info->chnl_addr;
190 187
191 /* Enable the msic for conversion before reading */ 188 /* Enable the msic for conversion before reading */
192 ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); 189 ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCRRDATA_ENBL);
193 if (ret) 190 if (ret)
194 return ret; 191 return ret;
195 192
196 /* Re-toggle the RRDATARD bit (temporary workaround) */ 193 /* Re-toggle the RRDATARD bit (temporary workaround) */
197 ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL); 194 ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, MSIC_ADCTHERM_ENBL);
198 if (ret) 195 if (ret)
199 return ret; 196 return ret;
200 197
201 /* Read the higher bits of data */ 198 /* Read the higher bits of data */
202 ret = intel_scu_ipc_ioread8(addr, &data); 199 ret = intel_msic_reg_read(addr, &data);
203 if (ret) 200 if (ret)
204 return ret; 201 return ret;
205 202
@@ -207,7 +204,7 @@ static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp)
207 adc_val = (data << 2); 204 adc_val = (data << 2);
208 addr++; 205 addr++;
209 206
210 ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */ 207 ret = intel_msic_reg_read(addr, &data);/* Read lower bits */
211 if (ret) 208 if (ret)
212 return ret; 209 return ret;
213 210
@@ -235,7 +232,7 @@ static int configure_adc(int val)
235 int ret; 232 int ret;
236 uint8_t data; 233 uint8_t data;
237 234
238 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); 235 ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data);
239 if (ret) 236 if (ret)
240 return ret; 237 return ret;
241 238
@@ -246,7 +243,7 @@ static int configure_adc(int val)
246 /* Just stop the ADC */ 243 /* Just stop the ADC */
247 data &= (~MSIC_ADC_START); 244 data &= (~MSIC_ADC_START);
248 } 245 }
249 return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data); 246 return intel_msic_reg_write(INTEL_MSIC_ADC1CNTL1, data);
250} 247}
251 248
252/** 249/**
@@ -262,21 +259,21 @@ static int set_up_therm_channel(u16 base_addr)
262 int ret; 259 int ret;
263 260
264 /* Enable all the sensor channels */ 261 /* Enable all the sensor channels */
265 ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE); 262 ret = intel_msic_reg_write(base_addr, SKIN_SENSOR0_CODE);
266 if (ret) 263 if (ret)
267 return ret; 264 return ret;
268 265
269 ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE); 266 ret = intel_msic_reg_write(base_addr + 1, SKIN_SENSOR1_CODE);
270 if (ret) 267 if (ret)
271 return ret; 268 return ret;
272 269
273 ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE); 270 ret = intel_msic_reg_write(base_addr + 2, SYS_SENSOR_CODE);
274 if (ret) 271 if (ret)
275 return ret; 272 return ret;
276 273
277 /* Since this is the last channel, set the stop bit 274 /* Since this is the last channel, set the stop bit
278 * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ 275 * to 1 by ORing the DIE_SENSOR_CODE with 0x10 */
279 ret = intel_scu_ipc_iowrite8(base_addr + 3, 276 ret = intel_msic_reg_write(base_addr + 3,
280 (MSIC_DIE_SENSOR_CODE | 0x10)); 277 (MSIC_DIE_SENSOR_CODE | 0x10));
281 if (ret) 278 if (ret)
282 return ret; 279 return ret;
@@ -295,11 +292,11 @@ static int reset_stopbit(uint16_t addr)
295{ 292{
296 int ret; 293 int ret;
297 uint8_t data; 294 uint8_t data;
298 ret = intel_scu_ipc_ioread8(addr, &data); 295 ret = intel_msic_reg_read(addr, &data);
299 if (ret) 296 if (ret)
300 return ret; 297 return ret;
301 /* Set the stop bit to zero */ 298 /* Set the stop bit to zero */
302 return intel_scu_ipc_iowrite8(addr, (data & 0xEF)); 299 return intel_msic_reg_write(addr, (data & 0xEF));
303} 300}
304 301
305/** 302/**
@@ -322,7 +319,7 @@ static int find_free_channel(void)
322 uint8_t data; 319 uint8_t data;
323 320
324 /* check whether ADC is enabled */ 321 /* check whether ADC is enabled */
325 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); 322 ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL1, &data);
326 if (ret) 323 if (ret)
327 return ret; 324 return ret;
328 325
@@ -331,7 +328,7 @@ static int find_free_channel(void)
331 328
332 /* ADC is already enabled; Looking for an empty channel */ 329 /* ADC is already enabled; Looking for an empty channel */
333 for (i = 0; i < ADC_CHANLS_MAX; i++) { 330 for (i = 0; i < ADC_CHANLS_MAX; i++) {
334 ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data); 331 ret = intel_msic_reg_read(ADC_CHNL_START_ADDR + i, &data);
335 if (ret) 332 if (ret)
336 return ret; 333 return ret;
337 334
@@ -359,12 +356,14 @@ static int mid_initialize_adc(struct device *dev)
359 * Ensure that adctherm is disabled before we 356 * Ensure that adctherm is disabled before we
360 * initialize the ADC 357 * initialize the ADC
361 */ 358 */
362 ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data); 359 ret = intel_msic_reg_read(INTEL_MSIC_ADC1CNTL3, &data);
363 if (ret) 360 if (ret)
364 return ret; 361 return ret;
365 362
366 if (data & MSIC_ADCTHERM_MASK) 363 data &= ~MSIC_ADCTHERM_MASK;
367 dev_warn(dev, "ADCTHERM already set"); 364 ret = intel_msic_reg_write(INTEL_MSIC_ADC1CNTL3, data);
365 if (ret)
366 return ret;
368 367
369 /* Index of the first channel in which the stop bit is set */ 368 /* Index of the first channel in which the stop bit is set */
370 channel_index = find_free_channel(); 369 channel_index = find_free_channel();
@@ -546,10 +545,11 @@ static int mid_thermal_remove(struct platform_device *pdev)
546 return configure_adc(0); 545 return configure_adc(0);
547} 546}
548 547
549#define DRIVER_NAME "msic_sensor" 548#define DRIVER_NAME "msic_thermal"
550 549
551static const struct platform_device_id therm_id_table[] = { 550static const struct platform_device_id therm_id_table[] = {
552 { DRIVER_NAME, 1 }, 551 { DRIVER_NAME, 1 },
552 { "msic_thermal", 1 },
553 { } 553 { }
554}; 554};
555 555
@@ -565,18 +565,7 @@ static struct platform_driver mid_thermal_driver = {
565 .id_table = therm_id_table, 565 .id_table = therm_id_table,
566}; 566};
567 567
568static int __init mid_thermal_module_init(void) 568module_platform_driver(mid_thermal_driver);
569{
570 return platform_driver_register(&mid_thermal_driver);
571}
572
573static void __exit mid_thermal_module_exit(void)
574{
575 platform_driver_unregister(&mid_thermal_driver);
576}
577
578module_init(mid_thermal_module_init);
579module_exit(mid_thermal_module_exit);
580 569
581MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>"); 570MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>");
582MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver"); 571MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver");
diff --git a/drivers/platform/x86/intel_oaktrail.c b/drivers/platform/x86/intel_oaktrail.c
index 6ee0b5c90933..79a0c2f6be53 100644
--- a/drivers/platform/x86/intel_oaktrail.c
+++ b/drivers/platform/x86/intel_oaktrail.c
@@ -313,6 +313,7 @@ static struct dmi_system_id __initdata oaktrail_dmi_table[] = {
313 }, 313 },
314 { } 314 { }
315}; 315};
316MODULE_DEVICE_TABLE(dmi, oaktrail_dmi_table);
316 317
317static int __init oaktrail_init(void) 318static int __init oaktrail_init(void)
318{ 319{
@@ -394,4 +395,3 @@ MODULE_AUTHOR("Yin Kangkai (kangkai.yin@intel.com)");
394MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras"); 395MODULE_DESCRIPTION("Intel Oaktrail Platform ACPI Extras");
395MODULE_VERSION(DRIVER_VERSION); 396MODULE_VERSION(DRIVER_VERSION);
396MODULE_LICENSE("GPL"); 397MODULE_LICENSE("GPL");
397MODULE_ALIAS("dmi:*:svnIntelCorporation:pnOakTrailplatform:*");
diff --git a/drivers/platform/x86/intel_rar_register.c b/drivers/platform/x86/intel_rar_register.c
deleted file mode 100644
index c8a6aed45277..000000000000
--- a/drivers/platform/x86/intel_rar_register.c
+++ /dev/null
@@ -1,669 +0,0 @@
1/*
2 * rar_register.c - An Intel Restricted Access Region register driver
3 *
4 * Copyright(c) 2009 Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 *
21 * -------------------------------------------------------------------
22 * 20091204 Mark Allyn <mark.a.allyn@intel.com>
23 * Ossama Othman <ossama.othman@intel.com>
24 * Cleanup per feedback from Alan Cox and Arjan Van De Ven
25 *
26 * 20090806 Ossama Othman <ossama.othman@intel.com>
27 * Return zero high address if upper 22 bits is zero.
28 * Cleaned up checkpatch errors.
29 * Clarified that driver is dealing with bus addresses.
30 *
31 * 20090702 Ossama Othman <ossama.othman@intel.com>
32 * Removed unnecessary include directives
33 * Cleaned up spinlocks.
34 * Cleaned up logging.
35 * Improved invalid parameter checks.
36 * Fixed and simplified RAR address retrieval and RAR locking
37 * code.
38 *
39 * 20090626 Mark Allyn <mark.a.allyn@intel.com>
40 * Initial publish
41 */
42
43#include <linux/module.h>
44#include <linux/pci.h>
45#include <linux/spinlock.h>
46#include <linux/device.h>
47#include <linux/kernel.h>
48#include <linux/rar_register.h>
49
50/* === Lincroft Message Bus Interface === */
51#define LNC_MCR_OFFSET 0xD0 /* Message Control Register */
52#define LNC_MDR_OFFSET 0xD4 /* Message Data Register */
53
54/* Message Opcodes */
55#define LNC_MESSAGE_READ_OPCODE 0xD0
56#define LNC_MESSAGE_WRITE_OPCODE 0xE0
57
58/* Message Write Byte Enables */
59#define LNC_MESSAGE_BYTE_WRITE_ENABLES 0xF
60
61/* B-unit Port */
62#define LNC_BUNIT_PORT 0x3
63
64/* === Lincroft B-Unit Registers - Programmed by IA32 firmware === */
65#define LNC_BRAR0L 0x10
66#define LNC_BRAR0H 0x11
67#define LNC_BRAR1L 0x12
68#define LNC_BRAR1H 0x13
69/* Reserved for SeP */
70#define LNC_BRAR2L 0x14
71#define LNC_BRAR2H 0x15
72
73/* Moorestown supports three restricted access regions. */
74#define MRST_NUM_RAR 3
75
76/* RAR Bus Address Range */
77struct rar_addr {
78 dma_addr_t low;
79 dma_addr_t high;
80};
81
82/*
83 * We create one of these for each RAR
84 */
85struct client {
86 int (*callback)(unsigned long data);
87 unsigned long driver_priv;
88 bool busy;
89};
90
91static DEFINE_MUTEX(rar_mutex);
92static DEFINE_MUTEX(lnc_reg_mutex);
93
94/*
95 * One per RAR device (currently only one device)
96 */
97struct rar_device {
98 struct rar_addr rar_addr[MRST_NUM_RAR];
99 struct pci_dev *rar_dev;
100 bool registered;
101 bool allocated;
102 struct client client[MRST_NUM_RAR];
103};
104
105/* Current platforms have only one rar_device for 3 rar regions */
106static struct rar_device my_rar_device;
107
108/*
109 * Abstract out multiple device support. Current platforms only
110 * have a single RAR device.
111 */
112
113/**
114 * alloc_rar_device - return a new RAR structure
115 *
116 * Return a new (but not yet ready) RAR device object
117 */
118static struct rar_device *alloc_rar_device(void)
119{
120 if (my_rar_device.allocated)
121 return NULL;
122 my_rar_device.allocated = 1;
123 return &my_rar_device;
124}
125
126/**
127 * free_rar_device - free a RAR object
128 * @rar: the RAR device being freed
129 *
130 * Release a RAR object and any attached resources
131 */
132static void free_rar_device(struct rar_device *rar)
133{
134 pci_dev_put(rar->rar_dev);
135 rar->allocated = 0;
136}
137
138/**
139 * _rar_to_device - return the device handling this RAR
140 * @rar: RAR number
141 * @off: returned offset
142 *
143 * Internal helper for looking up RAR devices. This and alloc are the
144 * two functions that need touching to go to multiple RAR devices.
145 */
146static struct rar_device *_rar_to_device(int rar, int *off)
147{
148 if (rar >= 0 && rar < MRST_NUM_RAR) {
149 *off = rar;
150 return &my_rar_device;
151 }
152 return NULL;
153}
154
155/**
156 * rar_to_device - return the device handling this RAR
157 * @rar: RAR number
158 * @off: returned offset
159 *
160 * Return the device this RAR maps to if one is present, otherwise
161 * returns NULL. Reports the offset relative to the base of this
162 * RAR device in off.
163 */
164static struct rar_device *rar_to_device(int rar, int *off)
165{
166 struct rar_device *rar_dev = _rar_to_device(rar, off);
167 if (rar_dev == NULL || !rar_dev->registered)
168 return NULL;
169 return rar_dev;
170}
171
172/**
173 * rar_to_client - return the client handling this RAR
174 * @rar: RAR number
175 *
176 * Return the client this RAR maps to if a mapping is known, otherwise
177 * returns NULL.
178 */
179static struct client *rar_to_client(int rar)
180{
181 int idx;
182 struct rar_device *r = _rar_to_device(rar, &idx);
183 if (r != NULL)
184 return &r->client[idx];
185 return NULL;
186}
187
188/**
189 * rar_read_addr - retrieve a RAR mapping
190 * @pdev: PCI device for the RAR
191 * @offset: offset for message
192 * @addr: returned address
193 *
194 * Reads the address of a given RAR register. Returns 0 on success
195 * or an error code on failure.
196 */
197static int rar_read_addr(struct pci_dev *pdev, int offset, dma_addr_t *addr)
198{
199 /*
200 * ======== The Lincroft Message Bus Interface ========
201 * Lincroft registers may be obtained via PCI from
202 * the host bridge using the Lincroft Message Bus
203 * Interface. That message bus interface is generally
204 * comprised of two registers: a control register (MCR, 0xDO)
205 * and a data register (MDR, 0xD4).
206 *
207 * The MCR (message control register) format is the following:
208 * 1. [31:24]: Opcode
209 * 2. [23:16]: Port
210 * 3. [15:8]: Register Offset
211 * 4. [7:4]: Byte Enables (use 0xF to set all of these bits
212 * to 1)
213 * 5. [3:0]: reserved
214 *
215 * Read (0xD0) and write (0xE0) opcodes are written to the
216 * control register when reading and writing to Lincroft
217 * registers, respectively.
218 *
219 * We're interested in registers found in the Lincroft
220 * B-unit. The B-unit port is 0x3.
221 *
222 * The six B-unit RAR register offsets we use are listed
223 * earlier in this file.
224 *
225 * Lastly writing to the MCR register requires the "Byte
226 * enables" bits to be set to 1. This may be achieved by
227 * writing 0xF at bit 4.
228 *
229 * The MDR (message data register) format is the following:
230 * 1. [31:0]: Read/Write Data
231 *
232 * Data being read from this register is only available after
233 * writing the appropriate control message to the MCR
234 * register.
235 *
236 * Data being written to this register must be written before
237 * writing the appropriate control message to the MCR
238 * register.
239 */
240
241 int result;
242 u32 addr32;
243
244 /* Construct control message */
245 u32 const message =
246 (LNC_MESSAGE_READ_OPCODE << 24)
247 | (LNC_BUNIT_PORT << 16)
248 | (offset << 8)
249 | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
250
251 dev_dbg(&pdev->dev, "Offset for 'get' LNC MSG is %x\n", offset);
252
253 /*
254 * We synchronize access to the Lincroft MCR and MDR registers
255 * until BOTH the command is issued through the MCR register
256 * and the corresponding data is read from the MDR register.
257 * Otherwise a race condition would exist between accesses to
258 * both registers.
259 */
260
261 mutex_lock(&lnc_reg_mutex);
262
263 /* Send the control message */
264 result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
265 if (!result) {
266 /* Read back the address as a 32bit value */
267 result = pci_read_config_dword(pdev, LNC_MDR_OFFSET, &addr32);
268 *addr = (dma_addr_t)addr32;
269 }
270 mutex_unlock(&lnc_reg_mutex);
271 return result;
272}
273
274/**
275 * rar_set_addr - Set a RAR mapping
276 * @pdev: PCI device for the RAR
277 * @offset: offset for message
278 * @addr: address to set
279 *
280 * Sets the address of a given RAR register. Returns 0 on success
281 * or an error code on failure.
282 */
283static int rar_set_addr(struct pci_dev *pdev,
284 int offset,
285 dma_addr_t addr)
286{
287 /*
288 * Data being written to this register must be written before
289 * writing the appropriate control message to the MCR
290 * register.
291 * See rar_get_addrs() for a description of the
292 * message bus interface being used here.
293 */
294
295 int result;
296
297 /* Construct control message */
298 u32 const message = (LNC_MESSAGE_WRITE_OPCODE << 24)
299 | (LNC_BUNIT_PORT << 16)
300 | (offset << 8)
301 | (LNC_MESSAGE_BYTE_WRITE_ENABLES << 4);
302
303 /*
304 * We synchronize access to the Lincroft MCR and MDR registers
305 * until BOTH the command is issued through the MCR register
306 * and the corresponding data is read from the MDR register.
307 * Otherwise a race condition would exist between accesses to
308 * both registers.
309 */
310
311 mutex_lock(&lnc_reg_mutex);
312
313 /* Send the control message */
314 result = pci_write_config_dword(pdev, LNC_MDR_OFFSET, addr);
315 if (!result)
316 /* And address */
317 result = pci_write_config_dword(pdev, LNC_MCR_OFFSET, message);
318
319 mutex_unlock(&lnc_reg_mutex);
320 return result;
321}
322
323/*
324 * rar_init_params - Initialize RAR parameters
325 * @rar: RAR device to initialise
326 *
327 * Initialize RAR parameters, such as bus addresses, etc. Returns 0
328 * on success, or an error code on failure.
329 */
330static int init_rar_params(struct rar_device *rar)
331{
332 struct pci_dev *pdev = rar->rar_dev;
333 unsigned int i;
334 int result = 0;
335 int offset = 0x10; /* RAR 0 to 2 in order low/high/low/high/... */
336
337 /* Retrieve RAR start and end bus addresses.
338 * Access the RAR registers through the Lincroft Message Bus
339 * Interface on PCI device: 00:00.0 Host bridge.
340 */
341
342 for (i = 0; i < MRST_NUM_RAR; ++i) {
343 struct rar_addr *addr = &rar->rar_addr[i];
344
345 result = rar_read_addr(pdev, offset++, &addr->low);
346 if (result != 0)
347 return result;
348
349 result = rar_read_addr(pdev, offset++, &addr->high);
350 if (result != 0)
351 return result;
352
353
354 /*
355 * Only the upper 22 bits of the RAR addresses are
356 * stored in their corresponding RAR registers so we
357 * must set the lower 10 bits accordingly.
358
359 * The low address has its lower 10 bits cleared, and
360 * the high address has all its lower 10 bits set,
361 * e.g.:
362 * low = 0x2ffffc00
363 */
364
365 addr->low &= (dma_addr_t)0xfffffc00u;
366
367 /*
368 * Set bits 9:0 on uppser address if bits 31:10 are non
369 * zero; otherwize clear all bits
370 */
371
372 if ((addr->high & 0xfffffc00u) == 0)
373 addr->high = 0;
374 else
375 addr->high |= 0x3ffu;
376 }
377 /* Done accessing the device. */
378
379 if (result == 0) {
380 for (i = 0; i != MRST_NUM_RAR; ++i) {
381 /*
382 * "BRAR" refers to the RAR registers in the
383 * Lincroft B-unit.
384 */
385 dev_info(&pdev->dev, "BRAR[%u] bus address range = "
386 "[%lx, %lx]\n", i,
387 (unsigned long)rar->rar_addr[i].low,
388 (unsigned long)rar->rar_addr[i].high);
389 }
390 }
391 return result;
392}
393
394/**
395 * rar_get_address - get the bus address in a RAR
396 * @start: return value of start address of block
397 * @end: return value of end address of block
398 *
399 * The rar_get_address function is used by other device drivers
400 * to obtain RAR address information on a RAR. It takes three
401 * parameters:
402 *
403 * The function returns a 0 upon success or an error if there is no RAR
404 * facility on this system.
405 */
406int rar_get_address(int rar_index, dma_addr_t *start, dma_addr_t *end)
407{
408 int idx;
409 struct rar_device *rar = rar_to_device(rar_index, &idx);
410
411 if (rar == NULL) {
412 WARN_ON(1);
413 return -ENODEV;
414 }
415
416 *start = rar->rar_addr[idx].low;
417 *end = rar->rar_addr[idx].high;
418 return 0;
419}
420EXPORT_SYMBOL(rar_get_address);
421
422/**
423 * rar_lock - lock a RAR register
424 * @rar_index: RAR to lock (0-2)
425 *
426 * The rar_lock function is ued by other device drivers to lock an RAR.
427 * once a RAR is locked, it stays locked until the next system reboot.
428 *
429 * The function returns a 0 upon success or an error if there is no RAR
430 * facility on this system, or the locking fails
431 */
432int rar_lock(int rar_index)
433{
434 struct rar_device *rar;
435 int result;
436 int idx;
437 dma_addr_t low, high;
438
439 rar = rar_to_device(rar_index, &idx);
440
441 if (rar == NULL) {
442 WARN_ON(1);
443 return -EINVAL;
444 }
445
446 low = rar->rar_addr[idx].low & 0xfffffc00u;
447 high = rar->rar_addr[idx].high & 0xfffffc00u;
448
449 /*
450 * Only allow I/O from the graphics and Langwell;
451 * not from the x86 processor
452 */
453
454 if (rar_index == RAR_TYPE_VIDEO) {
455 low |= 0x00000009;
456 high |= 0x00000015;
457 } else if (rar_index == RAR_TYPE_AUDIO) {
458 /* Only allow I/O from Langwell; nothing from x86 */
459 low |= 0x00000008;
460 high |= 0x00000018;
461 } else
462 /* Read-only from all agents */
463 high |= 0x00000018;
464
465 /*
466 * Now program the register using the Lincroft message
467 * bus interface.
468 */
469 result = rar_set_addr(rar->rar_dev,
470 2 * idx, low);
471
472 if (result == 0)
473 result = rar_set_addr(rar->rar_dev,
474 2 * idx + 1, high);
475
476 return result;
477}
478EXPORT_SYMBOL(rar_lock);
479
480/**
481 * register_rar - register a RAR handler
482 * @num: RAR we wish to register for
483 * @callback: function to call when RAR support is available
484 * @data: data to pass to this function
485 *
486 * The register_rar function is to used by other device drivers
487 * to ensure that this driver is ready. As we cannot be sure of
488 * the compile/execute order of drivers in the kernel, it is
489 * best to give this driver a callback function to call when
490 * it is ready to give out addresses. The callback function
491 * would have those steps that continue the initialization of
492 * a driver that do require a valid RAR address. One of those
493 * steps would be to call rar_get_address()
494 *
495 * This function return 0 on success or an error code on failure.
496 */
497int register_rar(int num, int (*callback)(unsigned long data),
498 unsigned long data)
499{
500 /* For now we hardcode a single RAR device */
501 struct rar_device *rar;
502 struct client *c;
503 int idx;
504 int retval = 0;
505
506 mutex_lock(&rar_mutex);
507
508 /* Do we have a client mapping for this RAR number ? */
509 c = rar_to_client(num);
510 if (c == NULL) {
511 retval = -ERANGE;
512 goto done;
513 }
514 /* Is it claimed ? */
515 if (c->busy) {
516 retval = -EBUSY;
517 goto done;
518 }
519 c->busy = 1;
520
521 /* See if we have a handler for this RAR yet, if we do then fire it */
522 rar = rar_to_device(num, &idx);
523
524 if (rar) {
525 /*
526 * if the driver already registered, then we can simply
527 * call the callback right now
528 */
529 (*callback)(data);
530 goto done;
531 }
532
533 /* Arrange to be called back when the hardware is found */
534 c->callback = callback;
535 c->driver_priv = data;
536done:
537 mutex_unlock(&rar_mutex);
538 return retval;
539}
540EXPORT_SYMBOL(register_rar);
541
542/**
543 * unregister_rar - release a RAR allocation
544 * @num: RAR number
545 *
546 * Releases a RAR allocation, or pending allocation. If a callback is
547 * pending then this function will either complete before the unregister
548 * returns or not at all.
549 */
550
551void unregister_rar(int num)
552{
553 struct client *c;
554
555 mutex_lock(&rar_mutex);
556 c = rar_to_client(num);
557 if (c == NULL || !c->busy)
558 WARN_ON(1);
559 else
560 c->busy = 0;
561 mutex_unlock(&rar_mutex);
562}
563EXPORT_SYMBOL(unregister_rar);
564
565/**
566 * rar_callback - Process callbacks
567 * @rar: new RAR device
568 *
569 * Process the callbacks for a newly found RAR device.
570 */
571
572static void rar_callback(struct rar_device *rar)
573{
574 struct client *c = &rar->client[0];
575 int i;
576
577 mutex_lock(&rar_mutex);
578
579 rar->registered = 1; /* Ensure no more callbacks queue */
580
581 for (i = 0; i < MRST_NUM_RAR; i++) {
582 if (c->callback && c->busy) {
583 c->callback(c->driver_priv);
584 c->callback = NULL;
585 }
586 c++;
587 }
588 mutex_unlock(&rar_mutex);
589}
590
591/**
592 * rar_probe - PCI probe callback
593 * @dev: PCI device
594 * @id: matching entry in the match table
595 *
596 * A RAR device has been discovered. Initialise it and if successful
597 * process any pending callbacks that can now be completed.
598 */
599static int rar_probe(struct pci_dev *dev, const struct pci_device_id *id)
600{
601 int error;
602 struct rar_device *rar;
603
604 dev_dbg(&dev->dev, "PCI probe starting\n");
605
606 rar = alloc_rar_device();
607 if (rar == NULL)
608 return -EBUSY;
609
610 /* Enable the device */
611 error = pci_enable_device(dev);
612 if (error) {
613 dev_err(&dev->dev,
614 "Error enabling RAR register PCI device\n");
615 goto end_function;
616 }
617
618 /* Fill in the rar_device structure */
619 rar->rar_dev = pci_dev_get(dev);
620 pci_set_drvdata(dev, rar);
621
622 /*
623 * Initialize the RAR parameters, which have to be retrieved
624 * via the message bus interface.
625 */
626 error = init_rar_params(rar);
627 if (error) {
628 pci_disable_device(dev);
629 dev_err(&dev->dev, "Error retrieving RAR addresses\n");
630 goto end_function;
631 }
632 /* now call anyone who has registered (using callbacks) */
633 rar_callback(rar);
634 return 0;
635end_function:
636 free_rar_device(rar);
637 return error;
638}
639
640static DEFINE_PCI_DEVICE_TABLE(rar_pci_id_tbl) = {
641 { PCI_VDEVICE(INTEL, 0x4110) },
642 { 0 }
643};
644
645MODULE_DEVICE_TABLE(pci, rar_pci_id_tbl);
646
647/* field for registering driver to PCI device */
648static struct pci_driver rar_pci_driver = {
649 .name = "rar_register_driver",
650 .id_table = rar_pci_id_tbl,
651 .probe = rar_probe,
652 /* Cannot be unplugged - no remove */
653};
654
655static int __init rar_init_handler(void)
656{
657 return pci_register_driver(&rar_pci_driver);
658}
659
660static void __exit rar_exit_handler(void)
661{
662 pci_unregister_driver(&rar_pci_driver);
663}
664
665module_init(rar_init_handler);
666module_exit(rar_exit_handler);
667
668MODULE_LICENSE("GPL");
669MODULE_DESCRIPTION("Intel Restricted Access Region Register Driver");
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index f00d0d1e0653..9215ed72bece 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -159,7 +159,7 @@ static inline int busy_loop(void) /* Wait till scu status is busy */
159/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */ 159/* Read/Write power control(PMIC in Langwell, MSIC in PenWell) registers */
160static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id) 160static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
161{ 161{
162 int i, nc, bytes, d; 162 int nc;
163 u32 offset = 0; 163 u32 offset = 0;
164 int err; 164 int err;
165 u8 cbuf[IPC_WWBUF_SIZE] = { }; 165 u8 cbuf[IPC_WWBUF_SIZE] = { };
@@ -174,55 +174,34 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
174 return -ENODEV; 174 return -ENODEV;
175 } 175 }
176 176
177 if (platform != MRST_CPU_CHIP_PENWELL) { 177 for (nc = 0; nc < count; nc++, offset += 2) {
178 bytes = 0; 178 cbuf[offset] = addr[nc];
179 d = 0; 179 cbuf[offset + 1] = addr[nc] >> 8;
180 for (i = 0; i < count; i++) { 180 }
181 cbuf[bytes++] = addr[i];
182 cbuf[bytes++] = addr[i] >> 8;
183 if (id != IPC_CMD_PCNTRL_R)
184 cbuf[bytes++] = data[d++];
185 if (id == IPC_CMD_PCNTRL_M)
186 cbuf[bytes++] = data[d++];
187 }
188 for (i = 0; i < bytes; i += 4)
189 ipc_data_writel(wbuf[i/4], i);
190 ipc_command(bytes << 16 | id << 12 | 0 << 8 | op);
191 } else {
192 for (nc = 0; nc < count; nc++, offset += 2) {
193 cbuf[offset] = addr[nc];
194 cbuf[offset + 1] = addr[nc] >> 8;
195 }
196 181
197 if (id == IPC_CMD_PCNTRL_R) { 182 if (id == IPC_CMD_PCNTRL_R) {
198 for (nc = 0, offset = 0; nc < count; nc++, offset += 4) 183 for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
199 ipc_data_writel(wbuf[nc], offset); 184 ipc_data_writel(wbuf[nc], offset);
200 ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op); 185 ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op);
201 } else if (id == IPC_CMD_PCNTRL_W) { 186 } else if (id == IPC_CMD_PCNTRL_W) {
202 for (nc = 0; nc < count; nc++, offset += 1) 187 for (nc = 0; nc < count; nc++, offset += 1)
203 cbuf[offset] = data[nc]; 188 cbuf[offset] = data[nc];
204 for (nc = 0, offset = 0; nc < count; nc++, offset += 4) 189 for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
205 ipc_data_writel(wbuf[nc], offset); 190 ipc_data_writel(wbuf[nc], offset);
206 ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op); 191 ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op);
207 } else if (id == IPC_CMD_PCNTRL_M) { 192 } else if (id == IPC_CMD_PCNTRL_M) {
208 cbuf[offset] = data[0]; 193 cbuf[offset] = data[0];
209 cbuf[offset + 1] = data[1]; 194 cbuf[offset + 1] = data[1];
210 ipc_data_writel(wbuf[0], 0); /* Write wbuff */ 195 ipc_data_writel(wbuf[0], 0); /* Write wbuff */
211 ipc_command(4 << 16 | id << 12 | 0 << 8 | op); 196 ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
212 }
213 } 197 }
214 198
215 err = busy_loop(); 199 err = busy_loop();
216 if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */ 200 if (id == IPC_CMD_PCNTRL_R) { /* Read rbuf */
217 /* Workaround: values are read as 0 without memcpy_fromio */ 201 /* Workaround: values are read as 0 without memcpy_fromio */
218 memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16); 202 memcpy_fromio(cbuf, ipcdev.ipc_base + 0x90, 16);
219 if (platform != MRST_CPU_CHIP_PENWELL) { 203 for (nc = 0; nc < count; nc++)
220 for (nc = 0, offset = 2; nc < count; nc++, offset += 3) 204 data[nc] = ipc_data_readb(nc);
221 data[nc] = ipc_data_readb(offset);
222 } else {
223 for (nc = 0; nc < count; nc++)
224 data[nc] = ipc_data_readb(nc);
225 }
226 } 205 }
227 mutex_unlock(&ipclock); 206 mutex_unlock(&ipclock);
228 return err; 207 return err;
@@ -503,148 +482,6 @@ int intel_scu_ipc_i2c_cntrl(u32 addr, u32 *data)
503} 482}
504EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl); 483EXPORT_SYMBOL(intel_scu_ipc_i2c_cntrl);
505 484
506#define IPC_FW_LOAD_ADDR 0xFFFC0000 /* Storage location for FW image */
507#define IPC_FW_UPDATE_MBOX_ADDR 0xFFFFDFF4 /* Mailbox between ipc and scu */
508#define IPC_MAX_FW_SIZE 262144 /* 256K storage size for loading the FW image */
509#define IPC_FW_MIP_HEADER_SIZE 2048 /* Firmware MIP header size */
510/* IPC inform SCU to get ready for update process */
511#define IPC_CMD_FW_UPDATE_READY 0x10FE
512/* IPC inform SCU to go for update process */
513#define IPC_CMD_FW_UPDATE_GO 0x20FE
514/* Status code for fw update */
515#define IPC_FW_UPDATE_SUCCESS 0x444f4e45 /* Status code 'DONE' */
516#define IPC_FW_UPDATE_BADN 0x4241444E /* Status code 'BADN' */
517#define IPC_FW_TXHIGH 0x54784849 /* Status code 'IPC_FW_TXHIGH' */
518#define IPC_FW_TXLOW 0x54784c4f /* Status code 'IPC_FW_TXLOW' */
519
520struct fw_update_mailbox {
521 u32 status;
522 u32 scu_flag;
523 u32 driver_flag;
524};
525
526
527/**
528 * intel_scu_ipc_fw_update - Firmware update utility
529 * @buffer: firmware buffer
530 * @length: size of firmware buffer
531 *
532 * This function provides an interface to load the firmware into
533 * the SCU. Returns 0 on success or -1 on failure
534 */
535int intel_scu_ipc_fw_update(u8 *buffer, u32 length)
536{
537 void __iomem *fw_update_base;
538 struct fw_update_mailbox __iomem *mailbox = NULL;
539 int retry_cnt = 0;
540 u32 status;
541
542 mutex_lock(&ipclock);
543 fw_update_base = ioremap_nocache(IPC_FW_LOAD_ADDR, (128*1024));
544 if (fw_update_base == NULL) {
545 mutex_unlock(&ipclock);
546 return -ENOMEM;
547 }
548 mailbox = ioremap_nocache(IPC_FW_UPDATE_MBOX_ADDR,
549 sizeof(struct fw_update_mailbox));
550 if (mailbox == NULL) {
551 iounmap(fw_update_base);
552 mutex_unlock(&ipclock);
553 return -ENOMEM;
554 }
555
556 ipc_command(IPC_CMD_FW_UPDATE_READY);
557
558 /* Intitialize mailbox */
559 writel(0, &mailbox->status);
560 writel(0, &mailbox->scu_flag);
561 writel(0, &mailbox->driver_flag);
562
563 /* Driver copies the 2KB MIP header to SRAM at 0xFFFC0000*/
564 memcpy_toio(fw_update_base, buffer, 0x800);
565
566 /* Driver sends "FW Update" IPC command (CMD_ID 0xFE; MSG_ID 0x02).
567 * Upon receiving this command, SCU will write the 2K MIP header
568 * from 0xFFFC0000 into NAND.
569 * SCU will write a status code into the Mailbox, and then set scu_flag.
570 */
571
572 ipc_command(IPC_CMD_FW_UPDATE_GO);
573
574 /*Driver stalls until scu_flag is set */
575 while (readl(&mailbox->scu_flag) != 1) {
576 rmb();
577 mdelay(1);
578 }
579
580 /* Driver checks Mailbox status.
581 * If the status is 'BADN', then abort (bad NAND).
582 * If the status is 'IPC_FW_TXLOW', then continue.
583 */
584 while (readl(&mailbox->status) != IPC_FW_TXLOW) {
585 rmb();
586 mdelay(10);
587 }
588 mdelay(10);
589
590update_retry:
591 if (retry_cnt > 5)
592 goto update_end;
593
594 if (readl(&mailbox->status) != IPC_FW_TXLOW)
595 goto update_end;
596 buffer = buffer + 0x800;
597 memcpy_toio(fw_update_base, buffer, 0x20000);
598 writel(1, &mailbox->driver_flag);
599 while (readl(&mailbox->scu_flag) == 1) {
600 rmb();
601 mdelay(1);
602 }
603
604 /* check for 'BADN' */
605 if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN)
606 goto update_end;
607
608 while (readl(&mailbox->status) != IPC_FW_TXHIGH) {
609 rmb();
610 mdelay(10);
611 }
612 mdelay(10);
613
614 if (readl(&mailbox->status) != IPC_FW_TXHIGH)
615 goto update_end;
616
617 buffer = buffer + 0x20000;
618 memcpy_toio(fw_update_base, buffer, 0x20000);
619 writel(0, &mailbox->driver_flag);
620
621 while (mailbox->scu_flag == 0) {
622 rmb();
623 mdelay(1);
624 }
625
626 /* check for 'BADN' */
627 if (readl(&mailbox->status) == IPC_FW_UPDATE_BADN)
628 goto update_end;
629
630 if (readl(&mailbox->status) == IPC_FW_TXLOW) {
631 ++retry_cnt;
632 goto update_retry;
633 }
634
635update_end:
636 status = readl(&mailbox->status);
637
638 iounmap(fw_update_base);
639 iounmap(mailbox);
640 mutex_unlock(&ipclock);
641
642 if (status == IPC_FW_UPDATE_SUCCESS)
643 return 0;
644 return -EIO;
645}
646EXPORT_SYMBOL(intel_scu_ipc_fw_update);
647
648/* 485/*
649 * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1 486 * Interrupt handler gets called when ioc bit of IPC_COMMAND_REG set to 1
650 * When ioc bit is set to 1, caller api must wait for interrupt handler called 487 * When ioc bit is set to 1, caller api must wait for interrupt handler called
@@ -727,7 +564,6 @@ static void ipc_remove(struct pci_dev *pdev)
727} 564}
728 565
729static DEFINE_PCI_DEVICE_TABLE(pci_ids) = { 566static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
730 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080e)},
731 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)}, 567 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x082a)},
732 { 0,} 568 { 0,}
733}; 569};
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
index 2d0f9136ea9a..02bc5a6343c3 100644
--- a/drivers/platform/x86/intel_scu_ipcutil.c
+++ b/drivers/platform/x86/intel_scu_ipcutil.c
@@ -26,13 +26,10 @@
26 26
27static int major; 27static int major;
28 28
29#define MAX_FW_SIZE 264192
30
31/* ioctl commnds */ 29/* ioctl commnds */
32#define INTE_SCU_IPC_REGISTER_READ 0 30#define INTE_SCU_IPC_REGISTER_READ 0
33#define INTE_SCU_IPC_REGISTER_WRITE 1 31#define INTE_SCU_IPC_REGISTER_WRITE 1
34#define INTE_SCU_IPC_REGISTER_UPDATE 2 32#define INTE_SCU_IPC_REGISTER_UPDATE 2
35#define INTE_SCU_IPC_FW_UPDATE 0xA2
36 33
37struct scu_ipc_data { 34struct scu_ipc_data {
38 u32 count; /* No. of registers */ 35 u32 count; /* No. of registers */
@@ -88,27 +85,14 @@ static long scu_ipc_ioctl(struct file *fp, unsigned int cmd,
88 if (!capable(CAP_SYS_RAWIO)) 85 if (!capable(CAP_SYS_RAWIO))
89 return -EPERM; 86 return -EPERM;
90 87
91 if (cmd == INTE_SCU_IPC_FW_UPDATE) { 88 if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
92 u8 *fwbuf = kmalloc(MAX_FW_SIZE, GFP_KERNEL); 89 return -EFAULT;
93 if (fwbuf == NULL) 90 ret = scu_reg_access(cmd, &data);
94 return -ENOMEM; 91 if (ret < 0)
95 if (copy_from_user(fwbuf, (u8 *)arg, MAX_FW_SIZE)) { 92 return ret;
96 kfree(fwbuf); 93 if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
97 return -EFAULT; 94 return -EFAULT;
98 } 95 return 0;
99 ret = intel_scu_ipc_fw_update(fwbuf, MAX_FW_SIZE);
100 kfree(fwbuf);
101 return ret;
102 } else {
103 if (copy_from_user(&data, argp, sizeof(struct scu_ipc_data)))
104 return -EFAULT;
105 ret = scu_reg_access(cmd, &data);
106 if (ret < 0)
107 return ret;
108 if (copy_to_user(argp, &data, sizeof(struct scu_ipc_data)))
109 return -EFAULT;
110 return 0;
111 }
112} 96}
113 97
114static const struct file_operations scu_ipc_fops = { 98static const struct file_operations scu_ipc_fops = {
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index fd73ea89b857..e2a34b42ddc1 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -17,10 +17,18 @@
17#include <linux/delay.h> 17#include <linux/delay.h>
18#include <linux/pci.h> 18#include <linux/pci.h>
19#include <linux/backlight.h> 19#include <linux/backlight.h>
20#include <linux/leds.h>
20#include <linux/fb.h> 21#include <linux/fb.h>
21#include <linux/dmi.h> 22#include <linux/dmi.h>
22#include <linux/platform_device.h> 23#include <linux/platform_device.h>
23#include <linux/rfkill.h> 24#include <linux/rfkill.h>
25#include <linux/acpi.h>
26#include <linux/seq_file.h>
27#include <linux/debugfs.h>
28#include <linux/ctype.h>
29#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
30#include <acpi/video.h>
31#endif
24 32
25/* 33/*
26 * This driver is needed because a number of Samsung laptops do not hook 34 * This driver is needed because a number of Samsung laptops do not hook
@@ -41,9 +49,20 @@
41#define SABI_IFACE_COMPLETE 0x04 49#define SABI_IFACE_COMPLETE 0x04
42#define SABI_IFACE_DATA 0x05 50#define SABI_IFACE_DATA 0x05
43 51
44/* Structure to get data back to the calling function */ 52#define WL_STATUS_WLAN 0x0
45struct sabi_retval { 53#define WL_STATUS_BT 0x2
46 u8 retval[20]; 54
55/* Structure get/set data using sabi */
56struct sabi_data {
57 union {
58 struct {
59 u32 d0;
60 u32 d1;
61 u16 d2;
62 u8 d3;
63 };
64 u8 data[11];
65 };
47}; 66};
48 67
49struct sabi_header_offsets { 68struct sabi_header_offsets {
@@ -60,8 +79,8 @@ struct sabi_commands {
60 * Brightness is 0 - 8, as described above. 79 * Brightness is 0 - 8, as described above.
61 * Value 0 is for the BIOS to use 80 * Value 0 is for the BIOS to use
62 */ 81 */
63 u8 get_brightness; 82 u16 get_brightness;
64 u8 set_brightness; 83 u16 set_brightness;
65 84
66 /* 85 /*
67 * first byte: 86 * first byte:
@@ -72,40 +91,56 @@ struct sabi_commands {
72 * 0x03 - 3G is on 91 * 0x03 - 3G is on
73 * TODO, verify 3G is correct, that doesn't seem right... 92 * TODO, verify 3G is correct, that doesn't seem right...
74 */ 93 */
75 u8 get_wireless_button; 94 u16 get_wireless_button;
76 u8 set_wireless_button; 95 u16 set_wireless_button;
77 96
78 /* 0 is off, 1 is on */ 97 /* 0 is off, 1 is on */
79 u8 get_backlight; 98 u16 get_backlight;
80 u8 set_backlight; 99 u16 set_backlight;
81 100
82 /* 101 /*
83 * 0x80 or 0x00 - no action 102 * 0x80 or 0x00 - no action
84 * 0x81 - recovery key pressed 103 * 0x81 - recovery key pressed
85 */ 104 */
86 u8 get_recovery_mode; 105 u16 get_recovery_mode;
87 u8 set_recovery_mode; 106 u16 set_recovery_mode;
88 107
89 /* 108 /*
90 * on seclinux: 0 is low, 1 is high, 109 * on seclinux: 0 is low, 1 is high,
91 * on swsmi: 0 is normal, 1 is silent, 2 is turbo 110 * on swsmi: 0 is normal, 1 is silent, 2 is turbo
92 */ 111 */
93 u8 get_performance_level; 112 u16 get_performance_level;
94 u8 set_performance_level; 113 u16 set_performance_level;
114
115 /* 0x80 is off, 0x81 is on */
116 u16 get_battery_life_extender;
117 u16 set_battery_life_extender;
118
119 /* 0x80 is off, 0x81 is on */
120 u16 get_usb_charge;
121 u16 set_usb_charge;
122
123 /* the first byte is for bluetooth and the third one is for wlan */
124 u16 get_wireless_status;
125 u16 set_wireless_status;
126
127 /* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
128 u16 kbd_backlight;
95 129
96 /* 130 /*
97 * Tell the BIOS that Linux is running on this machine. 131 * Tell the BIOS that Linux is running on this machine.
98 * 81 is on, 80 is off 132 * 81 is on, 80 is off
99 */ 133 */
100 u8 set_linux; 134 u16 set_linux;
101}; 135};
102 136
103struct sabi_performance_level { 137struct sabi_performance_level {
104 const char *name; 138 const char *name;
105 u8 value; 139 u16 value;
106}; 140};
107 141
108struct sabi_config { 142struct sabi_config {
143 int sabi_version;
109 const char *test_string; 144 const char *test_string;
110 u16 main_function; 145 u16 main_function;
111 const struct sabi_header_offsets header_offsets; 146 const struct sabi_header_offsets header_offsets;
@@ -117,6 +152,10 @@ struct sabi_config {
117 152
118static const struct sabi_config sabi_configs[] = { 153static const struct sabi_config sabi_configs[] = {
119 { 154 {
155 /* I don't know if it is really 2, but it it is
156 * less than 3 anyway */
157 .sabi_version = 2,
158
120 .test_string = "SECLINUX", 159 .test_string = "SECLINUX",
121 160
122 .main_function = 0x4c49, 161 .main_function = 0x4c49,
@@ -146,6 +185,17 @@ static const struct sabi_config sabi_configs[] = {
146 .get_performance_level = 0x08, 185 .get_performance_level = 0x08,
147 .set_performance_level = 0x09, 186 .set_performance_level = 0x09,
148 187
188 .get_battery_life_extender = 0xFFFF,
189 .set_battery_life_extender = 0xFFFF,
190
191 .get_usb_charge = 0xFFFF,
192 .set_usb_charge = 0xFFFF,
193
194 .get_wireless_status = 0xFFFF,
195 .set_wireless_status = 0xFFFF,
196
197 .kbd_backlight = 0xFFFF,
198
149 .set_linux = 0x0a, 199 .set_linux = 0x0a,
150 }, 200 },
151 201
@@ -164,6 +214,8 @@ static const struct sabi_config sabi_configs[] = {
164 .max_brightness = 8, 214 .max_brightness = 8,
165 }, 215 },
166 { 216 {
217 .sabi_version = 3,
218
167 .test_string = "SwSmi@", 219 .test_string = "SwSmi@",
168 220
169 .main_function = 0x5843, 221 .main_function = 0x5843,
@@ -193,6 +245,17 @@ static const struct sabi_config sabi_configs[] = {
193 .get_performance_level = 0x31, 245 .get_performance_level = 0x31,
194 .set_performance_level = 0x32, 246 .set_performance_level = 0x32,
195 247
248 .get_battery_life_extender = 0x65,
249 .set_battery_life_extender = 0x66,
250
251 .get_usb_charge = 0x67,
252 .set_usb_charge = 0x68,
253
254 .get_wireless_status = 0x69,
255 .set_wireless_status = 0x6a,
256
257 .kbd_backlight = 0x78,
258
196 .set_linux = 0xff, 259 .set_linux = 0xff,
197 }, 260 },
198 261
@@ -217,16 +280,82 @@ static const struct sabi_config sabi_configs[] = {
217 { }, 280 { },
218}; 281};
219 282
220static const struct sabi_config *sabi_config; 283/*
284 * samsung-laptop/ - debugfs root directory
285 * f0000_segment - dump f0000 segment
286 * command - current command
287 * data - current data
288 * d0, d1, d2, d3 - data fields
289 * call - call SABI using command and data
290 *
291 * This allow to call arbitrary sabi commands wihout
292 * modifying the driver at all.
293 * For example, setting the keyboard backlight brightness to 5
294 *
295 * echo 0x78 > command
296 * echo 0x0582 > d0
297 * echo 0 > d1
298 * echo 0 > d2
299 * echo 0 > d3
300 * cat call
301 */
302
303struct samsung_laptop_debug {
304 struct dentry *root;
305 struct sabi_data data;
306 u16 command;
307
308 struct debugfs_blob_wrapper f0000_wrapper;
309 struct debugfs_blob_wrapper data_wrapper;
310 struct debugfs_blob_wrapper sdiag_wrapper;
311};
312
313struct samsung_laptop;
314
315struct samsung_rfkill {
316 struct samsung_laptop *samsung;
317 struct rfkill *rfkill;
318 enum rfkill_type type;
319};
320
321struct samsung_laptop {
322 const struct sabi_config *config;
323
324 void __iomem *sabi;
325 void __iomem *sabi_iface;
326 void __iomem *f0000_segment;
327
328 struct mutex sabi_mutex;
329
330 struct platform_device *platform_device;
331 struct backlight_device *backlight_device;
332
333 struct samsung_rfkill wlan;
334 struct samsung_rfkill bluetooth;
335
336 struct led_classdev kbd_led;
337 int kbd_led_wk;
338 struct workqueue_struct *led_workqueue;
339 struct work_struct kbd_led_work;
340
341 struct samsung_laptop_debug debug;
342 struct samsung_quirks *quirks;
343
344 bool handle_backlight;
345 bool has_stepping_quirk;
346
347 char sdiag[64];
348};
349
350struct samsung_quirks {
351 bool broken_acpi_video;
352};
353
354static struct samsung_quirks samsung_unknown = {};
221 355
222static void __iomem *sabi; 356static struct samsung_quirks samsung_broken_acpi_video = {
223static void __iomem *sabi_iface; 357 .broken_acpi_video = true,
224static void __iomem *f0000_segment; 358};
225static struct backlight_device *backlight_device;
226static struct mutex sabi_mutex;
227static struct platform_device *sdev;
228static struct rfkill *rfk;
229static bool has_stepping_quirk;
230 359
231static bool force; 360static bool force;
232module_param(force, bool, 0); 361module_param(force, bool, 0);
@@ -237,176 +366,143 @@ static bool debug;
237module_param(debug, bool, S_IRUGO | S_IWUSR); 366module_param(debug, bool, S_IRUGO | S_IWUSR);
238MODULE_PARM_DESC(debug, "Debug enabled or not"); 367MODULE_PARM_DESC(debug, "Debug enabled or not");
239 368
240static int sabi_get_command(u8 command, struct sabi_retval *sretval) 369static int sabi_command(struct samsung_laptop *samsung, u16 command,
370 struct sabi_data *in,
371 struct sabi_data *out)
241{ 372{
242 int retval = 0; 373 const struct sabi_config *config = samsung->config;
243 u16 port = readw(sabi + sabi_config->header_offsets.port); 374 int ret = 0;
375 u16 port = readw(samsung->sabi + config->header_offsets.port);
244 u8 complete, iface_data; 376 u8 complete, iface_data;
245 377
246 mutex_lock(&sabi_mutex); 378 mutex_lock(&samsung->sabi_mutex);
247
248 /* enable memory to be able to write to it */
249 outb(readb(sabi + sabi_config->header_offsets.en_mem), port);
250
251 /* write out the command */
252 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN);
253 writew(command, sabi_iface + SABI_IFACE_SUB);
254 writeb(0, sabi_iface + SABI_IFACE_COMPLETE);
255 outb(readb(sabi + sabi_config->header_offsets.iface_func), port);
256
257 /* write protect memory to make it safe */
258 outb(readb(sabi + sabi_config->header_offsets.re_mem), port);
259 379
260 /* see if the command actually succeeded */ 380 if (debug) {
261 complete = readb(sabi_iface + SABI_IFACE_COMPLETE); 381 if (in)
262 iface_data = readb(sabi_iface + SABI_IFACE_DATA); 382 pr_info("SABI command:0x%04x "
263 if (complete != 0xaa || iface_data == 0xff) { 383 "data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
264 pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", 384 command, in->d0, in->d1, in->d2, in->d3);
265 command, complete, iface_data); 385 else
266 retval = -EINVAL; 386 pr_info("SABI command:0x%04x", command);
267 goto exit;
268 } 387 }
269 /*
270 * Save off the data into a structure so the caller use it.
271 * Right now we only want the first 4 bytes,
272 * There are commands that need more, but not for the ones we
273 * currently care about.
274 */
275 sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA);
276 sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1);
277 sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2);
278 sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3);
279
280exit:
281 mutex_unlock(&sabi_mutex);
282 return retval;
283
284}
285
286static int sabi_set_command(u8 command, u8 data)
287{
288 int retval = 0;
289 u16 port = readw(sabi + sabi_config->header_offsets.port);
290 u8 complete, iface_data;
291
292 mutex_lock(&sabi_mutex);
293 388
294 /* enable memory to be able to write to it */ 389 /* enable memory to be able to write to it */
295 outb(readb(sabi + sabi_config->header_offsets.en_mem), port); 390 outb(readb(samsung->sabi + config->header_offsets.en_mem), port);
296 391
297 /* write out the command */ 392 /* write out the command */
298 writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); 393 writew(config->main_function, samsung->sabi_iface + SABI_IFACE_MAIN);
299 writew(command, sabi_iface + SABI_IFACE_SUB); 394 writew(command, samsung->sabi_iface + SABI_IFACE_SUB);
300 writeb(0, sabi_iface + SABI_IFACE_COMPLETE); 395 writeb(0, samsung->sabi_iface + SABI_IFACE_COMPLETE);
301 writeb(data, sabi_iface + SABI_IFACE_DATA); 396 if (in) {
302 outb(readb(sabi + sabi_config->header_offsets.iface_func), port); 397 writel(in->d0, samsung->sabi_iface + SABI_IFACE_DATA);
398 writel(in->d1, samsung->sabi_iface + SABI_IFACE_DATA + 4);
399 writew(in->d2, samsung->sabi_iface + SABI_IFACE_DATA + 8);
400 writeb(in->d3, samsung->sabi_iface + SABI_IFACE_DATA + 10);
401 }
402 outb(readb(samsung->sabi + config->header_offsets.iface_func), port);
303 403
304 /* write protect memory to make it safe */ 404 /* write protect memory to make it safe */
305 outb(readb(sabi + sabi_config->header_offsets.re_mem), port); 405 outb(readb(samsung->sabi + config->header_offsets.re_mem), port);
306 406
307 /* see if the command actually succeeded */ 407 /* see if the command actually succeeded */
308 complete = readb(sabi_iface + SABI_IFACE_COMPLETE); 408 complete = readb(samsung->sabi_iface + SABI_IFACE_COMPLETE);
309 iface_data = readb(sabi_iface + SABI_IFACE_DATA); 409 iface_data = readb(samsung->sabi_iface + SABI_IFACE_DATA);
410
411 /* iface_data = 0xFF happens when a command is not known
412 * so we only add a warning in debug mode since we will
413 * probably issue some unknown command at startup to find
414 * out which features are supported */
415 if (complete != 0xaa || (iface_data == 0xff && debug))
416 pr_warn("SABI command 0x%04x failed with"
417 " completion flag 0x%02x and interface data 0x%02x",
418 command, complete, iface_data);
419
310 if (complete != 0xaa || iface_data == 0xff) { 420 if (complete != 0xaa || iface_data == 0xff) {
311 pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", 421 ret = -EINVAL;
312 command, complete, iface_data); 422 goto exit;
313 retval = -EINVAL;
314 } 423 }
315 424
316 mutex_unlock(&sabi_mutex); 425 if (out) {
317 return retval; 426 out->d0 = readl(samsung->sabi_iface + SABI_IFACE_DATA);
318} 427 out->d1 = readl(samsung->sabi_iface + SABI_IFACE_DATA + 4);
319 428 out->d2 = readw(samsung->sabi_iface + SABI_IFACE_DATA + 2);
320static void test_backlight(void) 429 out->d3 = readb(samsung->sabi_iface + SABI_IFACE_DATA + 1);
321{ 430 }
322 struct sabi_retval sretval;
323
324 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
325 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
326
327 sabi_set_command(sabi_config->commands.set_backlight, 0);
328 printk(KERN_DEBUG "backlight should be off\n");
329
330 sabi_get_command(sabi_config->commands.get_backlight, &sretval);
331 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]);
332
333 msleep(1000);
334 431
335 sabi_set_command(sabi_config->commands.set_backlight, 1); 432 if (debug && out) {
336 printk(KERN_DEBUG "backlight should be on\n"); 433 pr_info("SABI return data:{0x%08x, 0x%08x, 0x%04x, 0x%02x}",
434 out->d0, out->d1, out->d2, out->d3);
435 }
337 436
338 sabi_get_command(sabi_config->commands.get_backlight, &sretval); 437exit:
339 printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); 438 mutex_unlock(&samsung->sabi_mutex);
439 return ret;
340} 440}
341 441
342static void test_wireless(void) 442/* simple wrappers usable with most commands */
443static int sabi_set_commandb(struct samsung_laptop *samsung,
444 u16 command, u8 data)
343{ 445{
344 struct sabi_retval sretval; 446 struct sabi_data in = { { { .d0 = 0, .d1 = 0, .d2 = 0, .d3 = 0 } } };
345
346 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
347 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
348
349 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
350 printk(KERN_DEBUG "wireless led should be off\n");
351
352 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
353 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
354 447
355 msleep(1000); 448 in.data[0] = data;
356 449 return sabi_command(samsung, command, &in, NULL);
357 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
358 printk(KERN_DEBUG "wireless led should be on\n");
359
360 sabi_get_command(sabi_config->commands.get_wireless_button, &sretval);
361 printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]);
362} 450}
363 451
364static u8 read_brightness(void) 452static int read_brightness(struct samsung_laptop *samsung)
365{ 453{
366 struct sabi_retval sretval; 454 const struct sabi_config *config = samsung->config;
455 const struct sabi_commands *commands = &samsung->config->commands;
456 struct sabi_data sretval;
367 int user_brightness = 0; 457 int user_brightness = 0;
368 int retval; 458 int retval;
369 459
370 retval = sabi_get_command(sabi_config->commands.get_brightness, 460 retval = sabi_command(samsung, commands->get_brightness,
371 &sretval); 461 NULL, &sretval);
372 if (!retval) { 462 if (retval)
373 user_brightness = sretval.retval[0]; 463 return retval;
374 if (user_brightness > sabi_config->min_brightness) 464
375 user_brightness -= sabi_config->min_brightness; 465 user_brightness = sretval.data[0];
376 else 466 if (user_brightness > config->min_brightness)
377 user_brightness = 0; 467 user_brightness -= config->min_brightness;
378 } 468 else
469 user_brightness = 0;
470
379 return user_brightness; 471 return user_brightness;
380} 472}
381 473
382static void set_brightness(u8 user_brightness) 474static void set_brightness(struct samsung_laptop *samsung, u8 user_brightness)
383{ 475{
384 u8 user_level = user_brightness + sabi_config->min_brightness; 476 const struct sabi_config *config = samsung->config;
477 const struct sabi_commands *commands = &samsung->config->commands;
478 u8 user_level = user_brightness + config->min_brightness;
385 479
386 if (has_stepping_quirk && user_level != 0) { 480 if (samsung->has_stepping_quirk && user_level != 0) {
387 /* 481 /*
388 * short circuit if the specified level is what's already set 482 * short circuit if the specified level is what's already set
389 * to prevent the screen from flickering needlessly 483 * to prevent the screen from flickering needlessly
390 */ 484 */
391 if (user_brightness == read_brightness()) 485 if (user_brightness == read_brightness(samsung))
392 return; 486 return;
393 487
394 sabi_set_command(sabi_config->commands.set_brightness, 0); 488 sabi_set_commandb(samsung, commands->set_brightness, 0);
395 } 489 }
396 490
397 sabi_set_command(sabi_config->commands.set_brightness, user_level); 491 sabi_set_commandb(samsung, commands->set_brightness, user_level);
398} 492}
399 493
400static int get_brightness(struct backlight_device *bd) 494static int get_brightness(struct backlight_device *bd)
401{ 495{
402 return (int)read_brightness(); 496 struct samsung_laptop *samsung = bl_get_data(bd);
497
498 return read_brightness(samsung);
403} 499}
404 500
405static void check_for_stepping_quirk(void) 501static void check_for_stepping_quirk(struct samsung_laptop *samsung)
406{ 502{
407 u8 initial_level; 503 int initial_level;
408 u8 check_level; 504 int check_level;
409 u8 orig_level = read_brightness(); 505 int orig_level = read_brightness(samsung);
410 506
411 /* 507 /*
412 * Some laptops exhibit the strange behaviour of stepping toward 508 * Some laptops exhibit the strange behaviour of stepping toward
@@ -416,34 +512,38 @@ static void check_for_stepping_quirk(void)
416 */ 512 */
417 513
418 if (orig_level == 0) 514 if (orig_level == 0)
419 set_brightness(1); 515 set_brightness(samsung, 1);
420 516
421 initial_level = read_brightness(); 517 initial_level = read_brightness(samsung);
422 518
423 if (initial_level <= 2) 519 if (initial_level <= 2)
424 check_level = initial_level + 2; 520 check_level = initial_level + 2;
425 else 521 else
426 check_level = initial_level - 2; 522 check_level = initial_level - 2;
427 523
428 has_stepping_quirk = false; 524 samsung->has_stepping_quirk = false;
429 set_brightness(check_level); 525 set_brightness(samsung, check_level);
430 526
431 if (read_brightness() != check_level) { 527 if (read_brightness(samsung) != check_level) {
432 has_stepping_quirk = true; 528 samsung->has_stepping_quirk = true;
433 pr_info("enabled workaround for brightness stepping quirk\n"); 529 pr_info("enabled workaround for brightness stepping quirk\n");
434 } 530 }
435 531
436 set_brightness(orig_level); 532 set_brightness(samsung, orig_level);
437} 533}
438 534
439static int update_status(struct backlight_device *bd) 535static int update_status(struct backlight_device *bd)
440{ 536{
441 set_brightness(bd->props.brightness); 537 struct samsung_laptop *samsung = bl_get_data(bd);
538 const struct sabi_commands *commands = &samsung->config->commands;
539
540 set_brightness(samsung, bd->props.brightness);
442 541
443 if (bd->props.power == FB_BLANK_UNBLANK) 542 if (bd->props.power == FB_BLANK_UNBLANK)
444 sabi_set_command(sabi_config->commands.set_backlight, 1); 543 sabi_set_commandb(samsung, commands->set_backlight, 1);
445 else 544 else
446 sabi_set_command(sabi_config->commands.set_backlight, 0); 545 sabi_set_commandb(samsung, commands->set_backlight, 0);
546
447 return 0; 547 return 0;
448} 548}
449 549
@@ -452,66 +552,101 @@ static const struct backlight_ops backlight_ops = {
452 .update_status = update_status, 552 .update_status = update_status,
453}; 553};
454 554
455static int rfkill_set(void *data, bool blocked) 555static int seclinux_rfkill_set(void *data, bool blocked)
456{ 556{
457 /* Do something with blocked...*/ 557 struct samsung_rfkill *srfkill = data;
458 /* 558 struct samsung_laptop *samsung = srfkill->samsung;
459 * blocked == false is on 559 const struct sabi_commands *commands = &samsung->config->commands;
460 * blocked == true is off
461 */
462 if (blocked)
463 sabi_set_command(sabi_config->commands.set_wireless_button, 0);
464 else
465 sabi_set_command(sabi_config->commands.set_wireless_button, 1);
466 560
467 return 0; 561 return sabi_set_commandb(samsung, commands->set_wireless_button,
562 !blocked);
468} 563}
469 564
470static struct rfkill_ops rfkill_ops = { 565static struct rfkill_ops seclinux_rfkill_ops = {
471 .set_block = rfkill_set, 566 .set_block = seclinux_rfkill_set,
472}; 567};
473 568
474static int init_wireless(struct platform_device *sdev) 569static int swsmi_wireless_status(struct samsung_laptop *samsung,
570 struct sabi_data *data)
475{ 571{
476 int retval; 572 const struct sabi_commands *commands = &samsung->config->commands;
477 573
478 rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, 574 return sabi_command(samsung, commands->get_wireless_status,
479 &rfkill_ops, NULL); 575 NULL, data);
480 if (!rfk) 576}
481 return -ENOMEM;
482
483 retval = rfkill_register(rfk);
484 if (retval) {
485 rfkill_destroy(rfk);
486 return -ENODEV;
487 }
488 577
489 return 0; 578static int swsmi_rfkill_set(void *priv, bool blocked)
579{
580 struct samsung_rfkill *srfkill = priv;
581 struct samsung_laptop *samsung = srfkill->samsung;
582 const struct sabi_commands *commands = &samsung->config->commands;
583 struct sabi_data data;
584 int ret, i;
585
586 ret = swsmi_wireless_status(samsung, &data);
587 if (ret)
588 return ret;
589
590 /* Don't set the state for non-present devices */
591 for (i = 0; i < 4; i++)
592 if (data.data[i] == 0x02)
593 data.data[1] = 0;
594
595 if (srfkill->type == RFKILL_TYPE_WLAN)
596 data.data[WL_STATUS_WLAN] = !blocked;
597 else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
598 data.data[WL_STATUS_BT] = !blocked;
599
600 return sabi_command(samsung, commands->set_wireless_status,
601 &data, &data);
490} 602}
491 603
492static void destroy_wireless(void) 604static void swsmi_rfkill_query(struct rfkill *rfkill, void *priv)
493{ 605{
494 rfkill_unregister(rfk); 606 struct samsung_rfkill *srfkill = priv;
495 rfkill_destroy(rfk); 607 struct samsung_laptop *samsung = srfkill->samsung;
608 struct sabi_data data;
609 int ret;
610
611 ret = swsmi_wireless_status(samsung, &data);
612 if (ret)
613 return ;
614
615 if (srfkill->type == RFKILL_TYPE_WLAN)
616 ret = data.data[WL_STATUS_WLAN];
617 else if (srfkill->type == RFKILL_TYPE_BLUETOOTH)
618 ret = data.data[WL_STATUS_BT];
619 else
620 return ;
621
622 rfkill_set_sw_state(rfkill, !ret);
496} 623}
497 624
625static struct rfkill_ops swsmi_rfkill_ops = {
626 .set_block = swsmi_rfkill_set,
627 .query = swsmi_rfkill_query,
628};
629
498static ssize_t get_performance_level(struct device *dev, 630static ssize_t get_performance_level(struct device *dev,
499 struct device_attribute *attr, char *buf) 631 struct device_attribute *attr, char *buf)
500{ 632{
501 struct sabi_retval sretval; 633 struct samsung_laptop *samsung = dev_get_drvdata(dev);
634 const struct sabi_config *config = samsung->config;
635 const struct sabi_commands *commands = &config->commands;
636 struct sabi_data sretval;
502 int retval; 637 int retval;
503 int i; 638 int i;
504 639
505 /* Read the state */ 640 /* Read the state */
506 retval = sabi_get_command(sabi_config->commands.get_performance_level, 641 retval = sabi_command(samsung, commands->get_performance_level,
507 &sretval); 642 NULL, &sretval);
508 if (retval) 643 if (retval)
509 return retval; 644 return retval;
510 645
511 /* The logic is backwards, yeah, lots of fun... */ 646 /* The logic is backwards, yeah, lots of fun... */
512 for (i = 0; sabi_config->performance_levels[i].name; ++i) { 647 for (i = 0; config->performance_levels[i].name; ++i) {
513 if (sretval.retval[0] == sabi_config->performance_levels[i].value) 648 if (sretval.data[0] == config->performance_levels[i].value)
514 return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); 649 return sprintf(buf, "%s\n", config->performance_levels[i].name);
515 } 650 }
516 return sprintf(buf, "%s\n", "unknown"); 651 return sprintf(buf, "%s\n", "unknown");
517} 652}
@@ -520,269 +655,178 @@ static ssize_t set_performance_level(struct device *dev,
520 struct device_attribute *attr, const char *buf, 655 struct device_attribute *attr, const char *buf,
521 size_t count) 656 size_t count)
522{ 657{
523 if (count >= 1) { 658 struct samsung_laptop *samsung = dev_get_drvdata(dev);
524 int i; 659 const struct sabi_config *config = samsung->config;
525 for (i = 0; sabi_config->performance_levels[i].name; ++i) { 660 const struct sabi_commands *commands = &config->commands;
526 const struct sabi_performance_level *level = 661 int i;
527 &sabi_config->performance_levels[i]; 662
528 if (!strncasecmp(level->name, buf, strlen(level->name))) { 663 if (count < 1)
529 sabi_set_command(sabi_config->commands.set_performance_level, 664 return count;
530 level->value); 665
531 break; 666 for (i = 0; config->performance_levels[i].name; ++i) {
532 } 667 const struct sabi_performance_level *level =
668 &config->performance_levels[i];
669 if (!strncasecmp(level->name, buf, strlen(level->name))) {
670 sabi_set_commandb(samsung,
671 commands->set_performance_level,
672 level->value);
673 break;
533 } 674 }
534 if (!sabi_config->performance_levels[i].name)
535 return -EINVAL;
536 } 675 }
676
677 if (!config->performance_levels[i].name)
678 return -EINVAL;
679
537 return count; 680 return count;
538} 681}
682
539static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, 683static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO,
540 get_performance_level, set_performance_level); 684 get_performance_level, set_performance_level);
541 685
686static int read_battery_life_extender(struct samsung_laptop *samsung)
687{
688 const struct sabi_commands *commands = &samsung->config->commands;
689 struct sabi_data data;
690 int retval;
691
692 if (commands->get_battery_life_extender == 0xFFFF)
693 return -ENODEV;
694
695 memset(&data, 0, sizeof(data));
696 data.data[0] = 0x80;
697 retval = sabi_command(samsung, commands->get_battery_life_extender,
698 &data, &data);
542 699
543static int __init dmi_check_cb(const struct dmi_system_id *id) 700 if (retval)
701 return retval;
702
703 if (data.data[0] != 0 && data.data[0] != 1)
704 return -ENODEV;
705
706 return data.data[0];
707}
708
709static int write_battery_life_extender(struct samsung_laptop *samsung,
710 int enabled)
544{ 711{
545 pr_info("found laptop model '%s'\n", 712 const struct sabi_commands *commands = &samsung->config->commands;
546 id->ident); 713 struct sabi_data data;
547 return 1; 714
715 memset(&data, 0, sizeof(data));
716 data.data[0] = 0x80 | enabled;
717 return sabi_command(samsung, commands->set_battery_life_extender,
718 &data, NULL);
548} 719}
549 720
550static struct dmi_system_id __initdata samsung_dmi_table[] = { 721static ssize_t get_battery_life_extender(struct device *dev,
551 { 722 struct device_attribute *attr,
552 .ident = "N128", 723 char *buf)
553 .matches = { 724{
554 DMI_MATCH(DMI_SYS_VENDOR, 725 struct samsung_laptop *samsung = dev_get_drvdata(dev);
555 "SAMSUNG ELECTRONICS CO., LTD."), 726 int ret;
556 DMI_MATCH(DMI_PRODUCT_NAME, "N128"), 727
557 DMI_MATCH(DMI_BOARD_NAME, "N128"), 728 ret = read_battery_life_extender(samsung);
558 }, 729 if (ret < 0)
559 .callback = dmi_check_cb, 730 return ret;
560 }, 731
561 { 732 return sprintf(buf, "%d\n", ret);
562 .ident = "N130", 733}
563 .matches = { 734
564 DMI_MATCH(DMI_SYS_VENDOR, 735static ssize_t set_battery_life_extender(struct device *dev,
565 "SAMSUNG ELECTRONICS CO., LTD."), 736 struct device_attribute *attr,
566 DMI_MATCH(DMI_PRODUCT_NAME, "N130"), 737 const char *buf, size_t count)
567 DMI_MATCH(DMI_BOARD_NAME, "N130"), 738{
568 }, 739 struct samsung_laptop *samsung = dev_get_drvdata(dev);
569 .callback = dmi_check_cb, 740 int ret, value;
570 }, 741
571 { 742 if (!count || sscanf(buf, "%i", &value) != 1)
572 .ident = "N510", 743 return -EINVAL;
573 .matches = { 744
574 DMI_MATCH(DMI_SYS_VENDOR, 745 ret = write_battery_life_extender(samsung, !!value);
575 "SAMSUNG ELECTRONICS CO., LTD."), 746 if (ret < 0)
576 DMI_MATCH(DMI_PRODUCT_NAME, "N510"), 747 return ret;
577 DMI_MATCH(DMI_BOARD_NAME, "N510"), 748
578 }, 749 return count;
579 .callback = dmi_check_cb, 750}
580 }, 751
581 { 752static DEVICE_ATTR(battery_life_extender, S_IWUSR | S_IRUGO,
582 .ident = "X125", 753 get_battery_life_extender, set_battery_life_extender);
583 .matches = { 754
584 DMI_MATCH(DMI_SYS_VENDOR, 755static int read_usb_charge(struct samsung_laptop *samsung)
585 "SAMSUNG ELECTRONICS CO., LTD."), 756{
586 DMI_MATCH(DMI_PRODUCT_NAME, "X125"), 757 const struct sabi_commands *commands = &samsung->config->commands;
587 DMI_MATCH(DMI_BOARD_NAME, "X125"), 758 struct sabi_data data;
588 }, 759 int retval;
589 .callback = dmi_check_cb, 760
590 }, 761 if (commands->get_usb_charge == 0xFFFF)
591 { 762 return -ENODEV;
592 .ident = "X120/X170", 763
593 .matches = { 764 memset(&data, 0, sizeof(data));
594 DMI_MATCH(DMI_SYS_VENDOR, 765 data.data[0] = 0x80;
595 "SAMSUNG ELECTRONICS CO., LTD."), 766 retval = sabi_command(samsung, commands->get_usb_charge,
596 DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), 767 &data, &data);
597 DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), 768
598 }, 769 if (retval)
599 .callback = dmi_check_cb, 770 return retval;
600 }, 771
601 { 772 if (data.data[0] != 0 && data.data[0] != 1)
602 .ident = "NC10", 773 return -ENODEV;
603 .matches = { 774
604 DMI_MATCH(DMI_SYS_VENDOR, 775 return data.data[0];
605 "SAMSUNG ELECTRONICS CO., LTD."), 776}
606 DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), 777
607 DMI_MATCH(DMI_BOARD_NAME, "NC10"), 778static int write_usb_charge(struct samsung_laptop *samsung,
608 }, 779 int enabled)
609 .callback = dmi_check_cb, 780{
610 }, 781 const struct sabi_commands *commands = &samsung->config->commands;
611 { 782 struct sabi_data data;
612 .ident = "NP-Q45", 783
613 .matches = { 784 memset(&data, 0, sizeof(data));
614 DMI_MATCH(DMI_SYS_VENDOR, 785 data.data[0] = 0x80 | enabled;
615 "SAMSUNG ELECTRONICS CO., LTD."), 786 return sabi_command(samsung, commands->set_usb_charge,
616 DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), 787 &data, NULL);
617 DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), 788}
618 }, 789
619 .callback = dmi_check_cb, 790static ssize_t get_usb_charge(struct device *dev,
620 }, 791 struct device_attribute *attr,
621 { 792 char *buf)
622 .ident = "X360", 793{
623 .matches = { 794 struct samsung_laptop *samsung = dev_get_drvdata(dev);
624 DMI_MATCH(DMI_SYS_VENDOR, 795 int ret;
625 "SAMSUNG ELECTRONICS CO., LTD."), 796
626 DMI_MATCH(DMI_PRODUCT_NAME, "X360"), 797 ret = read_usb_charge(samsung);
627 DMI_MATCH(DMI_BOARD_NAME, "X360"), 798 if (ret < 0)
628 }, 799 return ret;
629 .callback = dmi_check_cb, 800
630 }, 801 return sprintf(buf, "%d\n", ret);
631 { 802}
632 .ident = "R410 Plus", 803
633 .matches = { 804static ssize_t set_usb_charge(struct device *dev,
634 DMI_MATCH(DMI_SYS_VENDOR, 805 struct device_attribute *attr,
635 "SAMSUNG ELECTRONICS CO., LTD."), 806 const char *buf, size_t count)
636 DMI_MATCH(DMI_PRODUCT_NAME, "R410P"), 807{
637 DMI_MATCH(DMI_BOARD_NAME, "R460"), 808 struct samsung_laptop *samsung = dev_get_drvdata(dev);
638 }, 809 int ret, value;
639 .callback = dmi_check_cb, 810
640 }, 811 if (!count || sscanf(buf, "%i", &value) != 1)
641 { 812 return -EINVAL;
642 .ident = "R518", 813
643 .matches = { 814 ret = write_usb_charge(samsung, !!value);
644 DMI_MATCH(DMI_SYS_VENDOR, 815 if (ret < 0)
645 "SAMSUNG ELECTRONICS CO., LTD."), 816 return ret;
646 DMI_MATCH(DMI_PRODUCT_NAME, "R518"), 817
647 DMI_MATCH(DMI_BOARD_NAME, "R518"), 818 return count;
648 }, 819}
649 .callback = dmi_check_cb, 820
650 }, 821static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
651 { 822 get_usb_charge, set_usb_charge);
652 .ident = "R519/R719", 823
653 .matches = { 824static struct attribute *platform_attributes[] = {
654 DMI_MATCH(DMI_SYS_VENDOR, 825 &dev_attr_performance_level.attr,
655 "SAMSUNG ELECTRONICS CO., LTD."), 826 &dev_attr_battery_life_extender.attr,
656 DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), 827 &dev_attr_usb_charge.attr,
657 DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), 828 NULL
658 },
659 .callback = dmi_check_cb,
660 },
661 {
662 .ident = "N150/N210/N220",
663 .matches = {
664 DMI_MATCH(DMI_SYS_VENDOR,
665 "SAMSUNG ELECTRONICS CO., LTD."),
666 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
667 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
668 },
669 .callback = dmi_check_cb,
670 },
671 {
672 .ident = "N220",
673 .matches = {
674 DMI_MATCH(DMI_SYS_VENDOR,
675 "SAMSUNG ELECTRONICS CO., LTD."),
676 DMI_MATCH(DMI_PRODUCT_NAME, "N220"),
677 DMI_MATCH(DMI_BOARD_NAME, "N220"),
678 },
679 .callback = dmi_check_cb,
680 },
681 {
682 .ident = "N150/N210/N220/N230",
683 .matches = {
684 DMI_MATCH(DMI_SYS_VENDOR,
685 "SAMSUNG ELECTRONICS CO., LTD."),
686 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220/N230"),
687 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220/N230"),
688 },
689 .callback = dmi_check_cb,
690 },
691 {
692 .ident = "N150P/N210P/N220P",
693 .matches = {
694 DMI_MATCH(DMI_SYS_VENDOR,
695 "SAMSUNG ELECTRONICS CO., LTD."),
696 DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"),
697 DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"),
698 },
699 .callback = dmi_check_cb,
700 },
701 {
702 .ident = "R700",
703 .matches = {
704 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
705 DMI_MATCH(DMI_PRODUCT_NAME, "SR700"),
706 DMI_MATCH(DMI_BOARD_NAME, "SR700"),
707 },
708 .callback = dmi_check_cb,
709 },
710 {
711 .ident = "R530/R730",
712 .matches = {
713 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
714 DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"),
715 DMI_MATCH(DMI_BOARD_NAME, "R530/R730"),
716 },
717 .callback = dmi_check_cb,
718 },
719 {
720 .ident = "NF110/NF210/NF310",
721 .matches = {
722 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
723 DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
724 DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
725 },
726 .callback = dmi_check_cb,
727 },
728 {
729 .ident = "N145P/N250P/N260P",
730 .matches = {
731 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
732 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
733 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
734 },
735 .callback = dmi_check_cb,
736 },
737 {
738 .ident = "R70/R71",
739 .matches = {
740 DMI_MATCH(DMI_SYS_VENDOR,
741 "SAMSUNG ELECTRONICS CO., LTD."),
742 DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"),
743 DMI_MATCH(DMI_BOARD_NAME, "R70/R71"),
744 },
745 .callback = dmi_check_cb,
746 },
747 {
748 .ident = "P460",
749 .matches = {
750 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
751 DMI_MATCH(DMI_PRODUCT_NAME, "P460"),
752 DMI_MATCH(DMI_BOARD_NAME, "P460"),
753 },
754 .callback = dmi_check_cb,
755 },
756 {
757 .ident = "R528/R728",
758 .matches = {
759 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
760 DMI_MATCH(DMI_PRODUCT_NAME, "R528/R728"),
761 DMI_MATCH(DMI_BOARD_NAME, "R528/R728"),
762 },
763 .callback = dmi_check_cb,
764 },
765 {
766 .ident = "NC210/NC110",
767 .matches = {
768 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
769 DMI_MATCH(DMI_PRODUCT_NAME, "NC210/NC110"),
770 DMI_MATCH(DMI_BOARD_NAME, "NC210/NC110"),
771 },
772 .callback = dmi_check_cb,
773 },
774 {
775 .ident = "X520",
776 .matches = {
777 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
778 DMI_MATCH(DMI_PRODUCT_NAME, "X520"),
779 DMI_MATCH(DMI_BOARD_NAME, "X520"),
780 },
781 .callback = dmi_check_cb,
782 },
783 { },
784}; 829};
785MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
786 830
787static int find_signature(void __iomem *memcheck, const char *testStr) 831static int find_signature(void __iomem *memcheck, const char *testStr)
788{ 832{
@@ -803,153 +847,772 @@ static int find_signature(void __iomem *memcheck, const char *testStr)
803 return loca; 847 return loca;
804} 848}
805 849
806static int __init samsung_init(void) 850static void samsung_rfkill_exit(struct samsung_laptop *samsung)
807{ 851{
808 struct backlight_properties props; 852 if (samsung->wlan.rfkill) {
809 struct sabi_retval sretval; 853 rfkill_unregister(samsung->wlan.rfkill);
810 unsigned int ifaceP; 854 rfkill_destroy(samsung->wlan.rfkill);
811 int i; 855 samsung->wlan.rfkill = NULL;
812 int loca; 856 }
857 if (samsung->bluetooth.rfkill) {
858 rfkill_unregister(samsung->bluetooth.rfkill);
859 rfkill_destroy(samsung->bluetooth.rfkill);
860 samsung->bluetooth.rfkill = NULL;
861 }
862}
863
864static int samsung_new_rfkill(struct samsung_laptop *samsung,
865 struct samsung_rfkill *arfkill,
866 const char *name, enum rfkill_type type,
867 const struct rfkill_ops *ops,
868 int blocked)
869{
870 struct rfkill **rfkill = &arfkill->rfkill;
871 int ret;
872
873 arfkill->type = type;
874 arfkill->samsung = samsung;
875
876 *rfkill = rfkill_alloc(name, &samsung->platform_device->dev,
877 type, ops, arfkill);
878
879 if (!*rfkill)
880 return -EINVAL;
881
882 if (blocked != -1)
883 rfkill_init_sw_state(*rfkill, blocked);
884
885 ret = rfkill_register(*rfkill);
886 if (ret) {
887 rfkill_destroy(*rfkill);
888 *rfkill = NULL;
889 return ret;
890 }
891 return 0;
892}
893
894static int __init samsung_rfkill_init_seclinux(struct samsung_laptop *samsung)
895{
896 return samsung_new_rfkill(samsung, &samsung->wlan, "samsung-wlan",
897 RFKILL_TYPE_WLAN, &seclinux_rfkill_ops, -1);
898}
899
900static int __init samsung_rfkill_init_swsmi(struct samsung_laptop *samsung)
901{
902 struct sabi_data data;
903 int ret;
904
905 ret = swsmi_wireless_status(samsung, &data);
906 if (ret) {
907 /* Some swsmi laptops use the old seclinux way to control
908 * wireless devices */
909 if (ret == -EINVAL)
910 ret = samsung_rfkill_init_seclinux(samsung);
911 return ret;
912 }
913
914 /* 0x02 seems to mean that the device is no present/available */
915
916 if (data.data[WL_STATUS_WLAN] != 0x02)
917 ret = samsung_new_rfkill(samsung, &samsung->wlan,
918 "samsung-wlan",
919 RFKILL_TYPE_WLAN,
920 &swsmi_rfkill_ops,
921 !data.data[WL_STATUS_WLAN]);
922 if (ret)
923 goto exit;
924
925 if (data.data[WL_STATUS_BT] != 0x02)
926 ret = samsung_new_rfkill(samsung, &samsung->bluetooth,
927 "samsung-bluetooth",
928 RFKILL_TYPE_BLUETOOTH,
929 &swsmi_rfkill_ops,
930 !data.data[WL_STATUS_BT]);
931 if (ret)
932 goto exit;
933
934exit:
935 if (ret)
936 samsung_rfkill_exit(samsung);
937
938 return ret;
939}
940
941static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
942{
943 if (samsung->config->sabi_version == 2)
944 return samsung_rfkill_init_seclinux(samsung);
945 if (samsung->config->sabi_version == 3)
946 return samsung_rfkill_init_swsmi(samsung);
947 return 0;
948}
949
950static int kbd_backlight_enable(struct samsung_laptop *samsung)
951{
952 const struct sabi_commands *commands = &samsung->config->commands;
953 struct sabi_data data;
813 int retval; 954 int retval;
814 955
815 mutex_init(&sabi_mutex); 956 if (commands->kbd_backlight == 0xFFFF)
957 return -ENODEV;
958
959 memset(&data, 0, sizeof(data));
960 data.d0 = 0xaabb;
961 retval = sabi_command(samsung, commands->kbd_backlight,
962 &data, &data);
816 963
817 if (!force && !dmi_check_system(samsung_dmi_table)) 964 if (retval)
965 return retval;
966
967 if (data.d0 != 0xccdd)
818 return -ENODEV; 968 return -ENODEV;
969 return 0;
970}
819 971
820 f0000_segment = ioremap_nocache(0xf0000, 0xffff); 972static int kbd_backlight_read(struct samsung_laptop *samsung)
821 if (!f0000_segment) { 973{
822 pr_err("Can't map the segment at 0xf0000\n"); 974 const struct sabi_commands *commands = &samsung->config->commands;
823 return -EINVAL; 975 struct sabi_data data;
976 int retval;
977
978 memset(&data, 0, sizeof(data));
979 data.data[0] = 0x81;
980 retval = sabi_command(samsung, commands->kbd_backlight,
981 &data, &data);
982
983 if (retval)
984 return retval;
985
986 return data.data[0];
987}
988
989static int kbd_backlight_write(struct samsung_laptop *samsung, int brightness)
990{
991 const struct sabi_commands *commands = &samsung->config->commands;
992 struct sabi_data data;
993
994 memset(&data, 0, sizeof(data));
995 data.d0 = 0x82 | ((brightness & 0xFF) << 8);
996 return sabi_command(samsung, commands->kbd_backlight,
997 &data, NULL);
998}
999
1000static void kbd_led_update(struct work_struct *work)
1001{
1002 struct samsung_laptop *samsung;
1003
1004 samsung = container_of(work, struct samsung_laptop, kbd_led_work);
1005 kbd_backlight_write(samsung, samsung->kbd_led_wk);
1006}
1007
1008static void kbd_led_set(struct led_classdev *led_cdev,
1009 enum led_brightness value)
1010{
1011 struct samsung_laptop *samsung;
1012
1013 samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
1014
1015 if (value > samsung->kbd_led.max_brightness)
1016 value = samsung->kbd_led.max_brightness;
1017 else if (value < 0)
1018 value = 0;
1019
1020 samsung->kbd_led_wk = value;
1021 queue_work(samsung->led_workqueue, &samsung->kbd_led_work);
1022}
1023
1024static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
1025{
1026 struct samsung_laptop *samsung;
1027
1028 samsung = container_of(led_cdev, struct samsung_laptop, kbd_led);
1029 return kbd_backlight_read(samsung);
1030}
1031
1032static void samsung_leds_exit(struct samsung_laptop *samsung)
1033{
1034 if (!IS_ERR_OR_NULL(samsung->kbd_led.dev))
1035 led_classdev_unregister(&samsung->kbd_led);
1036 if (samsung->led_workqueue)
1037 destroy_workqueue(samsung->led_workqueue);
1038}
1039
1040static int __init samsung_leds_init(struct samsung_laptop *samsung)
1041{
1042 int ret = 0;
1043
1044 samsung->led_workqueue = create_singlethread_workqueue("led_workqueue");
1045 if (!samsung->led_workqueue)
1046 return -ENOMEM;
1047
1048 if (kbd_backlight_enable(samsung) >= 0) {
1049 INIT_WORK(&samsung->kbd_led_work, kbd_led_update);
1050
1051 samsung->kbd_led.name = "samsung::kbd_backlight";
1052 samsung->kbd_led.brightness_set = kbd_led_set;
1053 samsung->kbd_led.brightness_get = kbd_led_get;
1054 samsung->kbd_led.max_brightness = 8;
1055
1056 ret = led_classdev_register(&samsung->platform_device->dev,
1057 &samsung->kbd_led);
1058 }
1059
1060 if (ret)
1061 samsung_leds_exit(samsung);
1062
1063 return ret;
1064}
1065
1066static void samsung_backlight_exit(struct samsung_laptop *samsung)
1067{
1068 if (samsung->backlight_device) {
1069 backlight_device_unregister(samsung->backlight_device);
1070 samsung->backlight_device = NULL;
1071 }
1072}
1073
1074static int __init samsung_backlight_init(struct samsung_laptop *samsung)
1075{
1076 struct backlight_device *bd;
1077 struct backlight_properties props;
1078
1079 if (!samsung->handle_backlight)
1080 return 0;
1081
1082 memset(&props, 0, sizeof(struct backlight_properties));
1083 props.type = BACKLIGHT_PLATFORM;
1084 props.max_brightness = samsung->config->max_brightness -
1085 samsung->config->min_brightness;
1086
1087 bd = backlight_device_register("samsung",
1088 &samsung->platform_device->dev,
1089 samsung, &backlight_ops,
1090 &props);
1091 if (IS_ERR(bd))
1092 return PTR_ERR(bd);
1093
1094 samsung->backlight_device = bd;
1095 samsung->backlight_device->props.brightness = read_brightness(samsung);
1096 samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
1097 backlight_update_status(samsung->backlight_device);
1098
1099 return 0;
1100}
1101
1102static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
1103 struct attribute *attr, int idx)
1104{
1105 struct device *dev = container_of(kobj, struct device, kobj);
1106 struct platform_device *pdev = to_platform_device(dev);
1107 struct samsung_laptop *samsung = platform_get_drvdata(pdev);
1108 bool ok = true;
1109
1110 if (attr == &dev_attr_performance_level.attr)
1111 ok = !!samsung->config->performance_levels[0].name;
1112 if (attr == &dev_attr_battery_life_extender.attr)
1113 ok = !!(read_battery_life_extender(samsung) >= 0);
1114 if (attr == &dev_attr_usb_charge.attr)
1115 ok = !!(read_usb_charge(samsung) >= 0);
1116
1117 return ok ? attr->mode : 0;
1118}
1119
1120static struct attribute_group platform_attribute_group = {
1121 .is_visible = samsung_sysfs_is_visible,
1122 .attrs = platform_attributes
1123};
1124
1125static void samsung_sysfs_exit(struct samsung_laptop *samsung)
1126{
1127 struct platform_device *device = samsung->platform_device;
1128
1129 sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
1130}
1131
1132static int __init samsung_sysfs_init(struct samsung_laptop *samsung)
1133{
1134 struct platform_device *device = samsung->platform_device;
1135
1136 return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
1137
1138}
1139
1140static int show_call(struct seq_file *m, void *data)
1141{
1142 struct samsung_laptop *samsung = m->private;
1143 struct sabi_data *sdata = &samsung->debug.data;
1144 int ret;
1145
1146 seq_printf(m, "SABI 0x%04x {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
1147 samsung->debug.command,
1148 sdata->d0, sdata->d1, sdata->d2, sdata->d3);
1149
1150 ret = sabi_command(samsung, samsung->debug.command, sdata, sdata);
1151
1152 if (ret) {
1153 seq_printf(m, "SABI command 0x%04x failed\n",
1154 samsung->debug.command);
1155 return ret;
1156 }
1157
1158 seq_printf(m, "SABI {0x%08x, 0x%08x, 0x%04x, 0x%02x}\n",
1159 sdata->d0, sdata->d1, sdata->d2, sdata->d3);
1160 return 0;
1161}
1162
1163static int samsung_debugfs_open(struct inode *inode, struct file *file)
1164{
1165 return single_open(file, show_call, inode->i_private);
1166}
1167
1168static const struct file_operations samsung_laptop_call_io_ops = {
1169 .owner = THIS_MODULE,
1170 .open = samsung_debugfs_open,
1171 .read = seq_read,
1172 .llseek = seq_lseek,
1173 .release = single_release,
1174};
1175
1176static void samsung_debugfs_exit(struct samsung_laptop *samsung)
1177{
1178 debugfs_remove_recursive(samsung->debug.root);
1179}
1180
1181static int samsung_debugfs_init(struct samsung_laptop *samsung)
1182{
1183 struct dentry *dent;
1184
1185 samsung->debug.root = debugfs_create_dir("samsung-laptop", NULL);
1186 if (!samsung->debug.root) {
1187 pr_err("failed to create debugfs directory");
1188 goto error_debugfs;
1189 }
1190
1191 samsung->debug.f0000_wrapper.data = samsung->f0000_segment;
1192 samsung->debug.f0000_wrapper.size = 0xffff;
1193
1194 samsung->debug.data_wrapper.data = &samsung->debug.data;
1195 samsung->debug.data_wrapper.size = sizeof(samsung->debug.data);
1196
1197 samsung->debug.sdiag_wrapper.data = samsung->sdiag;
1198 samsung->debug.sdiag_wrapper.size = strlen(samsung->sdiag);
1199
1200 dent = debugfs_create_u16("command", S_IRUGO | S_IWUSR,
1201 samsung->debug.root, &samsung->debug.command);
1202 if (!dent)
1203 goto error_debugfs;
1204
1205 dent = debugfs_create_u32("d0", S_IRUGO | S_IWUSR, samsung->debug.root,
1206 &samsung->debug.data.d0);
1207 if (!dent)
1208 goto error_debugfs;
1209
1210 dent = debugfs_create_u32("d1", S_IRUGO | S_IWUSR, samsung->debug.root,
1211 &samsung->debug.data.d1);
1212 if (!dent)
1213 goto error_debugfs;
1214
1215 dent = debugfs_create_u16("d2", S_IRUGO | S_IWUSR, samsung->debug.root,
1216 &samsung->debug.data.d2);
1217 if (!dent)
1218 goto error_debugfs;
1219
1220 dent = debugfs_create_u8("d3", S_IRUGO | S_IWUSR, samsung->debug.root,
1221 &samsung->debug.data.d3);
1222 if (!dent)
1223 goto error_debugfs;
1224
1225 dent = debugfs_create_blob("data", S_IRUGO | S_IWUSR,
1226 samsung->debug.root,
1227 &samsung->debug.data_wrapper);
1228 if (!dent)
1229 goto error_debugfs;
1230
1231 dent = debugfs_create_blob("f0000_segment", S_IRUSR | S_IWUSR,
1232 samsung->debug.root,
1233 &samsung->debug.f0000_wrapper);
1234 if (!dent)
1235 goto error_debugfs;
1236
1237 dent = debugfs_create_file("call", S_IFREG | S_IRUGO,
1238 samsung->debug.root, samsung,
1239 &samsung_laptop_call_io_ops);
1240 if (!dent)
1241 goto error_debugfs;
1242
1243 dent = debugfs_create_blob("sdiag", S_IRUGO | S_IWUSR,
1244 samsung->debug.root,
1245 &samsung->debug.sdiag_wrapper);
1246 if (!dent)
1247 goto error_debugfs;
1248
1249 return 0;
1250
1251error_debugfs:
1252 samsung_debugfs_exit(samsung);
1253 return -ENOMEM;
1254}
1255
1256static void samsung_sabi_exit(struct samsung_laptop *samsung)
1257{
1258 const struct sabi_config *config = samsung->config;
1259
1260 /* Turn off "Linux" mode in the BIOS */
1261 if (config && config->commands.set_linux != 0xff)
1262 sabi_set_commandb(samsung, config->commands.set_linux, 0x80);
1263
1264 if (samsung->sabi_iface) {
1265 iounmap(samsung->sabi_iface);
1266 samsung->sabi_iface = NULL;
1267 }
1268 if (samsung->f0000_segment) {
1269 iounmap(samsung->f0000_segment);
1270 samsung->f0000_segment = NULL;
1271 }
1272
1273 samsung->config = NULL;
1274}
1275
1276static __init void samsung_sabi_infos(struct samsung_laptop *samsung, int loca,
1277 unsigned int ifaceP)
1278{
1279 const struct sabi_config *config = samsung->config;
1280
1281 printk(KERN_DEBUG "This computer supports SABI==%x\n",
1282 loca + 0xf0000 - 6);
1283
1284 printk(KERN_DEBUG "SABI header:\n");
1285 printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
1286 readw(samsung->sabi + config->header_offsets.port));
1287 printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
1288 readb(samsung->sabi + config->header_offsets.iface_func));
1289 printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
1290 readb(samsung->sabi + config->header_offsets.en_mem));
1291 printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
1292 readb(samsung->sabi + config->header_offsets.re_mem));
1293 printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
1294 readw(samsung->sabi + config->header_offsets.data_offset));
1295 printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
1296 readw(samsung->sabi + config->header_offsets.data_segment));
1297
1298 printk(KERN_DEBUG " SABI pointer = 0x%08x\n", ifaceP);
1299}
1300
1301static void __init samsung_sabi_diag(struct samsung_laptop *samsung)
1302{
1303 int loca = find_signature(samsung->f0000_segment, "SDiaG@");
1304 int i;
1305
1306 if (loca == 0xffff)
1307 return ;
1308
1309 /* Example:
1310 * Ident: @SDiaG@686XX-N90X3A/966-SEC-07HL-S90X3A
1311 *
1312 * Product name: 90X3A
1313 * BIOS Version: 07HL
1314 */
1315 loca += 1;
1316 for (i = 0; loca < 0xffff && i < sizeof(samsung->sdiag) - 1; loca++) {
1317 char temp = readb(samsung->f0000_segment + loca);
1318
1319 if (isalnum(temp) || temp == '/' || temp == '-')
1320 samsung->sdiag[i++] = temp;
1321 else
1322 break ;
824 } 1323 }
825 1324
1325 if (debug && samsung->sdiag[0])
1326 pr_info("sdiag: %s", samsung->sdiag);
1327}
1328
1329static int __init samsung_sabi_init(struct samsung_laptop *samsung)
1330{
1331 const struct sabi_config *config = NULL;
1332 const struct sabi_commands *commands;
1333 unsigned int ifaceP;
1334 int ret = 0;
1335 int i;
1336 int loca;
1337
1338 samsung->f0000_segment = ioremap_nocache(0xf0000, 0xffff);
1339 if (!samsung->f0000_segment) {
1340 if (debug || force)
1341 pr_err("Can't map the segment at 0xf0000\n");
1342 ret = -EINVAL;
1343 goto exit;
1344 }
1345
1346 samsung_sabi_diag(samsung);
1347
826 /* Try to find one of the signatures in memory to find the header */ 1348 /* Try to find one of the signatures in memory to find the header */
827 for (i = 0; sabi_configs[i].test_string != 0; ++i) { 1349 for (i = 0; sabi_configs[i].test_string != 0; ++i) {
828 sabi_config = &sabi_configs[i]; 1350 samsung->config = &sabi_configs[i];
829 loca = find_signature(f0000_segment, sabi_config->test_string); 1351 loca = find_signature(samsung->f0000_segment,
1352 samsung->config->test_string);
830 if (loca != 0xffff) 1353 if (loca != 0xffff)
831 break; 1354 break;
832 } 1355 }
833 1356
834 if (loca == 0xffff) { 1357 if (loca == 0xffff) {
835 pr_err("This computer does not support SABI\n"); 1358 if (debug || force)
836 goto error_no_signature; 1359 pr_err("This computer does not support SABI\n");
1360 ret = -ENODEV;
1361 goto exit;
837 } 1362 }
838 1363
1364 config = samsung->config;
1365 commands = &config->commands;
1366
839 /* point to the SMI port Number */ 1367 /* point to the SMI port Number */
840 loca += 1; 1368 loca += 1;
841 sabi = (f0000_segment + loca); 1369 samsung->sabi = (samsung->f0000_segment + loca);
842
843 if (debug) {
844 printk(KERN_DEBUG "This computer supports SABI==%x\n",
845 loca + 0xf0000 - 6);
846 printk(KERN_DEBUG "SABI header:\n");
847 printk(KERN_DEBUG " SMI Port Number = 0x%04x\n",
848 readw(sabi + sabi_config->header_offsets.port));
849 printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n",
850 readb(sabi + sabi_config->header_offsets.iface_func));
851 printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n",
852 readb(sabi + sabi_config->header_offsets.en_mem));
853 printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n",
854 readb(sabi + sabi_config->header_offsets.re_mem));
855 printk(KERN_DEBUG " SABI data offset = 0x%04x\n",
856 readw(sabi + sabi_config->header_offsets.data_offset));
857 printk(KERN_DEBUG " SABI data segment = 0x%04x\n",
858 readw(sabi + sabi_config->header_offsets.data_segment));
859 }
860 1370
861 /* Get a pointer to the SABI Interface */ 1371 /* Get a pointer to the SABI Interface */
862 ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; 1372 ifaceP = (readw(samsung->sabi + config->header_offsets.data_segment) & 0x0ffff) << 4;
863 ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; 1373 ifaceP += readw(samsung->sabi + config->header_offsets.data_offset) & 0x0ffff;
864 sabi_iface = ioremap_nocache(ifaceP, 16);
865 if (!sabi_iface) {
866 pr_err("Can't remap %x\n", ifaceP);
867 goto error_no_signature;
868 }
869 if (debug) {
870 printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP);
871 printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface);
872 1374
873 test_backlight(); 1375 if (debug)
874 test_wireless(); 1376 samsung_sabi_infos(samsung, loca, ifaceP);
875 1377
876 retval = sabi_get_command(sabi_config->commands.get_brightness, 1378 samsung->sabi_iface = ioremap_nocache(ifaceP, 16);
877 &sretval); 1379 if (!samsung->sabi_iface) {
878 printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); 1380 pr_err("Can't remap %x\n", ifaceP);
1381 ret = -EINVAL;
1382 goto exit;
879 } 1383 }
880 1384
881 /* Turn on "Linux" mode in the BIOS */ 1385 /* Turn on "Linux" mode in the BIOS */
882 if (sabi_config->commands.set_linux != 0xff) { 1386 if (commands->set_linux != 0xff) {
883 retval = sabi_set_command(sabi_config->commands.set_linux, 1387 int retval = sabi_set_commandb(samsung,
884 0x81); 1388 commands->set_linux, 0x81);
885 if (retval) { 1389 if (retval) {
886 pr_warn("Linux mode was not set!\n"); 1390 pr_warn("Linux mode was not set!\n");
887 goto error_no_platform; 1391 ret = -ENODEV;
1392 goto exit;
888 } 1393 }
889 } 1394 }
890 1395
891 /* Check for stepping quirk */ 1396 /* Check for stepping quirk */
892 check_for_stepping_quirk(); 1397 if (samsung->handle_backlight)
1398 check_for_stepping_quirk(samsung);
893 1399
894 /* knock up a platform device to hang stuff off of */ 1400 pr_info("detected SABI interface: %s\n",
895 sdev = platform_device_register_simple("samsung", -1, NULL, 0); 1401 samsung->config->test_string);
896 if (IS_ERR(sdev))
897 goto error_no_platform;
898 1402
899 /* create a backlight device to talk to this one */ 1403exit:
900 memset(&props, 0, sizeof(struct backlight_properties)); 1404 if (ret)
901 props.type = BACKLIGHT_PLATFORM; 1405 samsung_sabi_exit(samsung);
902 props.max_brightness = sabi_config->max_brightness -
903 sabi_config->min_brightness;
904 backlight_device = backlight_device_register("samsung", &sdev->dev,
905 NULL, &backlight_ops,
906 &props);
907 if (IS_ERR(backlight_device))
908 goto error_no_backlight;
909
910 backlight_device->props.brightness = read_brightness();
911 backlight_device->props.power = FB_BLANK_UNBLANK;
912 backlight_update_status(backlight_device);
913
914 retval = init_wireless(sdev);
915 if (retval)
916 goto error_no_rfk;
917 1406
918 retval = device_create_file(&sdev->dev, &dev_attr_performance_level); 1407 return ret;
919 if (retval) 1408}
920 goto error_file_create; 1409
1410static void samsung_platform_exit(struct samsung_laptop *samsung)
1411{
1412 if (samsung->platform_device) {
1413 platform_device_unregister(samsung->platform_device);
1414 samsung->platform_device = NULL;
1415 }
1416}
1417
1418static int __init samsung_platform_init(struct samsung_laptop *samsung)
1419{
1420 struct platform_device *pdev;
1421
1422 pdev = platform_device_register_simple("samsung", -1, NULL, 0);
1423 if (IS_ERR(pdev))
1424 return PTR_ERR(pdev);
921 1425
1426 samsung->platform_device = pdev;
1427 platform_set_drvdata(samsung->platform_device, samsung);
922 return 0; 1428 return 0;
1429}
1430
1431static struct samsung_quirks *quirks;
1432
1433static int __init samsung_dmi_matched(const struct dmi_system_id *d)
1434{
1435 quirks = d->driver_data;
1436 return 0;
1437}
1438
1439static struct dmi_system_id __initdata samsung_dmi_table[] = {
1440 {
1441 .matches = {
1442 DMI_MATCH(DMI_SYS_VENDOR,
1443 "SAMSUNG ELECTRONICS CO., LTD."),
1444 DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
1445 },
1446 },
1447 {
1448 .matches = {
1449 DMI_MATCH(DMI_SYS_VENDOR,
1450 "SAMSUNG ELECTRONICS CO., LTD."),
1451 DMI_MATCH(DMI_CHASSIS_TYPE, "9"), /* Laptop */
1452 },
1453 },
1454 {
1455 .matches = {
1456 DMI_MATCH(DMI_SYS_VENDOR,
1457 "SAMSUNG ELECTRONICS CO., LTD."),
1458 DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */
1459 },
1460 },
1461 {
1462 .matches = {
1463 DMI_MATCH(DMI_SYS_VENDOR,
1464 "SAMSUNG ELECTRONICS CO., LTD."),
1465 DMI_MATCH(DMI_CHASSIS_TYPE, "14"), /* Sub-Notebook */
1466 },
1467 },
1468 /* Specific DMI ids for laptop with quirks */
1469 {
1470 .callback = samsung_dmi_matched,
1471 .ident = "N150P",
1472 .matches = {
1473 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1474 DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
1475 DMI_MATCH(DMI_BOARD_NAME, "N150P"),
1476 },
1477 .driver_data = &samsung_broken_acpi_video,
1478 },
1479 {
1480 .callback = samsung_dmi_matched,
1481 .ident = "N145P/N250P/N260P",
1482 .matches = {
1483 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1484 DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
1485 DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
1486 },
1487 .driver_data = &samsung_broken_acpi_video,
1488 },
1489 {
1490 .callback = samsung_dmi_matched,
1491 .ident = "N150/N210/N220",
1492 .matches = {
1493 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1494 DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"),
1495 DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"),
1496 },
1497 .driver_data = &samsung_broken_acpi_video,
1498 },
1499 {
1500 .callback = samsung_dmi_matched,
1501 .ident = "NF110/NF210/NF310",
1502 .matches = {
1503 DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
1504 DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"),
1505 DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"),
1506 },
1507 .driver_data = &samsung_broken_acpi_video,
1508 },
1509 { },
1510};
1511MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
923 1512
924error_file_create: 1513static struct platform_device *samsung_platform_device;
925 destroy_wireless();
926 1514
927error_no_rfk: 1515static int __init samsung_init(void)
928 backlight_device_unregister(backlight_device); 1516{
1517 struct samsung_laptop *samsung;
1518 int ret;
929 1519
930error_no_backlight: 1520 quirks = &samsung_unknown;
931 platform_device_unregister(sdev); 1521 if (!force && !dmi_check_system(samsung_dmi_table))
1522 return -ENODEV;
1523
1524 samsung = kzalloc(sizeof(*samsung), GFP_KERNEL);
1525 if (!samsung)
1526 return -ENOMEM;
932 1527
933error_no_platform: 1528 mutex_init(&samsung->sabi_mutex);
934 iounmap(sabi_iface); 1529 samsung->handle_backlight = true;
1530 samsung->quirks = quirks;
935 1531
936error_no_signature: 1532
937 iounmap(f0000_segment); 1533#if (defined CONFIG_ACPI_VIDEO || defined CONFIG_ACPI_VIDEO_MODULE)
938 return -EINVAL; 1534 /* Don't handle backlight here if the acpi video already handle it */
1535 if (acpi_video_backlight_support()) {
1536 if (samsung->quirks->broken_acpi_video) {
1537 pr_info("Disabling ACPI video driver\n");
1538 acpi_video_unregister();
1539 } else {
1540 samsung->handle_backlight = false;
1541 }
1542 }
1543#endif
1544
1545 ret = samsung_platform_init(samsung);
1546 if (ret)
1547 goto error_platform;
1548
1549 ret = samsung_sabi_init(samsung);
1550 if (ret)
1551 goto error_sabi;
1552
1553#ifdef CONFIG_ACPI
1554 /* Only log that if we are really on a sabi platform */
1555 if (acpi_video_backlight_support() &&
1556 !samsung->quirks->broken_acpi_video)
1557 pr_info("Backlight controlled by ACPI video driver\n");
1558#endif
1559
1560 ret = samsung_sysfs_init(samsung);
1561 if (ret)
1562 goto error_sysfs;
1563
1564 ret = samsung_backlight_init(samsung);
1565 if (ret)
1566 goto error_backlight;
1567
1568 ret = samsung_rfkill_init(samsung);
1569 if (ret)
1570 goto error_rfkill;
1571
1572 ret = samsung_leds_init(samsung);
1573 if (ret)
1574 goto error_leds;
1575
1576 ret = samsung_debugfs_init(samsung);
1577 if (ret)
1578 goto error_debugfs;
1579
1580 samsung_platform_device = samsung->platform_device;
1581 return ret;
1582
1583error_debugfs:
1584 samsung_leds_exit(samsung);
1585error_leds:
1586 samsung_rfkill_exit(samsung);
1587error_rfkill:
1588 samsung_backlight_exit(samsung);
1589error_backlight:
1590 samsung_sysfs_exit(samsung);
1591error_sysfs:
1592 samsung_sabi_exit(samsung);
1593error_sabi:
1594 samsung_platform_exit(samsung);
1595error_platform:
1596 kfree(samsung);
1597 return ret;
939} 1598}
940 1599
941static void __exit samsung_exit(void) 1600static void __exit samsung_exit(void)
942{ 1601{
943 /* Turn off "Linux" mode in the BIOS */ 1602 struct samsung_laptop *samsung;
944 if (sabi_config->commands.set_linux != 0xff) 1603
945 sabi_set_command(sabi_config->commands.set_linux, 0x80); 1604 samsung = platform_get_drvdata(samsung_platform_device);
946 1605
947 device_remove_file(&sdev->dev, &dev_attr_performance_level); 1606 samsung_debugfs_exit(samsung);
948 backlight_device_unregister(backlight_device); 1607 samsung_leds_exit(samsung);
949 destroy_wireless(); 1608 samsung_rfkill_exit(samsung);
950 iounmap(sabi_iface); 1609 samsung_backlight_exit(samsung);
951 iounmap(f0000_segment); 1610 samsung_sysfs_exit(samsung);
952 platform_device_unregister(sdev); 1611 samsung_sabi_exit(samsung);
1612 samsung_platform_exit(samsung);
1613
1614 kfree(samsung);
1615 samsung_platform_device = NULL;
953} 1616}
954 1617
955module_init(samsung_init); 1618module_init(samsung_init);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index c006dee5ebfe..8a51795aa02a 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -127,7 +127,7 @@ MODULE_PARM_DESC(minor,
127 "default is -1 (automatic)"); 127 "default is -1 (automatic)");
128#endif 128#endif
129 129
130static int kbd_backlight; /* = 1 */ 130static int kbd_backlight = 1;
131module_param(kbd_backlight, int, 0444); 131module_param(kbd_backlight, int, 0444);
132MODULE_PARM_DESC(kbd_backlight, 132MODULE_PARM_DESC(kbd_backlight,
133 "set this to 0 to disable keyboard backlight, " 133 "set this to 0 to disable keyboard backlight, "
@@ -347,6 +347,7 @@ static void sony_laptop_report_input_event(u8 event)
347 struct input_dev *jog_dev = sony_laptop_input.jog_dev; 347 struct input_dev *jog_dev = sony_laptop_input.jog_dev;
348 struct input_dev *key_dev = sony_laptop_input.key_dev; 348 struct input_dev *key_dev = sony_laptop_input.key_dev;
349 struct sony_laptop_keypress kp = { NULL }; 349 struct sony_laptop_keypress kp = { NULL };
350 int scancode = -1;
350 351
351 if (event == SONYPI_EVENT_FNKEY_RELEASED || 352 if (event == SONYPI_EVENT_FNKEY_RELEASED ||
352 event == SONYPI_EVENT_ANYBUTTON_RELEASED) { 353 event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
@@ -380,8 +381,8 @@ static void sony_laptop_report_input_event(u8 event)
380 dprintk("sony_laptop_report_input_event, event not known: %d\n", event); 381 dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
381 break; 382 break;
382 } 383 }
383 if (sony_laptop_input_index[event] != -1) { 384 if ((scancode = sony_laptop_input_index[event]) != -1) {
384 kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]]; 385 kp.key = sony_laptop_input_keycode_map[scancode];
385 if (kp.key != KEY_UNKNOWN) 386 if (kp.key != KEY_UNKNOWN)
386 kp.dev = key_dev; 387 kp.dev = key_dev;
387 } 388 }
@@ -389,9 +390,11 @@ static void sony_laptop_report_input_event(u8 event)
389 } 390 }
390 391
391 if (kp.dev) { 392 if (kp.dev) {
393 /* if we have a scancode we emit it so we can always
394 remap the key */
395 if (scancode != -1)
396 input_event(kp.dev, EV_MSC, MSC_SCAN, scancode);
392 input_report_key(kp.dev, kp.key, 1); 397 input_report_key(kp.dev, kp.key, 1);
393 /* we emit the scancode so we can always remap the key */
394 input_event(kp.dev, EV_MSC, MSC_SCAN, event);
395 input_sync(kp.dev); 398 input_sync(kp.dev);
396 399
397 /* schedule key release */ 400 /* schedule key release */
@@ -466,7 +469,7 @@ static int sony_laptop_setup_input(struct acpi_device *acpi_device)
466 jog_dev->name = "Sony Vaio Jogdial"; 469 jog_dev->name = "Sony Vaio Jogdial";
467 jog_dev->id.bustype = BUS_ISA; 470 jog_dev->id.bustype = BUS_ISA;
468 jog_dev->id.vendor = PCI_VENDOR_ID_SONY; 471 jog_dev->id.vendor = PCI_VENDOR_ID_SONY;
469 key_dev->dev.parent = &acpi_device->dev; 472 jog_dev->dev.parent = &acpi_device->dev;
470 473
471 input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE); 474 input_set_capability(jog_dev, EV_KEY, BTN_MIDDLE);
472 input_set_capability(jog_dev, EV_REL, REL_WHEEL); 475 input_set_capability(jog_dev, EV_REL, REL_WHEEL);
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index ea0c6075b720..d68c0002f4a2 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -8658,7 +8658,7 @@ static int __must_check __init get_thinkpad_model_data(
8658 } 8658 }
8659 8659
8660 s = dmi_get_system_info(DMI_PRODUCT_VERSION); 8660 s = dmi_get_system_info(DMI_PRODUCT_VERSION);
8661 if (s && !strnicmp(s, "ThinkPad", 8)) { 8661 if (s && !(strnicmp(s, "ThinkPad", 8) && strnicmp(s, "Lenovo", 6))) {
8662 tp->model_str = kstrdup(s, GFP_KERNEL); 8662 tp->model_str = kstrdup(s, GFP_KERNEL);
8663 if (!tp->model_str) 8663 if (!tp->model_str)
8664 return -ENOMEM; 8664 return -ENOMEM;
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index dcdc1f4a4624..ee79ce64d9df 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -52,6 +52,8 @@
52#include <linux/input/sparse-keymap.h> 52#include <linux/input/sparse-keymap.h>
53#include <linux/leds.h> 53#include <linux/leds.h>
54#include <linux/slab.h> 54#include <linux/slab.h>
55#include <linux/workqueue.h>
56#include <linux/i8042.h>
55 57
56#include <asm/uaccess.h> 58#include <asm/uaccess.h>
57 59
@@ -61,6 +63,11 @@ MODULE_AUTHOR("John Belmonte");
61MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver"); 63MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
62MODULE_LICENSE("GPL"); 64MODULE_LICENSE("GPL");
63 65
66#define TOSHIBA_WMI_EVENT_GUID "59142400-C6A3-40FA-BADB-8A2652834100"
67
68/* Scan code for Fn key on TOS1900 models */
69#define TOS1900_FN_SCAN 0x6e
70
64/* Toshiba ACPI method paths */ 71/* Toshiba ACPI method paths */
65#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX" 72#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
66 73
@@ -95,6 +102,8 @@ MODULE_LICENSE("GPL");
95#define HCI_WIRELESS 0x0056 102#define HCI_WIRELESS 0x0056
96 103
97/* field definitions */ 104/* field definitions */
105#define HCI_HOTKEY_DISABLE 0x0b
106#define HCI_HOTKEY_ENABLE 0x09
98#define HCI_LCD_BRIGHTNESS_BITS 3 107#define HCI_LCD_BRIGHTNESS_BITS 3
99#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS) 108#define HCI_LCD_BRIGHTNESS_SHIFT (16-HCI_LCD_BRIGHTNESS_BITS)
100#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS) 109#define HCI_LCD_BRIGHTNESS_LEVELS (1 << HCI_LCD_BRIGHTNESS_BITS)
@@ -111,6 +120,7 @@ struct toshiba_acpi_dev {
111 const char *method_hci; 120 const char *method_hci;
112 struct rfkill *bt_rfk; 121 struct rfkill *bt_rfk;
113 struct input_dev *hotkey_dev; 122 struct input_dev *hotkey_dev;
123 struct work_struct hotkey_work;
114 struct backlight_device *backlight_dev; 124 struct backlight_device *backlight_dev;
115 struct led_classdev led_dev; 125 struct led_classdev led_dev;
116 126
@@ -118,14 +128,18 @@ struct toshiba_acpi_dev {
118 int last_key_event; 128 int last_key_event;
119 int key_event_valid; 129 int key_event_valid;
120 130
121 int illumination_supported:1; 131 unsigned int illumination_supported:1;
122 int video_supported:1; 132 unsigned int video_supported:1;
123 int fan_supported:1; 133 unsigned int fan_supported:1;
124 int system_event_supported:1; 134 unsigned int system_event_supported:1;
135 unsigned int ntfy_supported:1;
136 unsigned int info_supported:1;
125 137
126 struct mutex mutex; 138 struct mutex mutex;
127}; 139};
128 140
141static struct toshiba_acpi_dev *toshiba_acpi;
142
129static const struct acpi_device_id toshiba_device_ids[] = { 143static const struct acpi_device_id toshiba_device_ids[] = {
130 {"TOS6200", 0}, 144 {"TOS6200", 0},
131 {"TOS6208", 0}, 145 {"TOS6208", 0},
@@ -138,6 +152,8 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
138 { KE_KEY, 0x101, { KEY_MUTE } }, 152 { KE_KEY, 0x101, { KEY_MUTE } },
139 { KE_KEY, 0x102, { KEY_ZOOMOUT } }, 153 { KE_KEY, 0x102, { KEY_ZOOMOUT } },
140 { KE_KEY, 0x103, { KEY_ZOOMIN } }, 154 { KE_KEY, 0x103, { KEY_ZOOMIN } },
155 { KE_KEY, 0x12c, { KEY_KBDILLUMTOGGLE } },
156 { KE_KEY, 0x139, { KEY_ZOOMRESET } },
141 { KE_KEY, 0x13b, { KEY_COFFEE } }, 157 { KE_KEY, 0x13b, { KEY_COFFEE } },
142 { KE_KEY, 0x13c, { KEY_BATTERY } }, 158 { KE_KEY, 0x13c, { KEY_BATTERY } },
143 { KE_KEY, 0x13d, { KEY_SLEEP } }, 159 { KE_KEY, 0x13d, { KEY_SLEEP } },
@@ -146,7 +162,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
146 { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } }, 162 { KE_KEY, 0x140, { KEY_BRIGHTNESSDOWN } },
147 { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } }, 163 { KE_KEY, 0x141, { KEY_BRIGHTNESSUP } },
148 { KE_KEY, 0x142, { KEY_WLAN } }, 164 { KE_KEY, 0x142, { KEY_WLAN } },
149 { KE_KEY, 0x143, { KEY_PROG1 } }, 165 { KE_KEY, 0x143, { KEY_TOUCHPAD_TOGGLE } },
150 { KE_KEY, 0x17f, { KEY_FN } }, 166 { KE_KEY, 0x17f, { KEY_FN } },
151 { KE_KEY, 0xb05, { KEY_PROG2 } }, 167 { KE_KEY, 0xb05, { KEY_PROG2 } },
152 { KE_KEY, 0xb06, { KEY_WWW } }, 168 { KE_KEY, 0xb06, { KEY_WWW } },
@@ -156,6 +172,7 @@ static const struct key_entry toshiba_acpi_keymap[] __devinitconst = {
156 { KE_KEY, 0xb32, { KEY_NEXTSONG } }, 172 { KE_KEY, 0xb32, { KEY_NEXTSONG } },
157 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } }, 173 { KE_KEY, 0xb33, { KEY_PLAYPAUSE } },
158 { KE_KEY, 0xb5a, { KEY_MEDIA } }, 174 { KE_KEY, 0xb5a, { KEY_MEDIA } },
175 { KE_IGNORE, 0x1430, { KEY_RESERVED } },
159 { KE_END, 0 }, 176 { KE_END, 0 },
160}; 177};
161 178
@@ -847,10 +864,78 @@ static const struct backlight_ops toshiba_backlight_data = {
847 .update_status = set_lcd_status, 864 .update_status = set_lcd_status,
848}; 865};
849 866
867static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
868 struct serio *port)
869{
870 if (str & 0x20)
871 return false;
872
873 if (unlikely(data == 0xe0))
874 return false;
875
876 if ((data & 0x7f) == TOS1900_FN_SCAN) {
877 schedule_work(&toshiba_acpi->hotkey_work);
878 return true;
879 }
880
881 return false;
882}
883
884static void toshiba_acpi_hotkey_work(struct work_struct *work)
885{
886 acpi_handle ec_handle = ec_get_handle();
887 acpi_status status;
888
889 if (!ec_handle)
890 return;
891
892 status = acpi_evaluate_object(ec_handle, "NTFY", NULL, NULL);
893 if (ACPI_FAILURE(status))
894 pr_err("ACPI NTFY method execution failed\n");
895}
896
897/*
898 * Returns hotkey scancode, or < 0 on failure.
899 */
900static int toshiba_acpi_query_hotkey(struct toshiba_acpi_dev *dev)
901{
902 struct acpi_buffer buf;
903 union acpi_object out_obj;
904 acpi_status status;
905
906 buf.pointer = &out_obj;
907 buf.length = sizeof(out_obj);
908
909 status = acpi_evaluate_object(dev->acpi_dev->handle, "INFO",
910 NULL, &buf);
911 if (ACPI_FAILURE(status) || out_obj.type != ACPI_TYPE_INTEGER) {
912 pr_err("ACPI INFO method execution failed\n");
913 return -EIO;
914 }
915
916 return out_obj.integer.value;
917}
918
919static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
920 int scancode)
921{
922 if (scancode == 0x100)
923 return;
924
925 /* act on key press; ignore key release */
926 if (scancode & 0x80)
927 return;
928
929 if (!sparse_keymap_report_event(dev->hotkey_dev, scancode, 1, true))
930 pr_info("Unknown key %x\n", scancode);
931}
932
850static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) 933static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
851{ 934{
852 acpi_status status; 935 acpi_status status;
936 acpi_handle ec_handle, handle;
853 int error; 937 int error;
938 u32 hci_result;
854 939
855 dev->hotkey_dev = input_allocate_device(); 940 dev->hotkey_dev = input_allocate_device();
856 if (!dev->hotkey_dev) { 941 if (!dev->hotkey_dev) {
@@ -866,21 +951,67 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
866 if (error) 951 if (error)
867 goto err_free_dev; 952 goto err_free_dev;
868 953
954 /*
955 * For some machines the SCI responsible for providing hotkey
956 * notification doesn't fire. We can trigger the notification
957 * whenever the Fn key is pressed using the NTFY method, if
958 * supported, so if it's present set up an i8042 key filter
959 * for this purpose.
960 */
961 status = AE_ERROR;
962 ec_handle = ec_get_handle();
963 if (ec_handle)
964 status = acpi_get_handle(ec_handle, "NTFY", &handle);
965
966 if (ACPI_SUCCESS(status)) {
967 INIT_WORK(&dev->hotkey_work, toshiba_acpi_hotkey_work);
968
969 error = i8042_install_filter(toshiba_acpi_i8042_filter);
970 if (error) {
971 pr_err("Error installing key filter\n");
972 goto err_free_keymap;
973 }
974
975 dev->ntfy_supported = 1;
976 }
977
978 /*
979 * Determine hotkey query interface. Prefer using the INFO
980 * method when it is available.
981 */
982 status = acpi_get_handle(dev->acpi_dev->handle, "INFO", &handle);
983 if (ACPI_SUCCESS(status)) {
984 dev->info_supported = 1;
985 } else {
986 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
987 if (hci_result == HCI_SUCCESS)
988 dev->system_event_supported = 1;
989 }
990
991 if (!dev->info_supported && !dev->system_event_supported) {
992 pr_warn("No hotkey query interface found\n");
993 goto err_remove_filter;
994 }
995
869 status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL); 996 status = acpi_evaluate_object(dev->acpi_dev->handle, "ENAB", NULL, NULL);
870 if (ACPI_FAILURE(status)) { 997 if (ACPI_FAILURE(status)) {
871 pr_info("Unable to enable hotkeys\n"); 998 pr_info("Unable to enable hotkeys\n");
872 error = -ENODEV; 999 error = -ENODEV;
873 goto err_free_keymap; 1000 goto err_remove_filter;
874 } 1001 }
875 1002
876 error = input_register_device(dev->hotkey_dev); 1003 error = input_register_device(dev->hotkey_dev);
877 if (error) { 1004 if (error) {
878 pr_info("Unable to register input device\n"); 1005 pr_info("Unable to register input device\n");
879 goto err_free_keymap; 1006 goto err_remove_filter;
880 } 1007 }
881 1008
1009 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &hci_result);
882 return 0; 1010 return 0;
883 1011
1012 err_remove_filter:
1013 if (dev->ntfy_supported)
1014 i8042_remove_filter(toshiba_acpi_i8042_filter);
884 err_free_keymap: 1015 err_free_keymap:
885 sparse_keymap_free(dev->hotkey_dev); 1016 sparse_keymap_free(dev->hotkey_dev);
886 err_free_dev: 1017 err_free_dev:
@@ -895,6 +1026,11 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
895 1026
896 remove_toshiba_proc_entries(dev); 1027 remove_toshiba_proc_entries(dev);
897 1028
1029 if (dev->ntfy_supported) {
1030 i8042_remove_filter(toshiba_acpi_i8042_filter);
1031 cancel_work_sync(&dev->hotkey_work);
1032 }
1033
898 if (dev->hotkey_dev) { 1034 if (dev->hotkey_dev) {
899 input_unregister_device(dev->hotkey_dev); 1035 input_unregister_device(dev->hotkey_dev);
900 sparse_keymap_free(dev->hotkey_dev); 1036 sparse_keymap_free(dev->hotkey_dev);
@@ -911,6 +1047,9 @@ static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
911 if (dev->illumination_supported) 1047 if (dev->illumination_supported)
912 led_classdev_unregister(&dev->led_dev); 1048 led_classdev_unregister(&dev->led_dev);
913 1049
1050 if (toshiba_acpi)
1051 toshiba_acpi = NULL;
1052
914 kfree(dev); 1053 kfree(dev);
915 1054
916 return 0; 1055 return 0;
@@ -936,12 +1075,14 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
936{ 1075{
937 struct toshiba_acpi_dev *dev; 1076 struct toshiba_acpi_dev *dev;
938 const char *hci_method; 1077 const char *hci_method;
939 u32 hci_result;
940 u32 dummy; 1078 u32 dummy;
941 bool bt_present; 1079 bool bt_present;
942 int ret = 0; 1080 int ret = 0;
943 struct backlight_properties props; 1081 struct backlight_properties props;
944 1082
1083 if (toshiba_acpi)
1084 return -EBUSY;
1085
945 pr_info("Toshiba Laptop ACPI Extras version %s\n", 1086 pr_info("Toshiba Laptop ACPI Extras version %s\n",
946 TOSHIBA_ACPI_VERSION); 1087 TOSHIBA_ACPI_VERSION);
947 1088
@@ -963,11 +1104,6 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
963 1104
964 mutex_init(&dev->mutex); 1105 mutex_init(&dev->mutex);
965 1106
966 /* enable event fifo */
967 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result);
968 if (hci_result == HCI_SUCCESS)
969 dev->system_event_supported = 1;
970
971 props.type = BACKLIGHT_PLATFORM; 1107 props.type = BACKLIGHT_PLATFORM;
972 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 1108 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
973 dev->backlight_dev = backlight_device_register("toshiba", 1109 dev->backlight_dev = backlight_device_register("toshiba",
@@ -1024,6 +1160,8 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
1024 1160
1025 create_toshiba_proc_entries(dev); 1161 create_toshiba_proc_entries(dev);
1026 1162
1163 toshiba_acpi = dev;
1164
1027 return 0; 1165 return 0;
1028 1166
1029error: 1167error:
@@ -1036,40 +1174,64 @@ static void toshiba_acpi_notify(struct acpi_device *acpi_dev, u32 event)
1036 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 1174 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1037 u32 hci_result, value; 1175 u32 hci_result, value;
1038 int retries = 3; 1176 int retries = 3;
1177 int scancode;
1039 1178
1040 if (!dev->system_event_supported || event != 0x80) 1179 if (event != 0x80)
1041 return; 1180 return;
1042 1181
1043 do { 1182 if (dev->info_supported) {
1044 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result); 1183 scancode = toshiba_acpi_query_hotkey(dev);
1045 switch (hci_result) { 1184 if (scancode < 0)
1046 case HCI_SUCCESS: 1185 pr_err("Failed to query hotkey event\n");
1047 if (value == 0x100) 1186 else if (scancode != 0)
1048 continue; 1187 toshiba_acpi_report_hotkey(dev, scancode);
1049 /* act on key press; ignore key release */ 1188 } else if (dev->system_event_supported) {
1050 if (value & 0x80) 1189 do {
1051 continue; 1190 hci_read1(dev, HCI_SYSTEM_EVENT, &value, &hci_result);
1052 1191 switch (hci_result) {
1053 if (!sparse_keymap_report_event(dev->hotkey_dev, 1192 case HCI_SUCCESS:
1054 value, 1, true)) { 1193 toshiba_acpi_report_hotkey(dev, (int)value);
1055 pr_info("Unknown key %x\n", 1194 break;
1056 value); 1195 case HCI_NOT_SUPPORTED:
1196 /*
1197 * This is a workaround for an unresolved
1198 * issue on some machines where system events
1199 * sporadically become disabled.
1200 */
1201 hci_write1(dev, HCI_SYSTEM_EVENT, 1,
1202 &hci_result);
1203 pr_notice("Re-enabled hotkeys\n");
1204 /* fall through */
1205 default:
1206 retries--;
1207 break;
1057 } 1208 }
1058 break; 1209 } while (retries && hci_result != HCI_EMPTY);
1059 case HCI_NOT_SUPPORTED: 1210 }
1060 /* This is a workaround for an unresolved issue on 1211}
1061 * some machines where system events sporadically 1212
1062 * become disabled. */ 1213static int toshiba_acpi_suspend(struct acpi_device *acpi_dev,
1063 hci_write1(dev, HCI_SYSTEM_EVENT, 1, &hci_result); 1214 pm_message_t state)
1064 pr_notice("Re-enabled hotkeys\n"); 1215{
1065 /* fall through */ 1216 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1066 default: 1217 u32 result;
1067 retries--; 1218
1068 break; 1219 if (dev->hotkey_dev)
1069 } 1220 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_DISABLE, &result);
1070 } while (retries && hci_result != HCI_EMPTY); 1221
1222 return 0;
1071} 1223}
1072 1224
1225static int toshiba_acpi_resume(struct acpi_device *acpi_dev)
1226{
1227 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
1228 u32 result;
1229
1230 if (dev->hotkey_dev)
1231 hci_write1(dev, HCI_HOTKEY_EVENT, HCI_HOTKEY_ENABLE, &result);
1232
1233 return 0;
1234}
1073 1235
1074static struct acpi_driver toshiba_acpi_driver = { 1236static struct acpi_driver toshiba_acpi_driver = {
1075 .name = "Toshiba ACPI driver", 1237 .name = "Toshiba ACPI driver",
@@ -1080,6 +1242,8 @@ static struct acpi_driver toshiba_acpi_driver = {
1080 .add = toshiba_acpi_add, 1242 .add = toshiba_acpi_add,
1081 .remove = toshiba_acpi_remove, 1243 .remove = toshiba_acpi_remove,
1082 .notify = toshiba_acpi_notify, 1244 .notify = toshiba_acpi_notify,
1245 .suspend = toshiba_acpi_suspend,
1246 .resume = toshiba_acpi_resume,
1083 }, 1247 },
1084}; 1248};
1085 1249
@@ -1087,6 +1251,14 @@ static int __init toshiba_acpi_init(void)
1087{ 1251{
1088 int ret; 1252 int ret;
1089 1253
1254 /*
1255 * Machines with this WMI guid aren't supported due to bugs in
1256 * their AML. This check relies on wmi initializing before
1257 * toshiba_acpi to guarantee guids have been identified.
1258 */
1259 if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID))
1260 return -ENODEV;
1261
1090 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir); 1262 toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
1091 if (!toshiba_proc_dir) { 1263 if (!toshiba_proc_dir) {
1092 pr_err("Unable to create proc dir " PROC_TOSHIBA "\n"); 1264 pr_err("Unable to create proc dir " PROC_TOSHIBA "\n");
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c
index e549eeeda121..41781ed8301c 100644
--- a/drivers/platform/x86/xo1-rfkill.c
+++ b/drivers/platform/x86/xo1-rfkill.c
@@ -67,19 +67,8 @@ static struct platform_driver xo1_rfkill_driver = {
67 .remove = __devexit_p(xo1_rfkill_remove), 67 .remove = __devexit_p(xo1_rfkill_remove),
68}; 68};
69 69
70static int __init xo1_rfkill_init(void) 70module_platform_driver(xo1_rfkill_driver);
71{
72 return platform_driver_register(&xo1_rfkill_driver);
73}
74
75static void __exit xo1_rfkill_exit(void)
76{
77 platform_driver_unregister(&xo1_rfkill_driver);
78}
79 71
80MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); 72MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>");
81MODULE_LICENSE("GPL"); 73MODULE_LICENSE("GPL");
82MODULE_ALIAS("platform:xo1-rfkill"); 74MODULE_ALIAS("platform:xo1-rfkill");
83
84module_init(xo1_rfkill_init);
85module_exit(xo1_rfkill_exit);