Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mjg59/platform-drivers-x86: (81 commits)
xo15-ebook: Remove device.wakeup_count
ips: use interruptible waits in ips-monitor
acer-wmi: does not poll device status when WMI event is available
acer-wmi: does not set persistence state by rfkill_init_sw_state
platform-drivers: x86: fix common misspellings
acer-wmi: use pr_<level> for messages
asus-wmi: potential NULL dereference in show_call()
asus-wmi: signedness bug in read_brightness()
platform-driver-x86: samsung-laptop: make dmi_check_cb to return 1 instead of 0
platform-driver-x86: fix wrong merge for compal-laptop.c
msi-laptop: use pr_<level> for messages
Platform: add Samsung Laptop platform driver
acer-wmi: Fix WMI ID
acer-wmi: deactive mail led when power off
msi-laptop: send out touchpad on/off key
acer-wmi: set the touchpad toggle key code to KEY_TOUCHPAD_TOGGLE
platform-driver-x86: intel_mid_thermal: fix unterminated platform_device_id table
sony-laptop: potential null dereference
sony-laptop: handle allocation failures
sony-laptop: return negative on failure in sony_nc_add()
...

+4850 -1264
+19
Documentation/ABI/testing/sysfs-driver-samsung-laptop
··· 1 + What: /sys/devices/platform/samsung/performance_level 2 + Date: January 1, 2010 3 + KernelVersion: 2.6.33 4 + Contact: Greg Kroah-Hartman <gregkh@suse.de> 5 + Description: Some Samsung laptops have different "performance levels" 6 + that are can be modified by a function key, and by this 7 + sysfs file. These values don't always make a whole lot 8 + of sense, but some users like to modify them to keep 9 + their fans quiet at all costs. Reading from this file 10 + will show the current performance level. Writing to the 11 + file can change this value. 12 + Valid options: 13 + "silent" 14 + "normal" 15 + "overclock" 16 + Note that not all laptops support all of these options. 17 + Specifically, not all support the "overclock" option, 18 + and it's still unknown if this value even changes 19 + anything, other than making the user feel a bit better.
+31
Documentation/ABI/testing/sysfs-platform-asus-wmi
··· 1 + What: /sys/devices/platform/<platform>/cpufv 2 + Date: Oct 2010 3 + KernelVersion: 2.6.37 4 + Contact: "Corentin Chary" <corentincj@iksaif.net> 5 + Description: 6 + Change CPU clock configuration (write-only). 7 + There are three available clock configuration: 8 + * 0 -> Super Performance Mode 9 + * 1 -> High Performance Mode 10 + * 2 -> Power Saving Mode 11 + 12 + What: /sys/devices/platform/<platform>/camera 13 + Date: Jan 2010 14 + KernelVersion: 2.6.39 15 + Contact: "Corentin Chary" <corentincj@iksaif.net> 16 + Description: 17 + Control the camera. 1 means on, 0 means off. 18 + 19 + What: /sys/devices/platform/<platform>/cardr 20 + Date: Jan 2010 21 + KernelVersion: 2.6.39 22 + Contact: "Corentin Chary" <corentincj@iksaif.net> 23 + Description: 24 + Control the card reader. 1 means on, 0 means off. 25 + 26 + What: /sys/devices/platform/<platform>/touchpad 27 + Date: Jan 2010 28 + KernelVersion: 2.6.39 29 + Contact: "Corentin Chary" <corentincj@iksaif.net> 30 + Description: 31 + Control the card touchpad. 1 means on, 0 means off.
-10
Documentation/ABI/testing/sysfs-platform-eeepc-wmi
··· 1 - What: /sys/devices/platform/eeepc-wmi/cpufv 2 - Date: Oct 2010 3 - KernelVersion: 2.6.37 4 - Contact: "Corentin Chary" <corentincj@iksaif.net> 5 - Description: 6 - Change CPU clock configuration (write-only). 7 - There are three available clock configuration: 8 - * 0 -> Super Performance Mode 9 - * 1 -> High Performance Mode 10 - * 2 -> Power Saving Mode
+30 -7
Documentation/laptops/sony-laptop.txt
··· 14 14 reported both through the ACPI subsystem as acpi events and through the INPUT 15 15 subsystem. See the logs of acpid or /proc/acpi/event and 16 16 /proc/bus/input/devices to find out what those events are and which input 17 - devices are created by the driver. 17 + devices are created by the driver. Additionally, loading the driver with the 18 + debug option will report all events in the kernel log. 18 19 19 20 Backlight control: 20 21 ------------------ ··· 65 64 # echo "1" > /sys/devices/platform/sony-laptop/audiopower 66 65 powers on the sound card. 67 66 67 + 68 + RFkill control: 69 + --------------- 70 + More recent Vaio models expose a consistent set of ACPI methods to 71 + control radio frequency emitting devices. If you are a lucky owner of 72 + such a laptop you will find the necessary rfkill devices under 73 + /sys/class/rfkill. Check those starting with sony-* in 74 + # grep . /sys/class/rfkill/*/{state,name} 75 + 76 + 68 77 Development: 69 78 ------------ 70 79 ··· 86 75 REPEAT: DON'T DO THIS IF YOU DON'T LIKE RISKY BUSINESS. 87 76 88 77 In your kernel logs you will find the list of all ACPI methods 89 - the SNC device has on your laptop. You can see the GCDP/GCDP methods 90 - used to pwer on/off the CD drive, but there are others. 78 + the SNC device has on your laptop. 79 + 80 + * For new models you will see a long list of meaningless method names, 81 + reading the DSDT table source should reveal that: 82 + (1) the SNC device uses an internal capability lookup table 83 + (2) SN00 is used to find values in the lookup table 84 + (3) SN06 and SN07 are used to call into the real methods based on 85 + offsets you can obtain iterating the table using SN00 86 + (4) SN02 used to enable events. 87 + Some values in the capability lookup table are more or less known, see 88 + the code for all sony_call_snc_handle calls, others are more obscure. 89 + 90 + * For old models you can see the GCDP/GCDP methods used to pwer on/off 91 + the CD drive, but there are others and they are usually different from 92 + model to model. 91 93 92 94 I HAVE NO IDEA WHAT THOSE METHODS DO. 93 95 ··· 132 108 laptop, including permanent damage. 133 109 134 110 * The sony-laptop and sonypi drivers do not interact at all. In the 135 - future, sonypi could use sony-laptop to do (part of) its business. 111 + future, sonypi will be removed and replaced by sony-laptop. 136 112 137 113 * spicctrl, which is the userspace tool used to communicate with the 138 - sonypi driver (through /dev/sonypi) does not try to use the 139 - sony-laptop driver. In the future, spicctrl could try sonypi first, 140 - and if it isn't present, try sony-laptop instead. 114 + sonypi driver (through /dev/sonypi) is deprecated as well since all 115 + its features are now available under the sysfs tree via sony-laptop.
+3 -27
MAINTAINERS
··· 1157 1157 F: Documentation/hwmon/asc7621 1158 1158 F: drivers/hwmon/asc7621.c 1159 1159 1160 - ASUS ACPI EXTRAS DRIVER 1160 + ASUS NOTEBOOKS AND EEEPC ACPI/WMI EXTRAS DRIVERS 1161 1161 M: Corentin Chary <corentincj@iksaif.net> 1162 - M: Karol Kozimor <sziwan@users.sourceforge.net> 1163 1162 L: acpi4asus-user@lists.sourceforge.net 1164 1163 L: platform-driver-x86@vger.kernel.org 1165 1164 W: http://acpi4asus.sf.net 1166 1165 S: Maintained 1167 - F: drivers/platform/x86/asus_acpi.c 1166 + F: drivers/platform/x86/asus*.c 1167 + F: drivers/platform/x86/eeepc*.c 1168 1168 1169 1169 ASUS ASB100 HARDWARE MONITOR DRIVER 1170 1170 M: "Mark M. Hoffman" <mhoffman@lightlink.com> 1171 1171 L: lm-sensors@lm-sensors.org 1172 1172 S: Maintained 1173 1173 F: drivers/hwmon/asb100.c 1174 - 1175 - ASUS LAPTOP EXTRAS DRIVER 1176 - M: Corentin Chary <corentincj@iksaif.net> 1177 - L: acpi4asus-user@lists.sourceforge.net 1178 - L: platform-driver-x86@vger.kernel.org 1179 - W: http://acpi4asus.sf.net 1180 - S: Maintained 1181 - F: drivers/platform/x86/asus-laptop.c 1182 1174 1183 1175 ASYNCHRONOUS TRANSFERS/TRANSFORMS (IOAT) API 1184 1176 M: Dan Williams <dan.j.williams@intel.com> ··· 2405 2413 T: git git://git.alsa-project.org/alsa-kernel.git 2406 2414 S: Maintained 2407 2415 F: sound/usb/misc/ua101.c 2408 - 2409 - EEEPC LAPTOP EXTRAS DRIVER 2410 - M: Corentin Chary <corentincj@iksaif.net> 2411 - L: acpi4asus-user@lists.sourceforge.net 2412 - L: platform-driver-x86@vger.kernel.org 2413 - W: http://acpi4asus.sf.net 2414 - S: Maintained 2415 - F: drivers/platform/x86/eeepc-laptop.c 2416 - 2417 - EEEPC WMI EXTRAS DRIVER 2418 - M: Corentin Chary <corentincj@iksaif.net> 2419 - L: acpi4asus-user@lists.sourceforge.net 2420 - L: platform-driver-x86@vger.kernel.org 2421 - W: http://acpi4asus.sf.net 2422 - S: Maintained 2423 - F: drivers/platform/x86/eeepc-wmi.c 2424 2416 2425 2417 EFIFB FRAMEBUFFER DRIVER 2426 2418 L: linux-fbdev@vger.kernel.org
+85 -5
drivers/platform/x86/Kconfig
··· 101 101 To compile this driver as a module, choose M here: the module will 102 102 be called dell-wmi. 103 103 104 + config DELL_WMI_AIO 105 + tristate "WMI Hotkeys for Dell All-In-One series" 106 + depends on ACPI_WMI 107 + depends on INPUT 108 + select INPUT_SPARSEKMAP 109 + ---help--- 110 + Say Y here if you want to support WMI-based hotkeys on Dell 111 + All-In-One machines. 112 + 113 + To compile this driver as a module, choose M here: the module will 114 + be called dell-wmi. 115 + 116 + 104 117 config FUJITSU_LAPTOP 105 118 tristate "Fujitsu Laptop Extras" 106 119 depends on ACPI ··· 451 438 Bluetooth, backlight and allows powering on/off some other 452 439 devices. 453 440 454 - If you have an Eee PC laptop, say Y or M here. 441 + If you have an Eee PC laptop, say Y or M here. If this driver 442 + doesn't work on your Eee PC, try eeepc-wmi instead. 455 443 456 - config EEEPC_WMI 457 - tristate "Eee PC WMI Hotkey Driver (EXPERIMENTAL)" 444 + config ASUS_WMI 445 + tristate "ASUS WMI Driver (EXPERIMENTAL)" 458 446 depends on ACPI_WMI 459 447 depends on INPUT 448 + depends on HWMON 460 449 depends on EXPERIMENTAL 461 450 depends on BACKLIGHT_CLASS_DEVICE 462 451 depends on RFKILL || RFKILL = n 452 + depends on HOTPLUG_PCI 463 453 select INPUT_SPARSEKMAP 464 454 select LEDS_CLASS 465 455 select NEW_LEDS 466 456 ---help--- 467 - Say Y here if you want to support WMI-based hotkeys on Eee PC laptops. 457 + Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new 458 + Asus Notebooks). 468 459 469 460 To compile this driver as a module, choose M here: the module will 470 - be called eeepc-wmi. 461 + be called asus-wmi. 462 + 463 + config ASUS_NB_WMI 464 + tristate "Asus Notebook WMI Driver (EXPERIMENTAL)" 465 + depends on ASUS_WMI 466 + ---help--- 467 + This is a driver for newer Asus notebooks. It adds extra features 468 + like wireless radio and bluetooth control, leds, hotkeys, backlight... 469 + 470 + For more informations, see 471 + <file:Documentation/ABI/testing/sysfs-platform-asus-wmi> 472 + 473 + If you have an ACPI-WMI compatible Asus Notebook, say Y or M 474 + here. 475 + 476 + config EEEPC_WMI 477 + tristate "Eee PC WMI Driver (EXPERIMENTAL)" 478 + depends on ASUS_WMI 479 + ---help--- 480 + This is a driver for newer Eee PC laptops. It adds extra features 481 + like wireless radio and bluetooth control, leds, hotkeys, backlight... 482 + 483 + For more informations, see 484 + <file:Documentation/ABI/testing/sysfs-platform-asus-wmi> 485 + 486 + If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M 487 + here. 471 488 472 489 config ACPI_WMI 473 490 tristate "WMI" ··· 659 616 Say Y here to support GPIO via the SCU IPC interface 660 617 on Intel MID platforms. 661 618 619 + config INTEL_MID_POWER_BUTTON 620 + tristate "power button driver for Intel MID platforms" 621 + depends on INTEL_SCU_IPC && INPUT 622 + help 623 + This driver handles the power button on the Intel MID platforms. 624 + 625 + If unsure, say N. 626 + 627 + config INTEL_MFLD_THERMAL 628 + tristate "Thermal driver for Intel Medfield platform" 629 + depends on INTEL_SCU_IPC && THERMAL 630 + help 631 + Say Y here to enable thermal driver support for the Intel Medfield 632 + platform. 633 + 662 634 config RAR_REGISTER 663 635 bool "Restricted Access Region Register Driver" 664 636 depends on PCI && X86_MRST ··· 729 671 ---help--- 730 672 Support for enabling/disabling the WLAN interface on the OLPC XO-1 731 673 laptop. 674 + 675 + config XO15_EBOOK 676 + tristate "OLPC XO-1.5 ebook switch" 677 + depends on ACPI && INPUT 678 + ---help--- 679 + Support for the ebook switch on the OLPC XO-1.5 laptop. 680 + 681 + This switch is triggered as the screen is rotated and folded down to 682 + convert the device into ebook form. 683 + 684 + config SAMSUNG_LAPTOP 685 + tristate "Samsung Laptop driver" 686 + depends on RFKILL && BACKLIGHT_CLASS_DEVICE && X86 687 + ---help--- 688 + This module implements a driver for a wide range of different 689 + Samsung laptops. It offers control over the different 690 + function keys, wireless LED, LCD backlight level, and 691 + sometimes provides a "performance_control" sysfs file to allow 692 + the performance level of the laptop to be changed. 693 + 694 + To compile this driver as a module, choose M here: the module 695 + will be called samsung-laptop. 732 696 733 697 endif # X86_PLATFORM_DEVICES
+8 -1
drivers/platform/x86/Makefile
··· 3 3 # x86 Platform-Specific Drivers 4 4 # 5 5 obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o 6 + obj-$(CONFIG_ASUS_WMI) += asus-wmi.o 7 + obj-$(CONFIG_ASUS_NB_WMI) += asus-nb-wmi.o 6 8 obj-$(CONFIG_EEEPC_LAPTOP) += eeepc-laptop.o 7 9 obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o 8 10 obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o ··· 12 10 obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o 13 11 obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o 14 12 obj-$(CONFIG_DELL_WMI) += dell-wmi.o 13 + obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o 15 14 obj-$(CONFIG_ACER_WMI) += acer-wmi.o 16 15 obj-$(CONFIG_ACERHDF) += acerhdf.o 17 16 obj-$(CONFIG_HP_ACCEL) += hp_accel.o ··· 32 29 obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o 33 30 obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o 34 31 obj-$(CONFIG_INTEL_SCU_IPC) += intel_scu_ipc.o 35 - obj-$(CONFIG_INTEL_SCU_IPC_UTIL)+= intel_scu_ipcutil.o 32 + obj-$(CONFIG_INTEL_SCU_IPC_UTIL) += intel_scu_ipcutil.o 33 + obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o 36 34 obj-$(CONFIG_RAR_REGISTER) += intel_rar_register.o 37 35 obj-$(CONFIG_INTEL_IPS) += intel_ips.o 38 36 obj-$(CONFIG_GPIO_INTEL_PMIC) += intel_pmic_gpio.o 39 37 obj-$(CONFIG_XO1_RFKILL) += xo1-rfkill.o 38 + obj-$(CONFIG_XO15_EBOOK) += xo15-ebook.o 40 39 obj-$(CONFIG_IBM_RTL) += ibm_rtl.o 40 + obj-$(CONFIG_SAMSUNG_LAPTOP) += samsung-laptop.o 41 + obj-$(CONFIG_INTEL_MFLD_THERMAL) += intel_mid_thermal.o
+77 -50
drivers/platform/x86/acer-wmi.c
··· 22 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23 23 */ 24 24 25 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 26 + 25 27 #include <linux/kernel.h> 26 28 #include <linux/module.h> 27 29 #include <linux/init.h> ··· 47 45 MODULE_AUTHOR("Carlos Corbacho"); 48 46 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver"); 49 47 MODULE_LICENSE("GPL"); 50 - 51 - #define ACER_LOGPREFIX "acer-wmi: " 52 - #define ACER_ERR KERN_ERR ACER_LOGPREFIX 53 - #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX 54 - #define ACER_INFO KERN_INFO ACER_LOGPREFIX 55 - #define ACER_WARNING KERN_WARNING ACER_LOGPREFIX 56 48 57 49 /* 58 50 * Magic Number ··· 80 84 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB" 81 85 #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C" 82 86 #define WMID_GUID1 "6AF4F258-B401-42FD-BE91-3D4AC2D7C0D3" 83 - #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A" 87 + #define WMID_GUID2 "95764E09-FB56-4E83-B31A-37761F60994A" 84 88 #define WMID_GUID3 "61EF69EA-865C-4BC3-A502-A0DEBA0CB531" 85 89 86 90 /* ··· 89 93 #define ACERWMID_EVENT_GUID "676AA15E-6A47-4D9F-A2CC-1E6D18D14026" 90 94 91 95 MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB"); 92 - MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"); 96 + MODULE_ALIAS("wmi:6AF4F258-B401-42Fd-BE91-3D4AC2D7C0D3"); 93 97 MODULE_ALIAS("wmi:676AA15E-6A47-4D9F-A2CC-1E6D18D14026"); 94 98 95 99 enum acer_wmi_event_ids { ··· 104 108 {KE_KEY, 0x23, {KEY_PROG3} }, /* P_Key */ 105 109 {KE_KEY, 0x24, {KEY_PROG4} }, /* Social networking_Key */ 106 110 {KE_KEY, 0x64, {KEY_SWITCHVIDEOMODE} }, /* Display Switch */ 107 - {KE_KEY, 0x82, {KEY_F22} }, /* Touch Pad On/Off */ 111 + {KE_KEY, 0x82, {KEY_TOUCHPAD_TOGGLE} }, /* Touch Pad On/Off */ 108 112 {KE_END, 0} 109 113 }; 110 114 ··· 217 221 static struct rfkill *wireless_rfkill; 218 222 static struct rfkill *bluetooth_rfkill; 219 223 static struct rfkill *threeg_rfkill; 224 + static bool rfkill_inited; 220 225 221 226 /* Each low-level interface must define at least some of the following */ 222 227 struct wmi_interface { ··· 842 845 has_type_aa = true; 843 846 type_aa = (struct hotkey_function_type_aa *) header; 844 847 845 - printk(ACER_INFO "Function bitmap for Communication Button: 0x%x\n", 848 + pr_info("Function bitmap for Communication Button: 0x%x\n", 846 849 type_aa->commun_func_bitmap); 847 850 848 851 if (type_aa->commun_func_bitmap & ACER_WMID3_GDS_WIRELESS) ··· 988 991 989 992 static void acer_led_exit(void) 990 993 { 994 + set_u32(LED_OFF, ACER_CAP_MAILLED); 991 995 led_classdev_unregister(&mail_led); 992 996 } 993 997 ··· 1034 1036 bd = backlight_device_register("acer-wmi", dev, NULL, &acer_bl_ops, 1035 1037 &props); 1036 1038 if (IS_ERR(bd)) { 1037 - printk(ACER_ERR "Could not register Acer backlight device\n"); 1039 + pr_err("Could not register Acer backlight device\n"); 1038 1040 acer_backlight_device = NULL; 1039 1041 return PTR_ERR(bd); 1040 1042 } ··· 1081 1083 return AE_ERROR; 1082 1084 } 1083 1085 if (obj->buffer.length != 8) { 1084 - printk(ACER_WARNING "Unknown buffer length %d\n", 1085 - obj->buffer.length); 1086 + pr_warning("Unknown buffer length %d\n", obj->buffer.length); 1086 1087 kfree(obj); 1087 1088 return AE_ERROR; 1088 1089 } ··· 1090 1093 kfree(obj); 1091 1094 1092 1095 if (return_value.error_code || return_value.ec_return_value) 1093 - printk(ACER_WARNING "Get Device Status failed: " 1096 + pr_warning("Get Device Status failed: " 1094 1097 "0x%x - 0x%x\n", return_value.error_code, 1095 1098 return_value.ec_return_value); 1096 1099 else ··· 1158 1161 { 1159 1162 acpi_status status; 1160 1163 u32 cap = (unsigned long)data; 1161 - status = set_u32(!blocked, cap); 1162 - if (ACPI_FAILURE(status)) 1163 - return -ENODEV; 1164 + 1165 + if (rfkill_inited) { 1166 + status = set_u32(!blocked, cap); 1167 + if (ACPI_FAILURE(status)) 1168 + return -ENODEV; 1169 + } 1170 + 1164 1171 return 0; 1165 1172 } 1166 1173 ··· 1188 1187 return ERR_PTR(-ENOMEM); 1189 1188 1190 1189 status = get_device_status(&state, cap); 1191 - if (ACPI_SUCCESS(status)) 1192 - rfkill_init_sw_state(rfkill_dev, !state); 1193 1190 1194 1191 err = rfkill_register(rfkill_dev); 1195 1192 if (err) { 1196 1193 rfkill_destroy(rfkill_dev); 1197 1194 return ERR_PTR(err); 1198 1195 } 1196 + 1197 + if (ACPI_SUCCESS(status)) 1198 + rfkill_set_sw_state(rfkill_dev, !state); 1199 + 1199 1200 return rfkill_dev; 1200 1201 } 1201 1202 ··· 1232 1229 } 1233 1230 } 1234 1231 1235 - schedule_delayed_work(&acer_rfkill_work, round_jiffies_relative(HZ)); 1232 + rfkill_inited = true; 1233 + 1234 + if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) 1235 + schedule_delayed_work(&acer_rfkill_work, 1236 + round_jiffies_relative(HZ)); 1236 1237 1237 1238 return 0; 1238 1239 } 1239 1240 1240 1241 static void acer_rfkill_exit(void) 1241 1242 { 1242 - cancel_delayed_work_sync(&acer_rfkill_work); 1243 + if (ec_raw_mode || !wmi_has_guid(ACERWMID_EVENT_GUID)) 1244 + cancel_delayed_work_sync(&acer_rfkill_work); 1243 1245 1244 1246 rfkill_unregister(wireless_rfkill); 1245 1247 rfkill_destroy(wireless_rfkill); ··· 1317 1309 1318 1310 status = wmi_get_event_data(value, &response); 1319 1311 if (status != AE_OK) { 1320 - printk(ACER_WARNING "bad event status 0x%x\n", status); 1312 + pr_warning("bad event status 0x%x\n", status); 1321 1313 return; 1322 1314 } 1323 1315 ··· 1326 1318 if (!obj) 1327 1319 return; 1328 1320 if (obj->type != ACPI_TYPE_BUFFER) { 1329 - printk(ACER_WARNING "Unknown response received %d\n", 1330 - obj->type); 1321 + pr_warning("Unknown response received %d\n", obj->type); 1331 1322 kfree(obj); 1332 1323 return; 1333 1324 } 1334 1325 if (obj->buffer.length != 8) { 1335 - printk(ACER_WARNING "Unknown buffer length %d\n", 1336 - obj->buffer.length); 1326 + pr_warning("Unknown buffer length %d\n", obj->buffer.length); 1337 1327 kfree(obj); 1338 1328 return; 1339 1329 } ··· 1341 1335 1342 1336 switch (return_value.function) { 1343 1337 case WMID_HOTKEY_EVENT: 1338 + if (return_value.device_state) { 1339 + u16 device_state = return_value.device_state; 1340 + pr_debug("deivces states: 0x%x\n", device_state); 1341 + if (has_cap(ACER_CAP_WIRELESS)) 1342 + rfkill_set_sw_state(wireless_rfkill, 1343 + !(device_state & ACER_WMID3_GDS_WIRELESS)); 1344 + if (has_cap(ACER_CAP_BLUETOOTH)) 1345 + rfkill_set_sw_state(bluetooth_rfkill, 1346 + !(device_state & ACER_WMID3_GDS_BLUETOOTH)); 1347 + if (has_cap(ACER_CAP_THREEG)) 1348 + rfkill_set_sw_state(threeg_rfkill, 1349 + !(device_state & ACER_WMID3_GDS_THREEG)); 1350 + } 1344 1351 if (!sparse_keymap_report_event(acer_wmi_input_dev, 1345 1352 return_value.key_num, 1, true)) 1346 - printk(ACER_WARNING "Unknown key number - 0x%x\n", 1353 + pr_warning("Unknown key number - 0x%x\n", 1347 1354 return_value.key_num); 1348 1355 break; 1349 1356 default: 1350 - printk(ACER_WARNING "Unknown function number - %d - %d\n", 1357 + pr_warning("Unknown function number - %d - %d\n", 1351 1358 return_value.function, return_value.key_num); 1352 1359 break; 1353 1360 } ··· 1389 1370 return AE_ERROR; 1390 1371 } 1391 1372 if (obj->buffer.length != 4) { 1392 - printk(ACER_WARNING "Unknown buffer length %d\n", 1393 - obj->buffer.length); 1373 + pr_warning("Unknown buffer length %d\n", obj->buffer.length); 1394 1374 kfree(obj); 1395 1375 return AE_ERROR; 1396 1376 } ··· 1414 1396 status = wmid3_set_lm_mode(&params, &return_value); 1415 1397 1416 1398 if (return_value.error_code || return_value.ec_return_value) 1417 - printk(ACER_WARNING "Enabling EC raw mode failed: " 1399 + pr_warning("Enabling EC raw mode failed: " 1418 1400 "0x%x - 0x%x\n", return_value.error_code, 1419 1401 return_value.ec_return_value); 1420 1402 else 1421 - printk(ACER_INFO "Enabled EC raw mode"); 1403 + pr_info("Enabled EC raw mode"); 1422 1404 1423 1405 return status; 1424 1406 } ··· 1437 1419 status = wmid3_set_lm_mode(&params, &return_value); 1438 1420 1439 1421 if (return_value.error_code || return_value.ec_return_value) 1440 - printk(ACER_WARNING "Enabling Launch Manager failed: " 1422 + pr_warning("Enabling Launch Manager failed: " 1441 1423 "0x%x - 0x%x\n", return_value.error_code, 1442 1424 return_value.ec_return_value); 1443 1425 ··· 1571 1553 1572 1554 if (has_cap(ACER_CAP_MAILLED)) { 1573 1555 get_u32(&value, ACER_CAP_MAILLED); 1556 + set_u32(LED_OFF, ACER_CAP_MAILLED); 1574 1557 data->mailled = value; 1575 1558 } 1576 1559 ··· 1599 1580 return 0; 1600 1581 } 1601 1582 1583 + static void acer_platform_shutdown(struct platform_device *device) 1584 + { 1585 + struct acer_data *data = &interface->data; 1586 + 1587 + if (!data) 1588 + return; 1589 + 1590 + if (has_cap(ACER_CAP_MAILLED)) 1591 + set_u32(LED_OFF, ACER_CAP_MAILLED); 1592 + } 1593 + 1602 1594 static struct platform_driver acer_platform_driver = { 1603 1595 .driver = { 1604 1596 .name = "acer-wmi", ··· 1619 1589 .remove = acer_platform_remove, 1620 1590 .suspend = acer_platform_suspend, 1621 1591 .resume = acer_platform_resume, 1592 + .shutdown = acer_platform_shutdown, 1622 1593 }; 1623 1594 1624 1595 static struct platform_device *acer_platform_device; ··· 1667 1636 { 1668 1637 interface->debug.root = debugfs_create_dir("acer-wmi", NULL); 1669 1638 if (!interface->debug.root) { 1670 - printk(ACER_ERR "Failed to create debugfs directory"); 1639 + pr_err("Failed to create debugfs directory"); 1671 1640 return -ENOMEM; 1672 1641 } 1673 1642 ··· 1688 1657 { 1689 1658 int err; 1690 1659 1691 - printk(ACER_INFO "Acer Laptop ACPI-WMI Extras\n"); 1660 + pr_info("Acer Laptop ACPI-WMI Extras\n"); 1692 1661 1693 1662 if (dmi_check_system(acer_blacklist)) { 1694 - printk(ACER_INFO "Blacklisted hardware detected - " 1695 - "not loading\n"); 1663 + pr_info("Blacklisted hardware detected - not loading\n"); 1696 1664 return -ENODEV; 1697 1665 } 1698 1666 ··· 1708 1678 1709 1679 if (wmi_has_guid(WMID_GUID2) && interface) { 1710 1680 if (ACPI_FAILURE(WMID_set_capabilities())) { 1711 - printk(ACER_ERR "Unable to detect available WMID " 1712 - "devices\n"); 1681 + pr_err("Unable to detect available WMID devices\n"); 1713 1682 return -ENODEV; 1714 1683 } 1715 1684 } else if (!wmi_has_guid(WMID_GUID2) && interface) { 1716 - printk(ACER_ERR "No WMID device detection method found\n"); 1685 + pr_err("No WMID device detection method found\n"); 1717 1686 return -ENODEV; 1718 1687 } 1719 1688 ··· 1720 1691 interface = &AMW0_interface; 1721 1692 1722 1693 if (ACPI_FAILURE(AMW0_set_capabilities())) { 1723 - printk(ACER_ERR "Unable to detect available AMW0 " 1724 - "devices\n"); 1694 + pr_err("Unable to detect available AMW0 devices\n"); 1725 1695 return -ENODEV; 1726 1696 } 1727 1697 } ··· 1729 1701 AMW0_find_mailled(); 1730 1702 1731 1703 if (!interface) { 1732 - printk(ACER_INFO "No or unsupported WMI interface, unable to " 1733 - "load\n"); 1704 + pr_err("No or unsupported WMI interface, unable to load\n"); 1734 1705 return -ENODEV; 1735 1706 } 1736 1707 ··· 1737 1710 1738 1711 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS)) { 1739 1712 interface->capability &= ~ACER_CAP_BRIGHTNESS; 1740 - printk(ACER_INFO "Brightness must be controlled by " 1713 + pr_info("Brightness must be controlled by " 1741 1714 "generic video driver\n"); 1742 1715 } 1743 1716 1744 1717 if (wmi_has_guid(WMID_GUID3)) { 1745 1718 if (ec_raw_mode) { 1746 1719 if (ACPI_FAILURE(acer_wmi_enable_ec_raw())) { 1747 - printk(ACER_ERR "Cannot enable EC raw mode\n"); 1720 + pr_err("Cannot enable EC raw mode\n"); 1748 1721 return -ENODEV; 1749 1722 } 1750 1723 } else if (ACPI_FAILURE(acer_wmi_enable_lm())) { 1751 - printk(ACER_ERR "Cannot enable Launch Manager mode\n"); 1724 + pr_err("Cannot enable Launch Manager mode\n"); 1752 1725 return -ENODEV; 1753 1726 } 1754 1727 } else if (ec_raw_mode) { 1755 - printk(ACER_INFO "No WMID EC raw mode enable method\n"); 1728 + pr_info("No WMID EC raw mode enable method\n"); 1756 1729 } 1757 1730 1758 1731 if (wmi_has_guid(ACERWMID_EVENT_GUID)) { ··· 1763 1736 1764 1737 err = platform_driver_register(&acer_platform_driver); 1765 1738 if (err) { 1766 - printk(ACER_ERR "Unable to register platform driver.\n"); 1739 + pr_err("Unable to register platform driver.\n"); 1767 1740 goto error_platform_register; 1768 1741 } 1769 1742 ··· 1818 1791 platform_device_unregister(acer_platform_device); 1819 1792 platform_driver_unregister(&acer_platform_driver); 1820 1793 1821 - printk(ACER_INFO "Acer Laptop WMI Extras unloaded\n"); 1794 + pr_info("Acer Laptop WMI Extras unloaded\n"); 1822 1795 return; 1823 1796 } 1824 1797
+21 -161
drivers/platform/x86/asus-laptop.c
··· 29 29 * John Belmonte - ACPI code for Toshiba laptop was a good starting point. 30 30 * Eric Burghard - LED display support for W1N 31 31 * Josh Green - Light Sens support 32 - * Thomas Tuttle - His first patch for led support was very helpfull 32 + * Thomas Tuttle - His first patch for led support was very helpful 33 33 * Sam Lin - GPS support 34 34 */ 35 35 ··· 50 50 #include <linux/input/sparse-keymap.h> 51 51 #include <linux/rfkill.h> 52 52 #include <linux/slab.h> 53 + #include <linux/dmi.h> 53 54 #include <acpi/acpi_drivers.h> 54 55 #include <acpi/acpi_bus.h> 55 56 ··· 158 157 #define METHOD_BRIGHTNESS_SET "SPLV" 159 158 #define METHOD_BRIGHTNESS_GET "GPLV" 160 159 161 - /* Backlight */ 162 - static acpi_handle lcd_switch_handle; 163 - static char *lcd_switch_paths[] = { 164 - "\\_SB.PCI0.SBRG.EC0._Q10", /* All new models */ 165 - "\\_SB.PCI0.ISA.EC0._Q10", /* A1x */ 166 - "\\_SB.PCI0.PX40.ECD0._Q10", /* L3C */ 167 - "\\_SB.PCI0.PX40.EC0.Q10", /* M1A */ 168 - "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */ 169 - "\\_SB.PCI0.LPCB.EC0._Q0E", /* P30/P35 */ 170 - "\\_SB.PCI0.PX40.Q10", /* S1x */ 171 - "\\Q10"}; /* A2x, L2D, L3D, M2E */ 172 - 173 160 /* Display */ 174 161 #define METHOD_SWITCH_DISPLAY "SDSP" 175 - 176 - static acpi_handle display_get_handle; 177 - static char *display_get_paths[] = { 178 - /* A6B, A6K A6R A7D F3JM L4R M6R A3G M6A M6V VX-1 V6J V6V W3Z */ 179 - "\\_SB.PCI0.P0P1.VGA.GETD", 180 - /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V S5A M5A z33A W1Jc W2V G1 */ 181 - "\\_SB.PCI0.P0P2.VGA.GETD", 182 - /* A6V A6Q */ 183 - "\\_SB.PCI0.P0P3.VGA.GETD", 184 - /* A6T, A6M */ 185 - "\\_SB.PCI0.P0PA.VGA.GETD", 186 - /* L3C */ 187 - "\\_SB.PCI0.PCI1.VGAC.NMAP", 188 - /* Z96F */ 189 - "\\_SB.PCI0.VGA.GETD", 190 - /* A2D */ 191 - "\\ACTD", 192 - /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */ 193 - "\\ADVG", 194 - /* P30 */ 195 - "\\DNXT", 196 - /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */ 197 - "\\INFB", 198 - /* A3F A6F A3N A3L M6N W3N W6A */ 199 - "\\SSTE"}; 200 162 201 163 #define METHOD_ALS_CONTROL "ALSC" /* Z71A Z71V */ 202 164 #define METHOD_ALS_LEVEL "ALSL" /* Z71A Z71V */ ··· 210 246 211 247 int wireless_status; 212 248 bool have_rsts; 213 - int lcd_state; 214 249 215 250 struct rfkill *gps_rfkill; 216 251 ··· 522 559 /* 523 560 * Backlight device 524 561 */ 525 - static int asus_lcd_status(struct asus_laptop *asus) 526 - { 527 - return asus->lcd_state; 528 - } 529 - 530 - static int asus_lcd_set(struct asus_laptop *asus, int value) 531 - { 532 - int lcd = 0; 533 - acpi_status status = 0; 534 - 535 - lcd = !!value; 536 - 537 - if (lcd == asus_lcd_status(asus)) 538 - return 0; 539 - 540 - if (!lcd_switch_handle) 541 - return -ENODEV; 542 - 543 - status = acpi_evaluate_object(lcd_switch_handle, 544 - NULL, NULL, NULL); 545 - 546 - if (ACPI_FAILURE(status)) { 547 - pr_warning("Error switching LCD\n"); 548 - return -ENODEV; 549 - } 550 - 551 - asus->lcd_state = lcd; 552 - return 0; 553 - } 554 - 555 - static void lcd_blank(struct asus_laptop *asus, int blank) 556 - { 557 - struct backlight_device *bd = asus->backlight_device; 558 - 559 - asus->lcd_state = (blank == FB_BLANK_UNBLANK); 560 - 561 - if (bd) { 562 - bd->props.power = blank; 563 - backlight_update_status(bd); 564 - } 565 - } 566 - 567 562 static int asus_read_brightness(struct backlight_device *bd) 568 563 { 569 564 struct asus_laptop *asus = bl_get_data(bd); ··· 549 628 550 629 static int update_bl_status(struct backlight_device *bd) 551 630 { 552 - struct asus_laptop *asus = bl_get_data(bd); 553 - int rv; 554 631 int value = bd->props.brightness; 555 632 556 - rv = asus_set_brightness(bd, value); 557 - if (rv) 558 - return rv; 559 - 560 - value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0; 561 - return asus_lcd_set(asus, value); 633 + return asus_set_brightness(bd, value); 562 634 } 563 635 564 636 static const struct backlight_ops asusbl_ops = { ··· 575 661 struct backlight_properties props; 576 662 577 663 if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) || 578 - acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL) || 579 - !lcd_switch_handle) 664 + acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL)) 580 665 return 0; 581 666 582 667 memset(&props, 0, sizeof(struct backlight_properties)); ··· 884 971 return; 885 972 } 886 973 887 - static int read_display(struct asus_laptop *asus) 888 - { 889 - unsigned long long value = 0; 890 - acpi_status rv = AE_OK; 891 - 892 - /* 893 - * In most of the case, we know how to set the display, but sometime 894 - * we can't read it 895 - */ 896 - if (display_get_handle) { 897 - rv = acpi_evaluate_integer(display_get_handle, NULL, 898 - NULL, &value); 899 - if (ACPI_FAILURE(rv)) 900 - pr_warning("Error reading display status\n"); 901 - } 902 - 903 - value &= 0x0F; /* needed for some models, shouldn't hurt others */ 904 - 905 - return value; 906 - } 907 - 908 - /* 909 - * Now, *this* one could be more user-friendly, but so far, no-one has 910 - * complained. The significance of bits is the same as in store_disp() 911 - */ 912 - static ssize_t show_disp(struct device *dev, 913 - struct device_attribute *attr, char *buf) 914 - { 915 - struct asus_laptop *asus = dev_get_drvdata(dev); 916 - 917 - if (!display_get_handle) 918 - return -ENODEV; 919 - return sprintf(buf, "%d\n", read_display(asus)); 920 - } 921 - 922 974 /* 923 975 * Experimental support for display switching. As of now: 1 should activate 924 976 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI. ··· 1125 1247 struct asus_laptop *asus = acpi_driver_data(device); 1126 1248 u16 count; 1127 1249 1128 - /* 1129 - * We need to tell the backlight device when the backlight power is 1130 - * switched 1131 - */ 1132 - if (event == ATKD_LCD_ON) 1133 - lcd_blank(asus, FB_BLANK_UNBLANK); 1134 - else if (event == ATKD_LCD_OFF) 1135 - lcd_blank(asus, FB_BLANK_POWERDOWN); 1136 - 1137 1250 /* TODO Find a better way to handle events count. */ 1138 1251 count = asus->event_count[event % 128]++; 1139 1252 acpi_bus_generate_proc_event(asus->device, event, count); ··· 1151 1282 show_bluetooth, store_bluetooth); 1152 1283 static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax); 1153 1284 static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan); 1154 - static DEVICE_ATTR(display, S_IRUGO | S_IWUSR, show_disp, store_disp); 1285 + static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp); 1155 1286 static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd); 1156 1287 static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl); 1157 1288 static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw); ··· 1262 1393 } 1263 1394 }; 1264 1395 1265 - static int asus_handle_init(char *name, acpi_handle * handle, 1266 - char **paths, int num_paths) 1267 - { 1268 - int i; 1269 - acpi_status status; 1270 - 1271 - for (i = 0; i < num_paths; i++) { 1272 - status = acpi_get_handle(NULL, paths[i], handle); 1273 - if (ACPI_SUCCESS(status)) 1274 - return 0; 1275 - } 1276 - 1277 - *handle = NULL; 1278 - return -ENODEV; 1279 - } 1280 - 1281 - #define ASUS_HANDLE_INIT(object) \ 1282 - asus_handle_init(#object, &object##_handle, object##_paths, \ 1283 - ARRAY_SIZE(object##_paths)) 1284 - 1285 1396 /* 1286 1397 * This function is used to initialize the context with right values. In this 1287 1398 * method, we can make all the detection we want, and modify the asus_laptop ··· 1347 1498 if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL)) 1348 1499 asus->have_rsts = true; 1349 1500 1350 - /* Scheduled for removal */ 1351 - ASUS_HANDLE_INIT(lcd_switch); 1352 - ASUS_HANDLE_INIT(display_get); 1353 - 1354 1501 kfree(model); 1355 1502 1356 1503 return AE_OK; ··· 1398 1553 asus_als_level(asus, asus->light_level); 1399 1554 } 1400 1555 1401 - asus->lcd_state = 1; /* LCD should be on when the module load */ 1402 1556 return result; 1557 + } 1558 + 1559 + static void __devinit asus_dmi_check(void) 1560 + { 1561 + const char *model; 1562 + 1563 + model = dmi_get_system_info(DMI_PRODUCT_NAME); 1564 + if (!model) 1565 + return; 1566 + 1567 + /* On L1400B WLED control the sound card, don't mess with it ... */ 1568 + if (strncmp(model, "L1400B", 6) == 0) { 1569 + wlan_status = -1; 1570 + } 1403 1571 } 1404 1572 1405 1573 static bool asus_device_present; ··· 1432 1574 strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS); 1433 1575 device->driver_data = asus; 1434 1576 asus->device = device; 1577 + 1578 + asus_dmi_check(); 1435 1579 1436 1580 result = asus_acpi_init(asus); 1437 1581 if (result)
+98
drivers/platform/x86/asus-nb-wmi.c
··· 1 + /* 2 + * Asus Notebooks WMI hotkey driver 3 + * 4 + * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.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 as published by 8 + * the Free Software Foundation; either version 2 of the License, or 9 + * (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 14 + * GNU 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 02111-1307 USA 19 + */ 20 + 21 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22 + 23 + #include <linux/kernel.h> 24 + #include <linux/module.h> 25 + #include <linux/init.h> 26 + #include <linux/input.h> 27 + #include <linux/input/sparse-keymap.h> 28 + 29 + #include "asus-wmi.h" 30 + 31 + #define ASUS_NB_WMI_FILE "asus-nb-wmi" 32 + 33 + MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>"); 34 + MODULE_DESCRIPTION("Asus Notebooks WMI Hotkey Driver"); 35 + MODULE_LICENSE("GPL"); 36 + 37 + #define ASUS_NB_WMI_EVENT_GUID "0B3CBB35-E3C2-45ED-91C2-4C5A6D195D1C" 38 + 39 + MODULE_ALIAS("wmi:"ASUS_NB_WMI_EVENT_GUID); 40 + 41 + static const struct key_entry asus_nb_wmi_keymap[] = { 42 + { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 43 + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 44 + { KE_KEY, 0x32, { KEY_MUTE } }, 45 + { KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */ 46 + { KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */ 47 + { KE_KEY, 0x40, { KEY_PREVIOUSSONG } }, 48 + { KE_KEY, 0x41, { KEY_NEXTSONG } }, 49 + { KE_KEY, 0x43, { KEY_STOPCD } }, 50 + { KE_KEY, 0x45, { KEY_PLAYPAUSE } }, 51 + { KE_KEY, 0x4c, { KEY_MEDIA } }, 52 + { KE_KEY, 0x50, { KEY_EMAIL } }, 53 + { KE_KEY, 0x51, { KEY_WWW } }, 54 + { KE_KEY, 0x55, { KEY_CALC } }, 55 + { KE_KEY, 0x5C, { KEY_F15 } }, /* Power Gear key */ 56 + { KE_KEY, 0x5D, { KEY_WLAN } }, 57 + { KE_KEY, 0x5E, { KEY_WLAN } }, 58 + { KE_KEY, 0x5F, { KEY_WLAN } }, 59 + { KE_KEY, 0x60, { KEY_SWITCHVIDEOMODE } }, 60 + { KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, 61 + { KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, 62 + { KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, 63 + { KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, 64 + { KE_KEY, 0x7E, { KEY_BLUETOOTH } }, 65 + { KE_KEY, 0x7D, { KEY_BLUETOOTH } }, 66 + { KE_KEY, 0x82, { KEY_CAMERA } }, 67 + { KE_KEY, 0x88, { KEY_RFKILL } }, 68 + { KE_KEY, 0x8A, { KEY_PROG1 } }, 69 + { KE_KEY, 0x95, { KEY_MEDIA } }, 70 + { KE_KEY, 0x99, { KEY_PHONE } }, 71 + { KE_KEY, 0xb5, { KEY_CALC } }, 72 + { KE_KEY, 0xc4, { KEY_KBDILLUMUP } }, 73 + { KE_KEY, 0xc5, { KEY_KBDILLUMDOWN } }, 74 + { KE_END, 0}, 75 + }; 76 + 77 + static struct asus_wmi_driver asus_nb_wmi_driver = { 78 + .name = ASUS_NB_WMI_FILE, 79 + .owner = THIS_MODULE, 80 + .event_guid = ASUS_NB_WMI_EVENT_GUID, 81 + .keymap = asus_nb_wmi_keymap, 82 + .input_name = "Asus WMI hotkeys", 83 + .input_phys = ASUS_NB_WMI_FILE "/input0", 84 + }; 85 + 86 + 87 + static int __init asus_nb_wmi_init(void) 88 + { 89 + return asus_wmi_register_driver(&asus_nb_wmi_driver); 90 + } 91 + 92 + static void __exit asus_nb_wmi_exit(void) 93 + { 94 + asus_wmi_unregister_driver(&asus_nb_wmi_driver); 95 + } 96 + 97 + module_init(asus_nb_wmi_init); 98 + module_exit(asus_nb_wmi_exit);
+1656
drivers/platform/x86/asus-wmi.c
··· 1 + /* 2 + * Asus PC WMI hotkey driver 3 + * 4 + * Copyright(C) 2010 Intel Corporation. 5 + * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> 6 + * 7 + * Portions based on wistron_btns.c: 8 + * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 9 + * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> 10 + * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License as published by 14 + * the Free Software Foundation; either version 2 of the License, or 15 + * (at your option) any later version. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + * You should have received a copy of the GNU General Public License 23 + * along with this program; if not, write to the Free Software 24 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 + */ 26 + 27 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 28 + 29 + #include <linux/kernel.h> 30 + #include <linux/module.h> 31 + #include <linux/init.h> 32 + #include <linux/types.h> 33 + #include <linux/slab.h> 34 + #include <linux/input.h> 35 + #include <linux/input/sparse-keymap.h> 36 + #include <linux/fb.h> 37 + #include <linux/backlight.h> 38 + #include <linux/leds.h> 39 + #include <linux/rfkill.h> 40 + #include <linux/pci.h> 41 + #include <linux/pci_hotplug.h> 42 + #include <linux/hwmon.h> 43 + #include <linux/hwmon-sysfs.h> 44 + #include <linux/debugfs.h> 45 + #include <linux/seq_file.h> 46 + #include <linux/platform_device.h> 47 + #include <acpi/acpi_bus.h> 48 + #include <acpi/acpi_drivers.h> 49 + 50 + #include "asus-wmi.h" 51 + 52 + MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>, " 53 + "Yong Wang <yong.y.wang@intel.com>"); 54 + MODULE_DESCRIPTION("Asus Generic WMI Driver"); 55 + MODULE_LICENSE("GPL"); 56 + 57 + #define to_platform_driver(drv) \ 58 + (container_of((drv), struct platform_driver, driver)) 59 + 60 + #define to_asus_wmi_driver(pdrv) \ 61 + (container_of((pdrv), struct asus_wmi_driver, platform_driver)) 62 + 63 + #define ASUS_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" 64 + 65 + #define NOTIFY_BRNUP_MIN 0x11 66 + #define NOTIFY_BRNUP_MAX 0x1f 67 + #define NOTIFY_BRNDOWN_MIN 0x20 68 + #define NOTIFY_BRNDOWN_MAX 0x2e 69 + 70 + /* WMI Methods */ 71 + #define ASUS_WMI_METHODID_SPEC 0x43455053 /* BIOS SPECification */ 72 + #define ASUS_WMI_METHODID_SFBD 0x44424653 /* Set First Boot Device */ 73 + #define ASUS_WMI_METHODID_GLCD 0x44434C47 /* Get LCD status */ 74 + #define ASUS_WMI_METHODID_GPID 0x44495047 /* Get Panel ID?? (Resol) */ 75 + #define ASUS_WMI_METHODID_QMOD 0x444F4D51 /* Quiet MODe */ 76 + #define ASUS_WMI_METHODID_SPLV 0x4C425053 /* Set Panel Light Value */ 77 + #define ASUS_WMI_METHODID_SFUN 0x4E554653 /* FUNCtionalities */ 78 + #define ASUS_WMI_METHODID_SDSP 0x50534453 /* Set DiSPlay output */ 79 + #define ASUS_WMI_METHODID_GDSP 0x50534447 /* Get DiSPlay output */ 80 + #define ASUS_WMI_METHODID_DEVP 0x50564544 /* DEVice Policy */ 81 + #define ASUS_WMI_METHODID_OSVR 0x5256534F /* OS VeRsion */ 82 + #define ASUS_WMI_METHODID_DSTS 0x53544344 /* Device STatuS */ 83 + #define ASUS_WMI_METHODID_DSTS2 0x53545344 /* Device STatuS #2*/ 84 + #define ASUS_WMI_METHODID_BSTS 0x53545342 /* Bios STatuS ? */ 85 + #define ASUS_WMI_METHODID_DEVS 0x53564544 /* DEVice Set */ 86 + #define ASUS_WMI_METHODID_CFVS 0x53564643 /* CPU Frequency Volt Set */ 87 + #define ASUS_WMI_METHODID_KBFT 0x5446424B /* KeyBoard FilTer */ 88 + #define ASUS_WMI_METHODID_INIT 0x54494E49 /* INITialize */ 89 + #define ASUS_WMI_METHODID_HKEY 0x59454B48 /* Hot KEY ?? */ 90 + 91 + #define ASUS_WMI_UNSUPPORTED_METHOD 0xFFFFFFFE 92 + 93 + /* Wireless */ 94 + #define ASUS_WMI_DEVID_HW_SWITCH 0x00010001 95 + #define ASUS_WMI_DEVID_WIRELESS_LED 0x00010002 96 + #define ASUS_WMI_DEVID_WLAN 0x00010011 97 + #define ASUS_WMI_DEVID_BLUETOOTH 0x00010013 98 + #define ASUS_WMI_DEVID_GPS 0x00010015 99 + #define ASUS_WMI_DEVID_WIMAX 0x00010017 100 + #define ASUS_WMI_DEVID_WWAN3G 0x00010019 101 + #define ASUS_WMI_DEVID_UWB 0x00010021 102 + 103 + /* Leds */ 104 + /* 0x000200XX and 0x000400XX */ 105 + 106 + /* Backlight and Brightness */ 107 + #define ASUS_WMI_DEVID_BACKLIGHT 0x00050011 108 + #define ASUS_WMI_DEVID_BRIGHTNESS 0x00050012 109 + #define ASUS_WMI_DEVID_KBD_BACKLIGHT 0x00050021 110 + #define ASUS_WMI_DEVID_LIGHT_SENSOR 0x00050022 /* ?? */ 111 + 112 + /* Misc */ 113 + #define ASUS_WMI_DEVID_CAMERA 0x00060013 114 + 115 + /* Storage */ 116 + #define ASUS_WMI_DEVID_CARDREADER 0x00080013 117 + 118 + /* Input */ 119 + #define ASUS_WMI_DEVID_TOUCHPAD 0x00100011 120 + #define ASUS_WMI_DEVID_TOUCHPAD_LED 0x00100012 121 + 122 + /* Fan, Thermal */ 123 + #define ASUS_WMI_DEVID_THERMAL_CTRL 0x00110011 124 + #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 125 + 126 + /* Power */ 127 + #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012 128 + 129 + /* DSTS masks */ 130 + #define ASUS_WMI_DSTS_STATUS_BIT 0x00000001 131 + #define ASUS_WMI_DSTS_UNKNOWN_BIT 0x00000002 132 + #define ASUS_WMI_DSTS_PRESENCE_BIT 0x00010000 133 + #define ASUS_WMI_DSTS_USER_BIT 0x00020000 134 + #define ASUS_WMI_DSTS_BIOS_BIT 0x00040000 135 + #define ASUS_WMI_DSTS_BRIGHTNESS_MASK 0x000000FF 136 + #define ASUS_WMI_DSTS_MAX_BRIGTH_MASK 0x0000FF00 137 + 138 + struct bios_args { 139 + u32 arg0; 140 + u32 arg1; 141 + } __packed; 142 + 143 + /* 144 + * <platform>/ - debugfs root directory 145 + * dev_id - current dev_id 146 + * ctrl_param - current ctrl_param 147 + * method_id - current method_id 148 + * devs - call DEVS(dev_id, ctrl_param) and print result 149 + * dsts - call DSTS(dev_id) and print result 150 + * call - call method_id(dev_id, ctrl_param) and print result 151 + */ 152 + struct asus_wmi_debug { 153 + struct dentry *root; 154 + u32 method_id; 155 + u32 dev_id; 156 + u32 ctrl_param; 157 + }; 158 + 159 + struct asus_rfkill { 160 + struct asus_wmi *asus; 161 + struct rfkill *rfkill; 162 + u32 dev_id; 163 + }; 164 + 165 + struct asus_wmi { 166 + int dsts_id; 167 + int spec; 168 + int sfun; 169 + 170 + struct input_dev *inputdev; 171 + struct backlight_device *backlight_device; 172 + struct device *hwmon_device; 173 + struct platform_device *platform_device; 174 + 175 + struct led_classdev tpd_led; 176 + int tpd_led_wk; 177 + struct workqueue_struct *led_workqueue; 178 + struct work_struct tpd_led_work; 179 + 180 + struct asus_rfkill wlan; 181 + struct asus_rfkill bluetooth; 182 + struct asus_rfkill wimax; 183 + struct asus_rfkill wwan3g; 184 + 185 + struct hotplug_slot *hotplug_slot; 186 + struct mutex hotplug_lock; 187 + struct mutex wmi_lock; 188 + struct workqueue_struct *hotplug_workqueue; 189 + struct work_struct hotplug_work; 190 + 191 + struct asus_wmi_debug debug; 192 + 193 + struct asus_wmi_driver *driver; 194 + }; 195 + 196 + static int asus_wmi_input_init(struct asus_wmi *asus) 197 + { 198 + int err; 199 + 200 + asus->inputdev = input_allocate_device(); 201 + if (!asus->inputdev) 202 + return -ENOMEM; 203 + 204 + asus->inputdev->name = asus->driver->input_phys; 205 + asus->inputdev->phys = asus->driver->input_name; 206 + asus->inputdev->id.bustype = BUS_HOST; 207 + asus->inputdev->dev.parent = &asus->platform_device->dev; 208 + 209 + err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL); 210 + if (err) 211 + goto err_free_dev; 212 + 213 + err = input_register_device(asus->inputdev); 214 + if (err) 215 + goto err_free_keymap; 216 + 217 + return 0; 218 + 219 + err_free_keymap: 220 + sparse_keymap_free(asus->inputdev); 221 + err_free_dev: 222 + input_free_device(asus->inputdev); 223 + return err; 224 + } 225 + 226 + static void asus_wmi_input_exit(struct asus_wmi *asus) 227 + { 228 + if (asus->inputdev) { 229 + sparse_keymap_free(asus->inputdev); 230 + input_unregister_device(asus->inputdev); 231 + } 232 + 233 + asus->inputdev = NULL; 234 + } 235 + 236 + static int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, 237 + u32 *retval) 238 + { 239 + struct bios_args args = { 240 + .arg0 = arg0, 241 + .arg1 = arg1, 242 + }; 243 + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; 244 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 245 + acpi_status status; 246 + union acpi_object *obj; 247 + u32 tmp; 248 + 249 + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1, method_id, 250 + &input, &output); 251 + 252 + if (ACPI_FAILURE(status)) 253 + goto exit; 254 + 255 + obj = (union acpi_object *)output.pointer; 256 + if (obj && obj->type == ACPI_TYPE_INTEGER) 257 + tmp = (u32) obj->integer.value; 258 + else 259 + tmp = 0; 260 + 261 + if (retval) 262 + *retval = tmp; 263 + 264 + kfree(obj); 265 + 266 + exit: 267 + if (ACPI_FAILURE(status)) 268 + return -EIO; 269 + 270 + if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) 271 + return -ENODEV; 272 + 273 + return 0; 274 + } 275 + 276 + static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval) 277 + { 278 + return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval); 279 + } 280 + 281 + static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param, 282 + u32 *retval) 283 + { 284 + return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id, 285 + ctrl_param, retval); 286 + } 287 + 288 + /* Helper for special devices with magic return codes */ 289 + static int asus_wmi_get_devstate_bits(struct asus_wmi *asus, 290 + u32 dev_id, u32 mask) 291 + { 292 + u32 retval = 0; 293 + int err; 294 + 295 + err = asus_wmi_get_devstate(asus, dev_id, &retval); 296 + 297 + if (err < 0) 298 + return err; 299 + 300 + if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT)) 301 + return -ENODEV; 302 + 303 + if (mask == ASUS_WMI_DSTS_STATUS_BIT) { 304 + if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT) 305 + return -ENODEV; 306 + } 307 + 308 + return retval & mask; 309 + } 310 + 311 + static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id) 312 + { 313 + return asus_wmi_get_devstate_bits(asus, dev_id, 314 + ASUS_WMI_DSTS_STATUS_BIT); 315 + } 316 + 317 + /* 318 + * LEDs 319 + */ 320 + /* 321 + * These functions actually update the LED's, and are called from a 322 + * workqueue. By doing this as separate work rather than when the LED 323 + * subsystem asks, we avoid messing with the Asus ACPI stuff during a 324 + * potentially bad time, such as a timer interrupt. 325 + */ 326 + static void tpd_led_update(struct work_struct *work) 327 + { 328 + int ctrl_param; 329 + struct asus_wmi *asus; 330 + 331 + asus = container_of(work, struct asus_wmi, tpd_led_work); 332 + 333 + ctrl_param = asus->tpd_led_wk; 334 + asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL); 335 + } 336 + 337 + static void tpd_led_set(struct led_classdev *led_cdev, 338 + enum led_brightness value) 339 + { 340 + struct asus_wmi *asus; 341 + 342 + asus = container_of(led_cdev, struct asus_wmi, tpd_led); 343 + 344 + asus->tpd_led_wk = !!value; 345 + queue_work(asus->led_workqueue, &asus->tpd_led_work); 346 + } 347 + 348 + static int read_tpd_led_state(struct asus_wmi *asus) 349 + { 350 + return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED); 351 + } 352 + 353 + static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) 354 + { 355 + struct asus_wmi *asus; 356 + 357 + asus = container_of(led_cdev, struct asus_wmi, tpd_led); 358 + 359 + return read_tpd_led_state(asus); 360 + } 361 + 362 + static int asus_wmi_led_init(struct asus_wmi *asus) 363 + { 364 + int rv; 365 + 366 + if (read_tpd_led_state(asus) < 0) 367 + return 0; 368 + 369 + asus->led_workqueue = create_singlethread_workqueue("led_workqueue"); 370 + if (!asus->led_workqueue) 371 + return -ENOMEM; 372 + INIT_WORK(&asus->tpd_led_work, tpd_led_update); 373 + 374 + asus->tpd_led.name = "asus::touchpad"; 375 + asus->tpd_led.brightness_set = tpd_led_set; 376 + asus->tpd_led.brightness_get = tpd_led_get; 377 + asus->tpd_led.max_brightness = 1; 378 + 379 + rv = led_classdev_register(&asus->platform_device->dev, &asus->tpd_led); 380 + if (rv) { 381 + destroy_workqueue(asus->led_workqueue); 382 + return rv; 383 + } 384 + 385 + return 0; 386 + } 387 + 388 + static void asus_wmi_led_exit(struct asus_wmi *asus) 389 + { 390 + if (asus->tpd_led.dev) 391 + led_classdev_unregister(&asus->tpd_led); 392 + if (asus->led_workqueue) 393 + destroy_workqueue(asus->led_workqueue); 394 + } 395 + 396 + /* 397 + * PCI hotplug (for wlan rfkill) 398 + */ 399 + static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus) 400 + { 401 + int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); 402 + 403 + if (result < 0) 404 + return false; 405 + return !result; 406 + } 407 + 408 + static void asus_rfkill_hotplug(struct asus_wmi *asus) 409 + { 410 + struct pci_dev *dev; 411 + struct pci_bus *bus; 412 + bool blocked; 413 + bool absent; 414 + u32 l; 415 + 416 + mutex_lock(&asus->wmi_lock); 417 + blocked = asus_wlan_rfkill_blocked(asus); 418 + mutex_unlock(&asus->wmi_lock); 419 + 420 + mutex_lock(&asus->hotplug_lock); 421 + 422 + if (asus->wlan.rfkill) 423 + rfkill_set_sw_state(asus->wlan.rfkill, blocked); 424 + 425 + if (asus->hotplug_slot) { 426 + bus = pci_find_bus(0, 1); 427 + if (!bus) { 428 + pr_warning("Unable to find PCI bus 1?\n"); 429 + goto out_unlock; 430 + } 431 + 432 + if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) { 433 + pr_err("Unable to read PCI config space?\n"); 434 + goto out_unlock; 435 + } 436 + absent = (l == 0xffffffff); 437 + 438 + if (blocked != absent) { 439 + pr_warning("BIOS says wireless lan is %s, " 440 + "but the pci device is %s\n", 441 + blocked ? "blocked" : "unblocked", 442 + absent ? "absent" : "present"); 443 + pr_warning("skipped wireless hotplug as probably " 444 + "inappropriate for this model\n"); 445 + goto out_unlock; 446 + } 447 + 448 + if (!blocked) { 449 + dev = pci_get_slot(bus, 0); 450 + if (dev) { 451 + /* Device already present */ 452 + pci_dev_put(dev); 453 + goto out_unlock; 454 + } 455 + dev = pci_scan_single_device(bus, 0); 456 + if (dev) { 457 + pci_bus_assign_resources(bus); 458 + if (pci_bus_add_device(dev)) 459 + pr_err("Unable to hotplug wifi\n"); 460 + } 461 + } else { 462 + dev = pci_get_slot(bus, 0); 463 + if (dev) { 464 + pci_remove_bus_device(dev); 465 + pci_dev_put(dev); 466 + } 467 + } 468 + } 469 + 470 + out_unlock: 471 + mutex_unlock(&asus->hotplug_lock); 472 + } 473 + 474 + static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data) 475 + { 476 + struct asus_wmi *asus = data; 477 + 478 + if (event != ACPI_NOTIFY_BUS_CHECK) 479 + return; 480 + 481 + /* 482 + * We can't call directly asus_rfkill_hotplug because most 483 + * of the time WMBC is still being executed and not reetrant. 484 + * There is currently no way to tell ACPICA that we want this 485 + * method to be serialized, we schedule a asus_rfkill_hotplug 486 + * call later, in a safer context. 487 + */ 488 + queue_work(asus->hotplug_workqueue, &asus->hotplug_work); 489 + } 490 + 491 + static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node) 492 + { 493 + acpi_status status; 494 + acpi_handle handle; 495 + 496 + status = acpi_get_handle(NULL, node, &handle); 497 + 498 + if (ACPI_SUCCESS(status)) { 499 + status = acpi_install_notify_handler(handle, 500 + ACPI_SYSTEM_NOTIFY, 501 + asus_rfkill_notify, asus); 502 + if (ACPI_FAILURE(status)) 503 + pr_warning("Failed to register notify on %s\n", node); 504 + } else 505 + return -ENODEV; 506 + 507 + return 0; 508 + } 509 + 510 + static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node) 511 + { 512 + acpi_status status = AE_OK; 513 + acpi_handle handle; 514 + 515 + status = acpi_get_handle(NULL, node, &handle); 516 + 517 + if (ACPI_SUCCESS(status)) { 518 + status = acpi_remove_notify_handler(handle, 519 + ACPI_SYSTEM_NOTIFY, 520 + asus_rfkill_notify); 521 + if (ACPI_FAILURE(status)) 522 + pr_err("Error removing rfkill notify handler %s\n", 523 + node); 524 + } 525 + } 526 + 527 + static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot, 528 + u8 *value) 529 + { 530 + struct asus_wmi *asus = hotplug_slot->private; 531 + int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); 532 + 533 + if (result < 0) 534 + return result; 535 + 536 + *value = !!result; 537 + return 0; 538 + } 539 + 540 + static void asus_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) 541 + { 542 + kfree(hotplug_slot->info); 543 + kfree(hotplug_slot); 544 + } 545 + 546 + static struct hotplug_slot_ops asus_hotplug_slot_ops = { 547 + .owner = THIS_MODULE, 548 + .get_adapter_status = asus_get_adapter_status, 549 + .get_power_status = asus_get_adapter_status, 550 + }; 551 + 552 + static void asus_hotplug_work(struct work_struct *work) 553 + { 554 + struct asus_wmi *asus; 555 + 556 + asus = container_of(work, struct asus_wmi, hotplug_work); 557 + asus_rfkill_hotplug(asus); 558 + } 559 + 560 + static int asus_setup_pci_hotplug(struct asus_wmi *asus) 561 + { 562 + int ret = -ENOMEM; 563 + struct pci_bus *bus = pci_find_bus(0, 1); 564 + 565 + if (!bus) { 566 + pr_err("Unable to find wifi PCI bus\n"); 567 + return -ENODEV; 568 + } 569 + 570 + asus->hotplug_workqueue = 571 + create_singlethread_workqueue("hotplug_workqueue"); 572 + if (!asus->hotplug_workqueue) 573 + goto error_workqueue; 574 + 575 + INIT_WORK(&asus->hotplug_work, asus_hotplug_work); 576 + 577 + asus->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); 578 + if (!asus->hotplug_slot) 579 + goto error_slot; 580 + 581 + asus->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), 582 + GFP_KERNEL); 583 + if (!asus->hotplug_slot->info) 584 + goto error_info; 585 + 586 + asus->hotplug_slot->private = asus; 587 + asus->hotplug_slot->release = &asus_cleanup_pci_hotplug; 588 + asus->hotplug_slot->ops = &asus_hotplug_slot_ops; 589 + asus_get_adapter_status(asus->hotplug_slot, 590 + &asus->hotplug_slot->info->adapter_status); 591 + 592 + ret = pci_hp_register(asus->hotplug_slot, bus, 0, "asus-wifi"); 593 + if (ret) { 594 + pr_err("Unable to register hotplug slot - %d\n", ret); 595 + goto error_register; 596 + } 597 + 598 + return 0; 599 + 600 + error_register: 601 + kfree(asus->hotplug_slot->info); 602 + error_info: 603 + kfree(asus->hotplug_slot); 604 + asus->hotplug_slot = NULL; 605 + error_slot: 606 + destroy_workqueue(asus->hotplug_workqueue); 607 + error_workqueue: 608 + return ret; 609 + } 610 + 611 + /* 612 + * Rfkill devices 613 + */ 614 + static int asus_rfkill_set(void *data, bool blocked) 615 + { 616 + struct asus_rfkill *priv = data; 617 + u32 ctrl_param = !blocked; 618 + 619 + return asus_wmi_set_devstate(priv->dev_id, ctrl_param, NULL); 620 + } 621 + 622 + static void asus_rfkill_query(struct rfkill *rfkill, void *data) 623 + { 624 + struct asus_rfkill *priv = data; 625 + int result; 626 + 627 + result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id); 628 + 629 + if (result < 0) 630 + return; 631 + 632 + rfkill_set_sw_state(priv->rfkill, !result); 633 + } 634 + 635 + static int asus_rfkill_wlan_set(void *data, bool blocked) 636 + { 637 + struct asus_rfkill *priv = data; 638 + struct asus_wmi *asus = priv->asus; 639 + int ret; 640 + 641 + /* 642 + * This handler is enabled only if hotplug is enabled. 643 + * In this case, the asus_wmi_set_devstate() will 644 + * trigger a wmi notification and we need to wait 645 + * this call to finish before being able to call 646 + * any wmi method 647 + */ 648 + mutex_lock(&asus->wmi_lock); 649 + ret = asus_rfkill_set(data, blocked); 650 + mutex_unlock(&asus->wmi_lock); 651 + return ret; 652 + } 653 + 654 + static const struct rfkill_ops asus_rfkill_wlan_ops = { 655 + .set_block = asus_rfkill_wlan_set, 656 + .query = asus_rfkill_query, 657 + }; 658 + 659 + static const struct rfkill_ops asus_rfkill_ops = { 660 + .set_block = asus_rfkill_set, 661 + .query = asus_rfkill_query, 662 + }; 663 + 664 + static int asus_new_rfkill(struct asus_wmi *asus, 665 + struct asus_rfkill *arfkill, 666 + const char *name, enum rfkill_type type, int dev_id) 667 + { 668 + int result = asus_wmi_get_devstate_simple(asus, dev_id); 669 + struct rfkill **rfkill = &arfkill->rfkill; 670 + 671 + if (result < 0) 672 + return result; 673 + 674 + arfkill->dev_id = dev_id; 675 + arfkill->asus = asus; 676 + 677 + if (dev_id == ASUS_WMI_DEVID_WLAN && asus->driver->hotplug_wireless) 678 + *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, 679 + &asus_rfkill_wlan_ops, arfkill); 680 + else 681 + *rfkill = rfkill_alloc(name, &asus->platform_device->dev, type, 682 + &asus_rfkill_ops, arfkill); 683 + 684 + if (!*rfkill) 685 + return -EINVAL; 686 + 687 + rfkill_init_sw_state(*rfkill, !result); 688 + result = rfkill_register(*rfkill); 689 + if (result) { 690 + rfkill_destroy(*rfkill); 691 + *rfkill = NULL; 692 + return result; 693 + } 694 + return 0; 695 + } 696 + 697 + static void asus_wmi_rfkill_exit(struct asus_wmi *asus) 698 + { 699 + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); 700 + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); 701 + asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); 702 + if (asus->wlan.rfkill) { 703 + rfkill_unregister(asus->wlan.rfkill); 704 + rfkill_destroy(asus->wlan.rfkill); 705 + asus->wlan.rfkill = NULL; 706 + } 707 + /* 708 + * Refresh pci hotplug in case the rfkill state was changed after 709 + * asus_unregister_rfkill_notifier() 710 + */ 711 + asus_rfkill_hotplug(asus); 712 + if (asus->hotplug_slot) 713 + pci_hp_deregister(asus->hotplug_slot); 714 + if (asus->hotplug_workqueue) 715 + destroy_workqueue(asus->hotplug_workqueue); 716 + 717 + if (asus->bluetooth.rfkill) { 718 + rfkill_unregister(asus->bluetooth.rfkill); 719 + rfkill_destroy(asus->bluetooth.rfkill); 720 + asus->bluetooth.rfkill = NULL; 721 + } 722 + if (asus->wimax.rfkill) { 723 + rfkill_unregister(asus->wimax.rfkill); 724 + rfkill_destroy(asus->wimax.rfkill); 725 + asus->wimax.rfkill = NULL; 726 + } 727 + if (asus->wwan3g.rfkill) { 728 + rfkill_unregister(asus->wwan3g.rfkill); 729 + rfkill_destroy(asus->wwan3g.rfkill); 730 + asus->wwan3g.rfkill = NULL; 731 + } 732 + } 733 + 734 + static int asus_wmi_rfkill_init(struct asus_wmi *asus) 735 + { 736 + int result = 0; 737 + 738 + mutex_init(&asus->hotplug_lock); 739 + mutex_init(&asus->wmi_lock); 740 + 741 + result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan", 742 + RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN); 743 + 744 + if (result && result != -ENODEV) 745 + goto exit; 746 + 747 + result = asus_new_rfkill(asus, &asus->bluetooth, 748 + "asus-bluetooth", RFKILL_TYPE_BLUETOOTH, 749 + ASUS_WMI_DEVID_BLUETOOTH); 750 + 751 + if (result && result != -ENODEV) 752 + goto exit; 753 + 754 + result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax", 755 + RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX); 756 + 757 + if (result && result != -ENODEV) 758 + goto exit; 759 + 760 + result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g", 761 + RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G); 762 + 763 + if (result && result != -ENODEV) 764 + goto exit; 765 + 766 + if (!asus->driver->hotplug_wireless) 767 + goto exit; 768 + 769 + result = asus_setup_pci_hotplug(asus); 770 + /* 771 + * If we get -EBUSY then something else is handling the PCI hotplug - 772 + * don't fail in this case 773 + */ 774 + if (result == -EBUSY) 775 + result = 0; 776 + 777 + asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5"); 778 + asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6"); 779 + asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7"); 780 + /* 781 + * Refresh pci hotplug in case the rfkill state was changed during 782 + * setup. 783 + */ 784 + asus_rfkill_hotplug(asus); 785 + 786 + exit: 787 + if (result && result != -ENODEV) 788 + asus_wmi_rfkill_exit(asus); 789 + 790 + if (result == -ENODEV) 791 + result = 0; 792 + 793 + return result; 794 + } 795 + 796 + /* 797 + * Hwmon device 798 + */ 799 + static ssize_t asus_hwmon_pwm1(struct device *dev, 800 + struct device_attribute *attr, 801 + char *buf) 802 + { 803 + struct asus_wmi *asus = dev_get_drvdata(dev); 804 + u32 value; 805 + int err; 806 + 807 + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value); 808 + 809 + if (err < 0) 810 + return err; 811 + 812 + value |= 0xFF; 813 + 814 + if (value == 1) /* Low Speed */ 815 + value = 85; 816 + else if (value == 2) 817 + value = 170; 818 + else if (value == 3) 819 + value = 255; 820 + else if (value != 0) { 821 + pr_err("Unknown fan speed %#x", value); 822 + value = -1; 823 + } 824 + 825 + return sprintf(buf, "%d\n", value); 826 + } 827 + 828 + static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0); 829 + 830 + static ssize_t 831 + show_name(struct device *dev, struct device_attribute *attr, char *buf) 832 + { 833 + return sprintf(buf, "asus\n"); 834 + } 835 + static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); 836 + 837 + static struct attribute *hwmon_attributes[] = { 838 + &sensor_dev_attr_pwm1.dev_attr.attr, 839 + &sensor_dev_attr_name.dev_attr.attr, 840 + NULL 841 + }; 842 + 843 + static mode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj, 844 + struct attribute *attr, int idx) 845 + { 846 + struct device *dev = container_of(kobj, struct device, kobj); 847 + struct platform_device *pdev = to_platform_device(dev->parent); 848 + struct asus_wmi *asus = platform_get_drvdata(pdev); 849 + bool ok = true; 850 + int dev_id = -1; 851 + u32 value = ASUS_WMI_UNSUPPORTED_METHOD; 852 + 853 + if (attr == &sensor_dev_attr_pwm1.dev_attr.attr) 854 + dev_id = ASUS_WMI_DEVID_FAN_CTRL; 855 + 856 + if (dev_id != -1) { 857 + int err = asus_wmi_get_devstate(asus, dev_id, &value); 858 + 859 + if (err < 0) 860 + return err; 861 + } 862 + 863 + if (dev_id == ASUS_WMI_DEVID_FAN_CTRL) { 864 + /* 865 + * We need to find a better way, probably using sfun, 866 + * bits or spec ... 867 + * Currently we disable it if: 868 + * - ASUS_WMI_UNSUPPORTED_METHOD is returned 869 + * - reverved bits are non-zero 870 + * - sfun and presence bit are not set 871 + */ 872 + if (value != ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000 873 + || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT))) 874 + ok = false; 875 + } 876 + 877 + return ok ? attr->mode : 0; 878 + } 879 + 880 + static struct attribute_group hwmon_attribute_group = { 881 + .is_visible = asus_hwmon_sysfs_is_visible, 882 + .attrs = hwmon_attributes 883 + }; 884 + 885 + static void asus_wmi_hwmon_exit(struct asus_wmi *asus) 886 + { 887 + struct device *hwmon; 888 + 889 + hwmon = asus->hwmon_device; 890 + if (!hwmon) 891 + return; 892 + sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group); 893 + hwmon_device_unregister(hwmon); 894 + asus->hwmon_device = NULL; 895 + } 896 + 897 + static int asus_wmi_hwmon_init(struct asus_wmi *asus) 898 + { 899 + struct device *hwmon; 900 + int result; 901 + 902 + hwmon = hwmon_device_register(&asus->platform_device->dev); 903 + if (IS_ERR(hwmon)) { 904 + pr_err("Could not register asus hwmon device\n"); 905 + return PTR_ERR(hwmon); 906 + } 907 + asus->hwmon_device = hwmon; 908 + result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group); 909 + if (result) 910 + asus_wmi_hwmon_exit(asus); 911 + return result; 912 + } 913 + 914 + /* 915 + * Backlight 916 + */ 917 + static int read_backlight_power(struct asus_wmi *asus) 918 + { 919 + int ret = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_BACKLIGHT); 920 + 921 + if (ret < 0) 922 + return ret; 923 + 924 + return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN; 925 + } 926 + 927 + static int read_brightness_max(struct asus_wmi *asus) 928 + { 929 + u32 retval; 930 + int err; 931 + 932 + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); 933 + 934 + if (err < 0) 935 + return err; 936 + 937 + retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK; 938 + retval >>= 8; 939 + 940 + if (!retval) 941 + return -ENODEV; 942 + 943 + return retval; 944 + } 945 + 946 + static int read_brightness(struct backlight_device *bd) 947 + { 948 + struct asus_wmi *asus = bl_get_data(bd); 949 + u32 retval; 950 + int err; 951 + 952 + err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval); 953 + 954 + if (err < 0) 955 + return err; 956 + 957 + return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK; 958 + } 959 + 960 + static int update_bl_status(struct backlight_device *bd) 961 + { 962 + struct asus_wmi *asus = bl_get_data(bd); 963 + u32 ctrl_param; 964 + int power, err; 965 + 966 + ctrl_param = bd->props.brightness; 967 + 968 + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS, 969 + ctrl_param, NULL); 970 + 971 + if (err < 0) 972 + return err; 973 + 974 + power = read_backlight_power(asus); 975 + if (power != -ENODEV && bd->props.power != power) { 976 + ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK); 977 + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 978 + ctrl_param, NULL); 979 + } 980 + return err; 981 + } 982 + 983 + static const struct backlight_ops asus_wmi_bl_ops = { 984 + .get_brightness = read_brightness, 985 + .update_status = update_bl_status, 986 + }; 987 + 988 + static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code) 989 + { 990 + struct backlight_device *bd = asus->backlight_device; 991 + int old = bd->props.brightness; 992 + int new = old; 993 + 994 + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) 995 + new = code - NOTIFY_BRNUP_MIN + 1; 996 + else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) 997 + new = code - NOTIFY_BRNDOWN_MIN; 998 + 999 + bd->props.brightness = new; 1000 + backlight_update_status(bd); 1001 + backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); 1002 + 1003 + return old; 1004 + } 1005 + 1006 + static int asus_wmi_backlight_init(struct asus_wmi *asus) 1007 + { 1008 + struct backlight_device *bd; 1009 + struct backlight_properties props; 1010 + int max; 1011 + int power; 1012 + 1013 + max = read_brightness_max(asus); 1014 + 1015 + if (max == -ENODEV) 1016 + max = 0; 1017 + else if (max < 0) 1018 + return max; 1019 + 1020 + power = read_backlight_power(asus); 1021 + 1022 + if (power == -ENODEV) 1023 + power = FB_BLANK_UNBLANK; 1024 + else if (power < 0) 1025 + return power; 1026 + 1027 + memset(&props, 0, sizeof(struct backlight_properties)); 1028 + props.max_brightness = max; 1029 + bd = backlight_device_register(asus->driver->name, 1030 + &asus->platform_device->dev, asus, 1031 + &asus_wmi_bl_ops, &props); 1032 + if (IS_ERR(bd)) { 1033 + pr_err("Could not register backlight device\n"); 1034 + return PTR_ERR(bd); 1035 + } 1036 + 1037 + asus->backlight_device = bd; 1038 + 1039 + bd->props.brightness = read_brightness(bd); 1040 + bd->props.power = power; 1041 + backlight_update_status(bd); 1042 + 1043 + return 0; 1044 + } 1045 + 1046 + static void asus_wmi_backlight_exit(struct asus_wmi *asus) 1047 + { 1048 + if (asus->backlight_device) 1049 + backlight_device_unregister(asus->backlight_device); 1050 + 1051 + asus->backlight_device = NULL; 1052 + } 1053 + 1054 + static void asus_wmi_notify(u32 value, void *context) 1055 + { 1056 + struct asus_wmi *asus = context; 1057 + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 1058 + union acpi_object *obj; 1059 + acpi_status status; 1060 + int code; 1061 + int orig_code; 1062 + 1063 + status = wmi_get_event_data(value, &response); 1064 + if (status != AE_OK) { 1065 + pr_err("bad event status 0x%x\n", status); 1066 + return; 1067 + } 1068 + 1069 + obj = (union acpi_object *)response.pointer; 1070 + 1071 + if (!obj || obj->type != ACPI_TYPE_INTEGER) 1072 + goto exit; 1073 + 1074 + code = obj->integer.value; 1075 + orig_code = code; 1076 + 1077 + if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) 1078 + code = NOTIFY_BRNUP_MIN; 1079 + else if (code >= NOTIFY_BRNDOWN_MIN && 1080 + code <= NOTIFY_BRNDOWN_MAX) 1081 + code = NOTIFY_BRNDOWN_MIN; 1082 + 1083 + if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { 1084 + if (!acpi_video_backlight_support()) 1085 + asus_wmi_backlight_notify(asus, orig_code); 1086 + } else if (!sparse_keymap_report_event(asus->inputdev, code, 1, true)) 1087 + pr_info("Unknown key %x pressed\n", code); 1088 + 1089 + exit: 1090 + kfree(obj); 1091 + } 1092 + 1093 + /* 1094 + * Sys helpers 1095 + */ 1096 + static int parse_arg(const char *buf, unsigned long count, int *val) 1097 + { 1098 + if (!count) 1099 + return 0; 1100 + if (sscanf(buf, "%i", val) != 1) 1101 + return -EINVAL; 1102 + return count; 1103 + } 1104 + 1105 + static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid, 1106 + const char *buf, size_t count) 1107 + { 1108 + u32 retval; 1109 + int rv, err, value; 1110 + 1111 + value = asus_wmi_get_devstate_simple(asus, devid); 1112 + if (value == -ENODEV) /* Check device presence */ 1113 + return value; 1114 + 1115 + rv = parse_arg(buf, count, &value); 1116 + err = asus_wmi_set_devstate(devid, value, &retval); 1117 + 1118 + if (err < 0) 1119 + return err; 1120 + 1121 + return rv; 1122 + } 1123 + 1124 + static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf) 1125 + { 1126 + int value = asus_wmi_get_devstate_simple(asus, devid); 1127 + 1128 + if (value < 0) 1129 + return value; 1130 + 1131 + return sprintf(buf, "%d\n", value); 1132 + } 1133 + 1134 + #define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ 1135 + static ssize_t show_##_name(struct device *dev, \ 1136 + struct device_attribute *attr, \ 1137 + char *buf) \ 1138 + { \ 1139 + struct asus_wmi *asus = dev_get_drvdata(dev); \ 1140 + \ 1141 + return show_sys_wmi(asus, _cm, buf); \ 1142 + } \ 1143 + static ssize_t store_##_name(struct device *dev, \ 1144 + struct device_attribute *attr, \ 1145 + const char *buf, size_t count) \ 1146 + { \ 1147 + struct asus_wmi *asus = dev_get_drvdata(dev); \ 1148 + \ 1149 + return store_sys_wmi(asus, _cm, buf, count); \ 1150 + } \ 1151 + static struct device_attribute dev_attr_##_name = { \ 1152 + .attr = { \ 1153 + .name = __stringify(_name), \ 1154 + .mode = _mode }, \ 1155 + .show = show_##_name, \ 1156 + .store = store_##_name, \ 1157 + } 1158 + 1159 + ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD); 1160 + ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA); 1161 + ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER); 1162 + 1163 + static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, 1164 + const char *buf, size_t count) 1165 + { 1166 + int value; 1167 + 1168 + if (!count || sscanf(buf, "%i", &value) != 1) 1169 + return -EINVAL; 1170 + if (value < 0 || value > 2) 1171 + return -EINVAL; 1172 + 1173 + return asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL); 1174 + } 1175 + 1176 + static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); 1177 + 1178 + static struct attribute *platform_attributes[] = { 1179 + &dev_attr_cpufv.attr, 1180 + &dev_attr_camera.attr, 1181 + &dev_attr_cardr.attr, 1182 + &dev_attr_touchpad.attr, 1183 + NULL 1184 + }; 1185 + 1186 + static mode_t asus_sysfs_is_visible(struct kobject *kobj, 1187 + struct attribute *attr, int idx) 1188 + { 1189 + struct device *dev = container_of(kobj, struct device, kobj); 1190 + struct platform_device *pdev = to_platform_device(dev); 1191 + struct asus_wmi *asus = platform_get_drvdata(pdev); 1192 + bool ok = true; 1193 + int devid = -1; 1194 + 1195 + if (attr == &dev_attr_camera.attr) 1196 + devid = ASUS_WMI_DEVID_CAMERA; 1197 + else if (attr == &dev_attr_cardr.attr) 1198 + devid = ASUS_WMI_DEVID_CARDREADER; 1199 + else if (attr == &dev_attr_touchpad.attr) 1200 + devid = ASUS_WMI_DEVID_TOUCHPAD; 1201 + 1202 + if (devid != -1) 1203 + ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0); 1204 + 1205 + return ok ? attr->mode : 0; 1206 + } 1207 + 1208 + static struct attribute_group platform_attribute_group = { 1209 + .is_visible = asus_sysfs_is_visible, 1210 + .attrs = platform_attributes 1211 + }; 1212 + 1213 + static void asus_wmi_sysfs_exit(struct platform_device *device) 1214 + { 1215 + sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); 1216 + } 1217 + 1218 + static int asus_wmi_sysfs_init(struct platform_device *device) 1219 + { 1220 + return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); 1221 + } 1222 + 1223 + /* 1224 + * Platform device 1225 + */ 1226 + static int __init asus_wmi_platform_init(struct asus_wmi *asus) 1227 + { 1228 + int rv; 1229 + 1230 + /* INIT enable hotkeys on some models */ 1231 + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv)) 1232 + pr_info("Initialization: %#x", rv); 1233 + 1234 + /* We don't know yet what to do with this version... */ 1235 + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) { 1236 + pr_info("BIOS WMI version: %d.%d", rv >> 8, rv & 0xFF); 1237 + asus->spec = rv; 1238 + } 1239 + 1240 + /* 1241 + * The SFUN method probably allows the original driver to get the list 1242 + * of features supported by a given model. For now, 0x0100 or 0x0800 1243 + * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card. 1244 + * The significance of others is yet to be found. 1245 + */ 1246 + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) { 1247 + pr_info("SFUN value: %#x", rv); 1248 + asus->sfun = rv; 1249 + } 1250 + 1251 + /* 1252 + * Eee PC and Notebooks seems to have different method_id for DSTS, 1253 + * but it may also be related to the BIOS's SPEC. 1254 + * Note, on most Eeepc, there is no way to check if a method exist 1255 + * or note, while on notebooks, they returns 0xFFFFFFFE on failure, 1256 + * but once again, SPEC may probably be used for that kind of things. 1257 + */ 1258 + if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS, 0, 0, NULL)) 1259 + asus->dsts_id = ASUS_WMI_METHODID_DSTS; 1260 + else if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS2, 0, 0, NULL)) 1261 + asus->dsts_id = ASUS_WMI_METHODID_DSTS2; 1262 + 1263 + if (!asus->dsts_id) { 1264 + pr_err("Can't find DSTS"); 1265 + return -ENODEV; 1266 + } 1267 + 1268 + return asus_wmi_sysfs_init(asus->platform_device); 1269 + } 1270 + 1271 + static void asus_wmi_platform_exit(struct asus_wmi *asus) 1272 + { 1273 + asus_wmi_sysfs_exit(asus->platform_device); 1274 + } 1275 + 1276 + /* 1277 + * debugfs 1278 + */ 1279 + struct asus_wmi_debugfs_node { 1280 + struct asus_wmi *asus; 1281 + char *name; 1282 + int (*show) (struct seq_file *m, void *data); 1283 + }; 1284 + 1285 + static int show_dsts(struct seq_file *m, void *data) 1286 + { 1287 + struct asus_wmi *asus = m->private; 1288 + int err; 1289 + u32 retval = -1; 1290 + 1291 + err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval); 1292 + 1293 + if (err < 0) 1294 + return err; 1295 + 1296 + seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval); 1297 + 1298 + return 0; 1299 + } 1300 + 1301 + static int show_devs(struct seq_file *m, void *data) 1302 + { 1303 + struct asus_wmi *asus = m->private; 1304 + int err; 1305 + u32 retval = -1; 1306 + 1307 + err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param, 1308 + &retval); 1309 + 1310 + if (err < 0) 1311 + return err; 1312 + 1313 + seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id, 1314 + asus->debug.ctrl_param, retval); 1315 + 1316 + return 0; 1317 + } 1318 + 1319 + static int show_call(struct seq_file *m, void *data) 1320 + { 1321 + struct asus_wmi *asus = m->private; 1322 + struct bios_args args = { 1323 + .arg0 = asus->debug.dev_id, 1324 + .arg1 = asus->debug.ctrl_param, 1325 + }; 1326 + struct acpi_buffer input = { (acpi_size) sizeof(args), &args }; 1327 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 1328 + union acpi_object *obj; 1329 + acpi_status status; 1330 + 1331 + status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 1332 + 1, asus->debug.method_id, 1333 + &input, &output); 1334 + 1335 + if (ACPI_FAILURE(status)) 1336 + return -EIO; 1337 + 1338 + obj = (union acpi_object *)output.pointer; 1339 + if (obj && obj->type == ACPI_TYPE_INTEGER) 1340 + seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id, 1341 + asus->debug.dev_id, asus->debug.ctrl_param, 1342 + (u32) obj->integer.value); 1343 + else 1344 + seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id, 1345 + asus->debug.dev_id, asus->debug.ctrl_param, 1346 + obj ? obj->type : -1); 1347 + 1348 + kfree(obj); 1349 + 1350 + return 0; 1351 + } 1352 + 1353 + static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = { 1354 + {NULL, "devs", show_devs}, 1355 + {NULL, "dsts", show_dsts}, 1356 + {NULL, "call", show_call}, 1357 + }; 1358 + 1359 + static int asus_wmi_debugfs_open(struct inode *inode, struct file *file) 1360 + { 1361 + struct asus_wmi_debugfs_node *node = inode->i_private; 1362 + 1363 + return single_open(file, node->show, node->asus); 1364 + } 1365 + 1366 + static const struct file_operations asus_wmi_debugfs_io_ops = { 1367 + .owner = THIS_MODULE, 1368 + .open = asus_wmi_debugfs_open, 1369 + .read = seq_read, 1370 + .llseek = seq_lseek, 1371 + .release = single_release, 1372 + }; 1373 + 1374 + static void asus_wmi_debugfs_exit(struct asus_wmi *asus) 1375 + { 1376 + debugfs_remove_recursive(asus->debug.root); 1377 + } 1378 + 1379 + static int asus_wmi_debugfs_init(struct asus_wmi *asus) 1380 + { 1381 + struct dentry *dent; 1382 + int i; 1383 + 1384 + asus->debug.root = debugfs_create_dir(asus->driver->name, NULL); 1385 + if (!asus->debug.root) { 1386 + pr_err("failed to create debugfs directory"); 1387 + goto error_debugfs; 1388 + } 1389 + 1390 + dent = debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, 1391 + asus->debug.root, &asus->debug.method_id); 1392 + if (!dent) 1393 + goto error_debugfs; 1394 + 1395 + dent = debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, 1396 + asus->debug.root, &asus->debug.dev_id); 1397 + if (!dent) 1398 + goto error_debugfs; 1399 + 1400 + dent = debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, 1401 + asus->debug.root, &asus->debug.ctrl_param); 1402 + if (!dent) 1403 + goto error_debugfs; 1404 + 1405 + for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) { 1406 + struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i]; 1407 + 1408 + node->asus = asus; 1409 + dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, 1410 + asus->debug.root, node, 1411 + &asus_wmi_debugfs_io_ops); 1412 + if (!dent) { 1413 + pr_err("failed to create debug file: %s\n", node->name); 1414 + goto error_debugfs; 1415 + } 1416 + } 1417 + 1418 + return 0; 1419 + 1420 + error_debugfs: 1421 + asus_wmi_debugfs_exit(asus); 1422 + return -ENOMEM; 1423 + } 1424 + 1425 + /* 1426 + * WMI Driver 1427 + */ 1428 + static int asus_wmi_add(struct platform_device *pdev) 1429 + { 1430 + struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); 1431 + struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); 1432 + struct asus_wmi *asus; 1433 + acpi_status status; 1434 + int err; 1435 + 1436 + asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL); 1437 + if (!asus) 1438 + return -ENOMEM; 1439 + 1440 + asus->driver = wdrv; 1441 + asus->platform_device = pdev; 1442 + wdrv->platform_device = pdev; 1443 + platform_set_drvdata(asus->platform_device, asus); 1444 + 1445 + if (wdrv->quirks) 1446 + wdrv->quirks(asus->driver); 1447 + 1448 + err = asus_wmi_platform_init(asus); 1449 + if (err) 1450 + goto fail_platform; 1451 + 1452 + err = asus_wmi_input_init(asus); 1453 + if (err) 1454 + goto fail_input; 1455 + 1456 + err = asus_wmi_hwmon_init(asus); 1457 + if (err) 1458 + goto fail_hwmon; 1459 + 1460 + err = asus_wmi_led_init(asus); 1461 + if (err) 1462 + goto fail_leds; 1463 + 1464 + err = asus_wmi_rfkill_init(asus); 1465 + if (err) 1466 + goto fail_rfkill; 1467 + 1468 + if (!acpi_video_backlight_support()) { 1469 + err = asus_wmi_backlight_init(asus); 1470 + if (err && err != -ENODEV) 1471 + goto fail_backlight; 1472 + } else 1473 + pr_info("Backlight controlled by ACPI video driver\n"); 1474 + 1475 + status = wmi_install_notify_handler(asus->driver->event_guid, 1476 + asus_wmi_notify, asus); 1477 + if (ACPI_FAILURE(status)) { 1478 + pr_err("Unable to register notify handler - %d\n", status); 1479 + err = -ENODEV; 1480 + goto fail_wmi_handler; 1481 + } 1482 + 1483 + err = asus_wmi_debugfs_init(asus); 1484 + if (err) 1485 + goto fail_debugfs; 1486 + 1487 + return 0; 1488 + 1489 + fail_debugfs: 1490 + wmi_remove_notify_handler(asus->driver->event_guid); 1491 + fail_wmi_handler: 1492 + asus_wmi_backlight_exit(asus); 1493 + fail_backlight: 1494 + asus_wmi_rfkill_exit(asus); 1495 + fail_rfkill: 1496 + asus_wmi_led_exit(asus); 1497 + fail_leds: 1498 + asus_wmi_hwmon_exit(asus); 1499 + fail_hwmon: 1500 + asus_wmi_input_exit(asus); 1501 + fail_input: 1502 + asus_wmi_platform_exit(asus); 1503 + fail_platform: 1504 + kfree(asus); 1505 + return err; 1506 + } 1507 + 1508 + static int asus_wmi_remove(struct platform_device *device) 1509 + { 1510 + struct asus_wmi *asus; 1511 + 1512 + asus = platform_get_drvdata(device); 1513 + wmi_remove_notify_handler(asus->driver->event_guid); 1514 + asus_wmi_backlight_exit(asus); 1515 + asus_wmi_input_exit(asus); 1516 + asus_wmi_hwmon_exit(asus); 1517 + asus_wmi_led_exit(asus); 1518 + asus_wmi_rfkill_exit(asus); 1519 + asus_wmi_debugfs_exit(asus); 1520 + asus_wmi_platform_exit(asus); 1521 + 1522 + kfree(asus); 1523 + return 0; 1524 + } 1525 + 1526 + /* 1527 + * Platform driver - hibernate/resume callbacks 1528 + */ 1529 + static int asus_hotk_thaw(struct device *device) 1530 + { 1531 + struct asus_wmi *asus = dev_get_drvdata(device); 1532 + 1533 + if (asus->wlan.rfkill) { 1534 + bool wlan; 1535 + 1536 + /* 1537 + * Work around bios bug - acpi _PTS turns off the wireless led 1538 + * during suspend. Normally it restores it on resume, but 1539 + * we should kick it ourselves in case hibernation is aborted. 1540 + */ 1541 + wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN); 1542 + asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL); 1543 + } 1544 + 1545 + return 0; 1546 + } 1547 + 1548 + static int asus_hotk_restore(struct device *device) 1549 + { 1550 + struct asus_wmi *asus = dev_get_drvdata(device); 1551 + int bl; 1552 + 1553 + /* Refresh both wlan rfkill state and pci hotplug */ 1554 + if (asus->wlan.rfkill) 1555 + asus_rfkill_hotplug(asus); 1556 + 1557 + if (asus->bluetooth.rfkill) { 1558 + bl = !asus_wmi_get_devstate_simple(asus, 1559 + ASUS_WMI_DEVID_BLUETOOTH); 1560 + rfkill_set_sw_state(asus->bluetooth.rfkill, bl); 1561 + } 1562 + if (asus->wimax.rfkill) { 1563 + bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX); 1564 + rfkill_set_sw_state(asus->wimax.rfkill, bl); 1565 + } 1566 + if (asus->wwan3g.rfkill) { 1567 + bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G); 1568 + rfkill_set_sw_state(asus->wwan3g.rfkill, bl); 1569 + } 1570 + 1571 + return 0; 1572 + } 1573 + 1574 + static const struct dev_pm_ops asus_pm_ops = { 1575 + .thaw = asus_hotk_thaw, 1576 + .restore = asus_hotk_restore, 1577 + }; 1578 + 1579 + static int asus_wmi_probe(struct platform_device *pdev) 1580 + { 1581 + struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver); 1582 + struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv); 1583 + int ret; 1584 + 1585 + if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { 1586 + pr_warning("Management GUID not found\n"); 1587 + return -ENODEV; 1588 + } 1589 + 1590 + if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) { 1591 + pr_warning("Event GUID not found\n"); 1592 + return -ENODEV; 1593 + } 1594 + 1595 + if (wdrv->probe) { 1596 + ret = wdrv->probe(pdev); 1597 + if (ret) 1598 + return ret; 1599 + } 1600 + 1601 + return asus_wmi_add(pdev); 1602 + } 1603 + 1604 + static bool used; 1605 + 1606 + int asus_wmi_register_driver(struct asus_wmi_driver *driver) 1607 + { 1608 + struct platform_driver *platform_driver; 1609 + struct platform_device *platform_device; 1610 + 1611 + if (used) 1612 + return -EBUSY; 1613 + 1614 + platform_driver = &driver->platform_driver; 1615 + platform_driver->remove = asus_wmi_remove; 1616 + platform_driver->driver.owner = driver->owner; 1617 + platform_driver->driver.name = driver->name; 1618 + platform_driver->driver.pm = &asus_pm_ops; 1619 + 1620 + platform_device = platform_create_bundle(platform_driver, 1621 + asus_wmi_probe, 1622 + NULL, 0, NULL, 0); 1623 + if (IS_ERR(platform_device)) 1624 + return PTR_ERR(platform_device); 1625 + 1626 + used = true; 1627 + return 0; 1628 + } 1629 + EXPORT_SYMBOL_GPL(asus_wmi_register_driver); 1630 + 1631 + void asus_wmi_unregister_driver(struct asus_wmi_driver *driver) 1632 + { 1633 + platform_device_unregister(driver->platform_device); 1634 + platform_driver_unregister(&driver->platform_driver); 1635 + used = false; 1636 + } 1637 + EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver); 1638 + 1639 + static int __init asus_wmi_init(void) 1640 + { 1641 + if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) { 1642 + pr_info("Asus Management GUID not found"); 1643 + return -ENODEV; 1644 + } 1645 + 1646 + pr_info("ASUS WMI generic driver loaded"); 1647 + return 0; 1648 + } 1649 + 1650 + static void __exit asus_wmi_exit(void) 1651 + { 1652 + pr_info("ASUS WMI generic driver unloaded"); 1653 + } 1654 + 1655 + module_init(asus_wmi_init); 1656 + module_exit(asus_wmi_exit);
+58
drivers/platform/x86/asus-wmi.h
··· 1 + /* 2 + * Asus PC WMI hotkey driver 3 + * 4 + * Copyright(C) 2010 Intel Corporation. 5 + * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> 6 + * 7 + * Portions based on wistron_btns.c: 8 + * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> 9 + * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org> 10 + * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru> 11 + * 12 + * This program is free software; you can redistribute it and/or modify 13 + * it under the terms of the GNU General Public License as published by 14 + * the Free Software Foundation; either version 2 of the License, or 15 + * (at your option) any later version. 16 + * 17 + * This program is distributed in the hope that it will be useful, 18 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 + * GNU General Public License for more details. 21 + * 22 + * You should have received a copy of the GNU General Public License 23 + * along with this program; if not, write to the Free Software 24 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 25 + */ 26 + 27 + #ifndef _ASUS_WMI_H_ 28 + #define _ASUS_WMI_H_ 29 + 30 + #include <linux/platform_device.h> 31 + 32 + struct module; 33 + struct key_entry; 34 + struct asus_wmi; 35 + 36 + struct asus_wmi_driver { 37 + bool hotplug_wireless; 38 + 39 + const char *name; 40 + struct module *owner; 41 + 42 + const char *event_guid; 43 + 44 + const struct key_entry *keymap; 45 + const char *input_name; 46 + const char *input_phys; 47 + 48 + int (*probe) (struct platform_device *device); 49 + void (*quirks) (struct asus_wmi_driver *driver); 50 + 51 + struct platform_driver platform_driver; 52 + struct platform_device *platform_device; 53 + }; 54 + 55 + int asus_wmi_register_driver(struct asus_wmi_driver *driver); 56 + void asus_wmi_unregister_driver(struct asus_wmi_driver *driver); 57 + 58 + #endif /* !_ASUS_WMI_H_ */
+4 -4
drivers/platform/x86/compal-laptop.c
··· 201 201 * into 0x4F and read a few bytes from the output, like so: 202 202 * u8 writeData = 0x33; 203 203 * ec_transaction(0x4F, &writeData, 1, buffer, 32, 0); 204 - * That address is labled "fan1 table information" in the service manual. 204 + * That address is labelled "fan1 table information" in the service manual. 205 205 * It should be clear which value in 'buffer' changes). This seems to be 206 206 * related to fan speed. It isn't a proper 'realtime' fan speed value 207 207 * though, because physically stopping or speeding up the fan doesn't ··· 275 275 276 276 ec_write(BACKLIGHT_LEVEL_ADDR, level); 277 277 278 - return 1; 278 + return 0; 279 279 } 280 280 281 281 static int get_backlight_level(void) ··· 763 763 printk(KERN_INFO DRIVER_NAME": Identified laptop model '%s'\n", 764 764 id->ident); 765 765 extra_features = false; 766 - return 0; 766 + return 1; 767 767 } 768 768 769 769 static int dmi_check_cb_extra(const struct dmi_system_id *id) ··· 772 772 "enabling extra features\n", 773 773 id->ident); 774 774 extra_features = true; 775 - return 0; 775 + return 1; 776 776 } 777 777 778 778 static struct dmi_system_id __initdata compal_dmi_table[] = {
+171
drivers/platform/x86/dell-wmi-aio.c
··· 1 + /* 2 + * WMI hotkeys support for Dell All-In-One series 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License as published by 6 + * the Free Software Foundation; either version 2 of the License, or 7 + * (at your option) any later version. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 + */ 18 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 19 + 20 + #include <linux/kernel.h> 21 + #include <linux/module.h> 22 + #include <linux/init.h> 23 + #include <linux/types.h> 24 + #include <linux/input.h> 25 + #include <linux/input/sparse-keymap.h> 26 + #include <acpi/acpi_drivers.h> 27 + #include <linux/acpi.h> 28 + #include <linux/string.h> 29 + 30 + MODULE_DESCRIPTION("WMI hotkeys driver for Dell All-In-One series"); 31 + MODULE_LICENSE("GPL"); 32 + 33 + #define EVENT_GUID1 "284A0E6B-380E-472A-921F-E52786257FB4" 34 + #define EVENT_GUID2 "02314822-307C-4F66-BF0E-48AEAEB26CC8" 35 + 36 + static const char *dell_wmi_aio_guids[] = { 37 + EVENT_GUID1, 38 + EVENT_GUID2, 39 + NULL 40 + }; 41 + 42 + MODULE_ALIAS("wmi:"EVENT_GUID1); 43 + MODULE_ALIAS("wmi:"EVENT_GUID2); 44 + 45 + static const struct key_entry dell_wmi_aio_keymap[] = { 46 + { KE_KEY, 0xc0, { KEY_VOLUMEUP } }, 47 + { KE_KEY, 0xc1, { KEY_VOLUMEDOWN } }, 48 + { KE_END, 0 } 49 + }; 50 + 51 + static struct input_dev *dell_wmi_aio_input_dev; 52 + 53 + static void dell_wmi_aio_notify(u32 value, void *context) 54 + { 55 + struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 56 + union acpi_object *obj; 57 + acpi_status status; 58 + 59 + status = wmi_get_event_data(value, &response); 60 + if (status != AE_OK) { 61 + pr_info("bad event status 0x%x\n", status); 62 + return; 63 + } 64 + 65 + obj = (union acpi_object *)response.pointer; 66 + if (obj) { 67 + unsigned int scancode; 68 + 69 + switch (obj->type) { 70 + case ACPI_TYPE_INTEGER: 71 + /* Most All-In-One correctly return integer scancode */ 72 + scancode = obj->integer.value; 73 + sparse_keymap_report_event(dell_wmi_aio_input_dev, 74 + scancode, 1, true); 75 + break; 76 + case ACPI_TYPE_BUFFER: 77 + /* Broken machines return the scancode in a buffer */ 78 + if (obj->buffer.pointer && obj->buffer.length > 0) { 79 + scancode = obj->buffer.pointer[0]; 80 + sparse_keymap_report_event( 81 + dell_wmi_aio_input_dev, 82 + scancode, 1, true); 83 + } 84 + break; 85 + } 86 + } 87 + kfree(obj); 88 + } 89 + 90 + static int __init dell_wmi_aio_input_setup(void) 91 + { 92 + int err; 93 + 94 + dell_wmi_aio_input_dev = input_allocate_device(); 95 + 96 + if (!dell_wmi_aio_input_dev) 97 + return -ENOMEM; 98 + 99 + dell_wmi_aio_input_dev->name = "Dell AIO WMI hotkeys"; 100 + dell_wmi_aio_input_dev->phys = "wmi/input0"; 101 + dell_wmi_aio_input_dev->id.bustype = BUS_HOST; 102 + 103 + err = sparse_keymap_setup(dell_wmi_aio_input_dev, 104 + dell_wmi_aio_keymap, NULL); 105 + if (err) { 106 + pr_err("Unable to setup input device keymap\n"); 107 + goto err_free_dev; 108 + } 109 + err = input_register_device(dell_wmi_aio_input_dev); 110 + if (err) { 111 + pr_info("Unable to register input device\n"); 112 + goto err_free_keymap; 113 + } 114 + return 0; 115 + 116 + err_free_keymap: 117 + sparse_keymap_free(dell_wmi_aio_input_dev); 118 + err_free_dev: 119 + input_free_device(dell_wmi_aio_input_dev); 120 + return err; 121 + } 122 + 123 + static const char *dell_wmi_aio_find(void) 124 + { 125 + int i; 126 + 127 + for (i = 0; dell_wmi_aio_guids[i] != NULL; i++) 128 + if (wmi_has_guid(dell_wmi_aio_guids[i])) 129 + return dell_wmi_aio_guids[i]; 130 + 131 + return NULL; 132 + } 133 + 134 + static int __init dell_wmi_aio_init(void) 135 + { 136 + int err; 137 + const char *guid; 138 + 139 + guid = dell_wmi_aio_find(); 140 + if (!guid) { 141 + pr_warning("No known WMI GUID found\n"); 142 + return -ENXIO; 143 + } 144 + 145 + err = dell_wmi_aio_input_setup(); 146 + if (err) 147 + return err; 148 + 149 + err = wmi_install_notify_handler(guid, dell_wmi_aio_notify, NULL); 150 + if (err) { 151 + pr_err("Unable to register notify handler - %d\n", err); 152 + sparse_keymap_free(dell_wmi_aio_input_dev); 153 + input_unregister_device(dell_wmi_aio_input_dev); 154 + return err; 155 + } 156 + 157 + return 0; 158 + } 159 + 160 + static void __exit dell_wmi_aio_exit(void) 161 + { 162 + const char *guid; 163 + 164 + guid = dell_wmi_aio_find(); 165 + wmi_remove_notify_handler(guid); 166 + sparse_keymap_free(dell_wmi_aio_input_dev); 167 + input_unregister_device(dell_wmi_aio_input_dev); 168 + } 169 + 170 + module_init(dell_wmi_aio_init); 171 + module_exit(dell_wmi_aio_exit);
+1 -1
drivers/platform/x86/eeepc-laptop.c
··· 1322 1322 { 1323 1323 int dummy; 1324 1324 1325 - /* Some BIOSes do not report cm although it is avaliable. 1325 + /* Some BIOSes do not report cm although it is available. 1326 1326 Check if cm_getv[cm] works and, if yes, assume cm should be set. */ 1327 1327 if (!(eeepc->cm_supported & (1 << cm)) 1328 1328 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
+76 -842
drivers/platform/x86/eeepc-wmi.c
··· 2 2 * Eee PC WMI hotkey driver 3 3 * 4 4 * Copyright(C) 2010 Intel Corporation. 5 - * Copyright(C) 2010 Corentin Chary <corentin.chary@gmail.com> 5 + * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com> 6 6 * 7 7 * Portions based on wistron_btns.c: 8 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> ··· 29 29 #include <linux/kernel.h> 30 30 #include <linux/module.h> 31 31 #include <linux/init.h> 32 - #include <linux/types.h> 33 - #include <linux/slab.h> 34 32 #include <linux/input.h> 35 33 #include <linux/input/sparse-keymap.h> 36 - #include <linux/fb.h> 37 - #include <linux/backlight.h> 38 - #include <linux/leds.h> 39 - #include <linux/rfkill.h> 40 - #include <linux/debugfs.h> 41 - #include <linux/seq_file.h> 42 - #include <linux/platform_device.h> 34 + #include <linux/dmi.h> 43 35 #include <acpi/acpi_bus.h> 44 - #include <acpi/acpi_drivers.h> 36 + 37 + #include "asus-wmi.h" 45 38 46 39 #define EEEPC_WMI_FILE "eeepc-wmi" 47 40 48 - MODULE_AUTHOR("Yong Wang <yong.y.wang@intel.com>"); 41 + MODULE_AUTHOR("Corentin Chary <corentincj@iksaif.net>"); 49 42 MODULE_DESCRIPTION("Eee PC WMI Hotkey Driver"); 50 43 MODULE_LICENSE("GPL"); 51 44 52 45 #define EEEPC_ACPI_HID "ASUS010" /* old _HID used in eeepc-laptop */ 53 46 54 47 #define EEEPC_WMI_EVENT_GUID "ABBC0F72-8EA1-11D1-00A0-C90629100000" 55 - #define EEEPC_WMI_MGMT_GUID "97845ED0-4E6D-11DE-8A39-0800200C9A66" 56 48 57 49 MODULE_ALIAS("wmi:"EEEPC_WMI_EVENT_GUID); 58 - MODULE_ALIAS("wmi:"EEEPC_WMI_MGMT_GUID); 59 50 60 - #define NOTIFY_BRNUP_MIN 0x11 61 - #define NOTIFY_BRNUP_MAX 0x1f 62 - #define NOTIFY_BRNDOWN_MIN 0x20 63 - #define NOTIFY_BRNDOWN_MAX 0x2e 51 + static bool hotplug_wireless; 64 52 65 - #define EEEPC_WMI_METHODID_DEVS 0x53564544 66 - #define EEEPC_WMI_METHODID_DSTS 0x53544344 67 - #define EEEPC_WMI_METHODID_CFVS 0x53564643 68 - 69 - #define EEEPC_WMI_DEVID_BACKLIGHT 0x00050012 70 - #define EEEPC_WMI_DEVID_TPDLED 0x00100011 71 - #define EEEPC_WMI_DEVID_WLAN 0x00010011 72 - #define EEEPC_WMI_DEVID_BLUETOOTH 0x00010013 73 - #define EEEPC_WMI_DEVID_WWAN3G 0x00010019 53 + module_param(hotplug_wireless, bool, 0444); 54 + MODULE_PARM_DESC(hotplug_wireless, 55 + "Enable hotplug for wireless device. " 56 + "If your laptop needs that, please report to " 57 + "acpi4asus-user@lists.sourceforge.net."); 74 58 75 59 static const struct key_entry eeepc_wmi_keymap[] = { 76 60 /* Sleep already handled via generic ACPI code */ 77 - { KE_KEY, 0x5d, { KEY_WLAN } }, 78 - { KE_KEY, 0x32, { KEY_MUTE } }, 79 - { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 80 61 { KE_KEY, 0x30, { KEY_VOLUMEUP } }, 81 - { KE_IGNORE, NOTIFY_BRNDOWN_MIN, { KEY_BRIGHTNESSDOWN } }, 82 - { KE_IGNORE, NOTIFY_BRNUP_MIN, { KEY_BRIGHTNESSUP } }, 62 + { KE_KEY, 0x31, { KEY_VOLUMEDOWN } }, 63 + { KE_KEY, 0x32, { KEY_MUTE } }, 64 + { KE_KEY, 0x5c, { KEY_F15 } }, /* Power Gear key */ 65 + { KE_KEY, 0x5d, { KEY_WLAN } }, 66 + { KE_KEY, 0x6b, { KEY_TOUCHPAD_TOGGLE } }, /* Toggle Touchpad */ 67 + { KE_KEY, 0x82, { KEY_CAMERA } }, 68 + { KE_KEY, 0x83, { KEY_CAMERA_ZOOMIN } }, 69 + { KE_KEY, 0x88, { KEY_WLAN } }, 83 70 { KE_KEY, 0xcc, { KEY_SWITCHVIDEOMODE } }, 84 - { KE_KEY, 0x6b, { KEY_F13 } }, /* Disable Touchpad */ 85 - { KE_KEY, 0xe1, { KEY_F14 } }, 86 - { KE_KEY, 0xe9, { KEY_DISPLAY_OFF } }, 87 - { KE_KEY, 0xe0, { KEY_PROG1 } }, 88 - { KE_KEY, 0x5c, { KEY_F15 } }, 71 + { KE_KEY, 0xe0, { KEY_PROG1 } }, /* Task Manager */ 72 + { KE_KEY, 0xe1, { KEY_F14 } }, /* Change Resolution */ 73 + { KE_KEY, 0xe9, { KEY_BRIGHTNESS_ZERO } }, 74 + { KE_KEY, 0xeb, { KEY_CAMERA_ZOOMOUT } }, 75 + { KE_KEY, 0xec, { KEY_CAMERA_UP } }, 76 + { KE_KEY, 0xed, { KEY_CAMERA_DOWN } }, 77 + { KE_KEY, 0xee, { KEY_CAMERA_LEFT } }, 78 + { KE_KEY, 0xef, { KEY_CAMERA_RIGHT } }, 89 79 { KE_END, 0}, 90 80 }; 91 81 92 - struct bios_args { 93 - u32 dev_id; 94 - u32 ctrl_param; 95 - }; 96 - 97 - /* 98 - * eeepc-wmi/ - debugfs root directory 99 - * dev_id - current dev_id 100 - * ctrl_param - current ctrl_param 101 - * devs - call DEVS(dev_id, ctrl_param) and print result 102 - * dsts - call DSTS(dev_id) and print result 103 - */ 104 - struct eeepc_wmi_debug { 105 - struct dentry *root; 106 - u32 dev_id; 107 - u32 ctrl_param; 108 - }; 109 - 110 - struct eeepc_wmi { 111 - struct input_dev *inputdev; 112 - struct backlight_device *backlight_device; 113 - struct platform_device *platform_device; 114 - 115 - struct led_classdev tpd_led; 116 - int tpd_led_wk; 117 - struct workqueue_struct *led_workqueue; 118 - struct work_struct tpd_led_work; 119 - 120 - struct rfkill *wlan_rfkill; 121 - struct rfkill *bluetooth_rfkill; 122 - struct rfkill *wwan3g_rfkill; 123 - 124 - struct eeepc_wmi_debug debug; 125 - }; 126 - 127 - /* Only used in eeepc_wmi_init() and eeepc_wmi_exit() */ 128 - static struct platform_device *platform_device; 129 - 130 - static int eeepc_wmi_input_init(struct eeepc_wmi *eeepc) 131 - { 132 - int err; 133 - 134 - eeepc->inputdev = input_allocate_device(); 135 - if (!eeepc->inputdev) 136 - return -ENOMEM; 137 - 138 - eeepc->inputdev->name = "Eee PC WMI hotkeys"; 139 - eeepc->inputdev->phys = EEEPC_WMI_FILE "/input0"; 140 - eeepc->inputdev->id.bustype = BUS_HOST; 141 - eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; 142 - 143 - err = sparse_keymap_setup(eeepc->inputdev, eeepc_wmi_keymap, NULL); 144 - if (err) 145 - goto err_free_dev; 146 - 147 - err = input_register_device(eeepc->inputdev); 148 - if (err) 149 - goto err_free_keymap; 150 - 151 - return 0; 152 - 153 - err_free_keymap: 154 - sparse_keymap_free(eeepc->inputdev); 155 - err_free_dev: 156 - input_free_device(eeepc->inputdev); 157 - return err; 158 - } 159 - 160 - static void eeepc_wmi_input_exit(struct eeepc_wmi *eeepc) 161 - { 162 - if (eeepc->inputdev) { 163 - sparse_keymap_free(eeepc->inputdev); 164 - input_unregister_device(eeepc->inputdev); 165 - } 166 - 167 - eeepc->inputdev = NULL; 168 - } 169 - 170 - static acpi_status eeepc_wmi_get_devstate(u32 dev_id, u32 *retval) 171 - { 172 - struct acpi_buffer input = { (acpi_size)sizeof(u32), &dev_id }; 173 - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 174 - union acpi_object *obj; 175 - acpi_status status; 176 - u32 tmp; 177 - 178 - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 179 - 1, EEEPC_WMI_METHODID_DSTS, &input, &output); 180 - 181 - if (ACPI_FAILURE(status)) 182 - return status; 183 - 184 - obj = (union acpi_object *)output.pointer; 185 - if (obj && obj->type == ACPI_TYPE_INTEGER) 186 - tmp = (u32)obj->integer.value; 187 - else 188 - tmp = 0; 189 - 190 - if (retval) 191 - *retval = tmp; 192 - 193 - kfree(obj); 194 - 195 - return status; 196 - 197 - } 198 - 199 - static acpi_status eeepc_wmi_set_devstate(u32 dev_id, u32 ctrl_param, 200 - u32 *retval) 201 - { 202 - struct bios_args args = { 203 - .dev_id = dev_id, 204 - .ctrl_param = ctrl_param, 205 - }; 206 - struct acpi_buffer input = { (acpi_size)sizeof(args), &args }; 207 - acpi_status status; 208 - 209 - if (!retval) { 210 - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, 211 - EEEPC_WMI_METHODID_DEVS, 212 - &input, NULL); 213 - } else { 214 - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 215 - union acpi_object *obj; 216 - u32 tmp; 217 - 218 - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 1, 219 - EEEPC_WMI_METHODID_DEVS, 220 - &input, &output); 221 - 222 - if (ACPI_FAILURE(status)) 223 - return status; 224 - 225 - obj = (union acpi_object *)output.pointer; 226 - if (obj && obj->type == ACPI_TYPE_INTEGER) 227 - tmp = (u32)obj->integer.value; 228 - else 229 - tmp = 0; 230 - 231 - *retval = tmp; 232 - 233 - kfree(obj); 234 - } 235 - 236 - return status; 237 - } 238 - 239 - /* 240 - * LEDs 241 - */ 242 - /* 243 - * These functions actually update the LED's, and are called from a 244 - * workqueue. By doing this as separate work rather than when the LED 245 - * subsystem asks, we avoid messing with the Eeepc ACPI stuff during a 246 - * potentially bad time, such as a timer interrupt. 247 - */ 248 - static void tpd_led_update(struct work_struct *work) 249 - { 250 - int ctrl_param; 251 - struct eeepc_wmi *eeepc; 252 - 253 - eeepc = container_of(work, struct eeepc_wmi, tpd_led_work); 254 - 255 - ctrl_param = eeepc->tpd_led_wk; 256 - eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_TPDLED, ctrl_param, NULL); 257 - } 258 - 259 - static void tpd_led_set(struct led_classdev *led_cdev, 260 - enum led_brightness value) 261 - { 262 - struct eeepc_wmi *eeepc; 263 - 264 - eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); 265 - 266 - eeepc->tpd_led_wk = !!value; 267 - queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); 268 - } 269 - 270 - static int read_tpd_state(struct eeepc_wmi *eeepc) 271 - { 272 - u32 retval; 273 - acpi_status status; 274 - 275 - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_TPDLED, &retval); 276 - 277 - if (ACPI_FAILURE(status)) 278 - return -1; 279 - else if (!retval || retval == 0x00060000) 280 - /* 281 - * if touchpad led is present, DSTS will set some bits, 282 - * usually 0x00020000. 283 - * 0x00060000 means that the device is not supported 284 - */ 285 - return -ENODEV; 286 - else 287 - /* Status is stored in the first bit */ 288 - return retval & 0x1; 289 - } 290 - 291 - static enum led_brightness tpd_led_get(struct led_classdev *led_cdev) 292 - { 293 - struct eeepc_wmi *eeepc; 294 - 295 - eeepc = container_of(led_cdev, struct eeepc_wmi, tpd_led); 296 - 297 - return read_tpd_state(eeepc); 298 - } 299 - 300 - static int eeepc_wmi_led_init(struct eeepc_wmi *eeepc) 301 - { 302 - int rv; 303 - 304 - if (read_tpd_state(eeepc) < 0) 305 - return 0; 306 - 307 - eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); 308 - if (!eeepc->led_workqueue) 309 - return -ENOMEM; 310 - INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); 311 - 312 - eeepc->tpd_led.name = "eeepc::touchpad"; 313 - eeepc->tpd_led.brightness_set = tpd_led_set; 314 - eeepc->tpd_led.brightness_get = tpd_led_get; 315 - eeepc->tpd_led.max_brightness = 1; 316 - 317 - rv = led_classdev_register(&eeepc->platform_device->dev, 318 - &eeepc->tpd_led); 319 - if (rv) { 320 - destroy_workqueue(eeepc->led_workqueue); 321 - return rv; 322 - } 323 - 324 - return 0; 325 - } 326 - 327 - static void eeepc_wmi_led_exit(struct eeepc_wmi *eeepc) 328 - { 329 - if (eeepc->tpd_led.dev) 330 - led_classdev_unregister(&eeepc->tpd_led); 331 - if (eeepc->led_workqueue) 332 - destroy_workqueue(eeepc->led_workqueue); 333 - } 334 - 335 - /* 336 - * Rfkill devices 337 - */ 338 - static int eeepc_rfkill_set(void *data, bool blocked) 339 - { 340 - int dev_id = (unsigned long)data; 341 - u32 ctrl_param = !blocked; 342 - 343 - return eeepc_wmi_set_devstate(dev_id, ctrl_param, NULL); 344 - } 345 - 346 - static void eeepc_rfkill_query(struct rfkill *rfkill, void *data) 347 - { 348 - int dev_id = (unsigned long)data; 349 - u32 retval; 350 - acpi_status status; 351 - 352 - status = eeepc_wmi_get_devstate(dev_id, &retval); 353 - 354 - if (ACPI_FAILURE(status)) 355 - return ; 356 - 357 - rfkill_set_sw_state(rfkill, !(retval & 0x1)); 358 - } 359 - 360 - static const struct rfkill_ops eeepc_rfkill_ops = { 361 - .set_block = eeepc_rfkill_set, 362 - .query = eeepc_rfkill_query, 363 - }; 364 - 365 - static int eeepc_new_rfkill(struct eeepc_wmi *eeepc, 366 - struct rfkill **rfkill, 367 - const char *name, 368 - enum rfkill_type type, int dev_id) 369 - { 370 - int result; 371 - u32 retval; 372 - acpi_status status; 373 - 374 - status = eeepc_wmi_get_devstate(dev_id, &retval); 375 - 376 - if (ACPI_FAILURE(status)) 377 - return -1; 378 - 379 - /* If the device is present, DSTS will always set some bits 380 - * 0x00070000 - 1110000000000000000 - device supported 381 - * 0x00060000 - 1100000000000000000 - not supported 382 - * 0x00020000 - 0100000000000000000 - device supported 383 - * 0x00010000 - 0010000000000000000 - not supported / special mode ? 384 - */ 385 - if (!retval || retval == 0x00060000) 386 - return -ENODEV; 387 - 388 - *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, 389 - &eeepc_rfkill_ops, (void *)(long)dev_id); 390 - 391 - if (!*rfkill) 392 - return -EINVAL; 393 - 394 - rfkill_init_sw_state(*rfkill, !(retval & 0x1)); 395 - result = rfkill_register(*rfkill); 396 - if (result) { 397 - rfkill_destroy(*rfkill); 398 - *rfkill = NULL; 399 - return result; 400 - } 401 - return 0; 402 - } 403 - 404 - static void eeepc_wmi_rfkill_exit(struct eeepc_wmi *eeepc) 405 - { 406 - if (eeepc->wlan_rfkill) { 407 - rfkill_unregister(eeepc->wlan_rfkill); 408 - rfkill_destroy(eeepc->wlan_rfkill); 409 - eeepc->wlan_rfkill = NULL; 410 - } 411 - if (eeepc->bluetooth_rfkill) { 412 - rfkill_unregister(eeepc->bluetooth_rfkill); 413 - rfkill_destroy(eeepc->bluetooth_rfkill); 414 - eeepc->bluetooth_rfkill = NULL; 415 - } 416 - if (eeepc->wwan3g_rfkill) { 417 - rfkill_unregister(eeepc->wwan3g_rfkill); 418 - rfkill_destroy(eeepc->wwan3g_rfkill); 419 - eeepc->wwan3g_rfkill = NULL; 420 - } 421 - } 422 - 423 - static int eeepc_wmi_rfkill_init(struct eeepc_wmi *eeepc) 424 - { 425 - int result = 0; 426 - 427 - result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, 428 - "eeepc-wlan", RFKILL_TYPE_WLAN, 429 - EEEPC_WMI_DEVID_WLAN); 430 - 431 - if (result && result != -ENODEV) 432 - goto exit; 433 - 434 - result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, 435 - "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, 436 - EEEPC_WMI_DEVID_BLUETOOTH); 437 - 438 - if (result && result != -ENODEV) 439 - goto exit; 440 - 441 - result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, 442 - "eeepc-wwan3g", RFKILL_TYPE_WWAN, 443 - EEEPC_WMI_DEVID_WWAN3G); 444 - 445 - if (result && result != -ENODEV) 446 - goto exit; 447 - 448 - exit: 449 - if (result && result != -ENODEV) 450 - eeepc_wmi_rfkill_exit(eeepc); 451 - 452 - if (result == -ENODEV) 453 - result = 0; 454 - 455 - return result; 456 - } 457 - 458 - /* 459 - * Backlight 460 - */ 461 - static int read_brightness(struct backlight_device *bd) 462 - { 463 - u32 retval; 464 - acpi_status status; 465 - 466 - status = eeepc_wmi_get_devstate(EEEPC_WMI_DEVID_BACKLIGHT, &retval); 467 - 468 - if (ACPI_FAILURE(status)) 469 - return -1; 470 - else 471 - return retval & 0xFF; 472 - } 473 - 474 - static int update_bl_status(struct backlight_device *bd) 475 - { 476 - 477 - u32 ctrl_param; 478 - acpi_status status; 479 - 480 - ctrl_param = bd->props.brightness; 481 - 482 - status = eeepc_wmi_set_devstate(EEEPC_WMI_DEVID_BACKLIGHT, 483 - ctrl_param, NULL); 484 - 485 - if (ACPI_FAILURE(status)) 486 - return -1; 487 - else 488 - return 0; 489 - } 490 - 491 - static const struct backlight_ops eeepc_wmi_bl_ops = { 492 - .get_brightness = read_brightness, 493 - .update_status = update_bl_status, 494 - }; 495 - 496 - static int eeepc_wmi_backlight_notify(struct eeepc_wmi *eeepc, int code) 497 - { 498 - struct backlight_device *bd = eeepc->backlight_device; 499 - int old = bd->props.brightness; 500 - int new = old; 501 - 502 - if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) 503 - new = code - NOTIFY_BRNUP_MIN + 1; 504 - else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX) 505 - new = code - NOTIFY_BRNDOWN_MIN; 506 - 507 - bd->props.brightness = new; 508 - backlight_update_status(bd); 509 - backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); 510 - 511 - return old; 512 - } 513 - 514 - static int eeepc_wmi_backlight_init(struct eeepc_wmi *eeepc) 515 - { 516 - struct backlight_device *bd; 517 - struct backlight_properties props; 518 - 519 - memset(&props, 0, sizeof(struct backlight_properties)); 520 - props.max_brightness = 15; 521 - bd = backlight_device_register(EEEPC_WMI_FILE, 522 - &eeepc->platform_device->dev, eeepc, 523 - &eeepc_wmi_bl_ops, &props); 524 - if (IS_ERR(bd)) { 525 - pr_err("Could not register backlight device\n"); 526 - return PTR_ERR(bd); 527 - } 528 - 529 - eeepc->backlight_device = bd; 530 - 531 - bd->props.brightness = read_brightness(bd); 532 - bd->props.power = FB_BLANK_UNBLANK; 533 - backlight_update_status(bd); 534 - 535 - return 0; 536 - } 537 - 538 - static void eeepc_wmi_backlight_exit(struct eeepc_wmi *eeepc) 539 - { 540 - if (eeepc->backlight_device) 541 - backlight_device_unregister(eeepc->backlight_device); 542 - 543 - eeepc->backlight_device = NULL; 544 - } 545 - 546 - static void eeepc_wmi_notify(u32 value, void *context) 547 - { 548 - struct eeepc_wmi *eeepc = context; 549 - struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; 550 - union acpi_object *obj; 551 - acpi_status status; 552 - int code; 553 - int orig_code; 554 - 555 - status = wmi_get_event_data(value, &response); 556 - if (status != AE_OK) { 557 - pr_err("bad event status 0x%x\n", status); 558 - return; 559 - } 560 - 561 - obj = (union acpi_object *)response.pointer; 562 - 563 - if (obj && obj->type == ACPI_TYPE_INTEGER) { 564 - code = obj->integer.value; 565 - orig_code = code; 566 - 567 - if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX) 568 - code = NOTIFY_BRNUP_MIN; 569 - else if (code >= NOTIFY_BRNDOWN_MIN && 570 - code <= NOTIFY_BRNDOWN_MAX) 571 - code = NOTIFY_BRNDOWN_MIN; 572 - 573 - if (code == NOTIFY_BRNUP_MIN || code == NOTIFY_BRNDOWN_MIN) { 574 - if (!acpi_video_backlight_support()) 575 - eeepc_wmi_backlight_notify(eeepc, orig_code); 576 - } 577 - 578 - if (!sparse_keymap_report_event(eeepc->inputdev, 579 - code, 1, true)) 580 - pr_info("Unknown key %x pressed\n", code); 581 - } 582 - 583 - kfree(obj); 584 - } 585 - 586 - static ssize_t store_cpufv(struct device *dev, struct device_attribute *attr, 587 - const char *buf, size_t count) 588 - { 589 - int value; 590 - struct acpi_buffer input = { (acpi_size)sizeof(value), &value }; 591 - acpi_status status; 592 - 593 - if (!count || sscanf(buf, "%i", &value) != 1) 594 - return -EINVAL; 595 - if (value < 0 || value > 2) 596 - return -EINVAL; 597 - 598 - status = wmi_evaluate_method(EEEPC_WMI_MGMT_GUID, 599 - 1, EEEPC_WMI_METHODID_CFVS, &input, NULL); 600 - 601 - if (ACPI_FAILURE(status)) 602 - return -EIO; 603 - else 604 - return count; 605 - } 606 - 607 - static DEVICE_ATTR(cpufv, S_IRUGO | S_IWUSR, NULL, store_cpufv); 608 - 609 - static struct attribute *platform_attributes[] = { 610 - &dev_attr_cpufv.attr, 611 - NULL 612 - }; 613 - 614 - static struct attribute_group platform_attribute_group = { 615 - .attrs = platform_attributes 616 - }; 617 - 618 - static void eeepc_wmi_sysfs_exit(struct platform_device *device) 619 - { 620 - sysfs_remove_group(&device->dev.kobj, &platform_attribute_group); 621 - } 622 - 623 - static int eeepc_wmi_sysfs_init(struct platform_device *device) 624 - { 625 - return sysfs_create_group(&device->dev.kobj, &platform_attribute_group); 626 - } 627 - 628 - /* 629 - * Platform device 630 - */ 631 - static int __init eeepc_wmi_platform_init(struct eeepc_wmi *eeepc) 632 - { 633 - int err; 634 - 635 - eeepc->platform_device = platform_device_alloc(EEEPC_WMI_FILE, -1); 636 - if (!eeepc->platform_device) 637 - return -ENOMEM; 638 - platform_set_drvdata(eeepc->platform_device, eeepc); 639 - 640 - err = platform_device_add(eeepc->platform_device); 641 - if (err) 642 - goto fail_platform_device; 643 - 644 - err = eeepc_wmi_sysfs_init(eeepc->platform_device); 645 - if (err) 646 - goto fail_sysfs; 647 - return 0; 648 - 649 - fail_sysfs: 650 - platform_device_del(eeepc->platform_device); 651 - fail_platform_device: 652 - platform_device_put(eeepc->platform_device); 653 - return err; 654 - } 655 - 656 - static void eeepc_wmi_platform_exit(struct eeepc_wmi *eeepc) 657 - { 658 - eeepc_wmi_sysfs_exit(eeepc->platform_device); 659 - platform_device_unregister(eeepc->platform_device); 660 - } 661 - 662 - /* 663 - * debugfs 664 - */ 665 - struct eeepc_wmi_debugfs_node { 666 - struct eeepc_wmi *eeepc; 667 - char *name; 668 - int (*show)(struct seq_file *m, void *data); 669 - }; 670 - 671 - static int show_dsts(struct seq_file *m, void *data) 672 - { 673 - struct eeepc_wmi *eeepc = m->private; 674 - acpi_status status; 675 - u32 retval = -1; 676 - 677 - status = eeepc_wmi_get_devstate(eeepc->debug.dev_id, &retval); 678 - 679 - if (ACPI_FAILURE(status)) 680 - return -EIO; 681 - 682 - seq_printf(m, "DSTS(%x) = %x\n", eeepc->debug.dev_id, retval); 683 - 684 - return 0; 685 - } 686 - 687 - static int show_devs(struct seq_file *m, void *data) 688 - { 689 - struct eeepc_wmi *eeepc = m->private; 690 - acpi_status status; 691 - u32 retval = -1; 692 - 693 - status = eeepc_wmi_set_devstate(eeepc->debug.dev_id, 694 - eeepc->debug.ctrl_param, &retval); 695 - if (ACPI_FAILURE(status)) 696 - return -EIO; 697 - 698 - seq_printf(m, "DEVS(%x, %x) = %x\n", eeepc->debug.dev_id, 699 - eeepc->debug.ctrl_param, retval); 700 - 701 - return 0; 702 - } 703 - 704 - static struct eeepc_wmi_debugfs_node eeepc_wmi_debug_files[] = { 705 - { NULL, "devs", show_devs }, 706 - { NULL, "dsts", show_dsts }, 707 - }; 708 - 709 - static int eeepc_wmi_debugfs_open(struct inode *inode, struct file *file) 710 - { 711 - struct eeepc_wmi_debugfs_node *node = inode->i_private; 712 - 713 - return single_open(file, node->show, node->eeepc); 714 - } 715 - 716 - static const struct file_operations eeepc_wmi_debugfs_io_ops = { 717 - .owner = THIS_MODULE, 718 - .open = eeepc_wmi_debugfs_open, 719 - .read = seq_read, 720 - .llseek = seq_lseek, 721 - .release = single_release, 722 - }; 723 - 724 - static void eeepc_wmi_debugfs_exit(struct eeepc_wmi *eeepc) 725 - { 726 - debugfs_remove_recursive(eeepc->debug.root); 727 - } 728 - 729 - static int eeepc_wmi_debugfs_init(struct eeepc_wmi *eeepc) 730 - { 731 - struct dentry *dent; 732 - int i; 733 - 734 - eeepc->debug.root = debugfs_create_dir(EEEPC_WMI_FILE, NULL); 735 - if (!eeepc->debug.root) { 736 - pr_err("failed to create debugfs directory"); 737 - goto error_debugfs; 738 - } 739 - 740 - dent = debugfs_create_x32("dev_id", S_IRUGO|S_IWUSR, 741 - eeepc->debug.root, &eeepc->debug.dev_id); 742 - if (!dent) 743 - goto error_debugfs; 744 - 745 - dent = debugfs_create_x32("ctrl_param", S_IRUGO|S_IWUSR, 746 - eeepc->debug.root, &eeepc->debug.ctrl_param); 747 - if (!dent) 748 - goto error_debugfs; 749 - 750 - for (i = 0; i < ARRAY_SIZE(eeepc_wmi_debug_files); i++) { 751 - struct eeepc_wmi_debugfs_node *node = &eeepc_wmi_debug_files[i]; 752 - 753 - node->eeepc = eeepc; 754 - dent = debugfs_create_file(node->name, S_IFREG | S_IRUGO, 755 - eeepc->debug.root, node, 756 - &eeepc_wmi_debugfs_io_ops); 757 - if (!dent) { 758 - pr_err("failed to create debug file: %s\n", node->name); 759 - goto error_debugfs; 760 - } 761 - } 762 - 763 - return 0; 764 - 765 - error_debugfs: 766 - eeepc_wmi_debugfs_exit(eeepc); 767 - return -ENOMEM; 768 - } 769 - 770 - /* 771 - * WMI Driver 772 - */ 773 - static struct platform_device * __init eeepc_wmi_add(void) 774 - { 775 - struct eeepc_wmi *eeepc; 776 - acpi_status status; 777 - int err; 778 - 779 - eeepc = kzalloc(sizeof(struct eeepc_wmi), GFP_KERNEL); 780 - if (!eeepc) 781 - return ERR_PTR(-ENOMEM); 782 - 783 - /* 784 - * Register the platform device first. It is used as a parent for the 785 - * sub-devices below. 786 - */ 787 - err = eeepc_wmi_platform_init(eeepc); 788 - if (err) 789 - goto fail_platform; 790 - 791 - err = eeepc_wmi_input_init(eeepc); 792 - if (err) 793 - goto fail_input; 794 - 795 - err = eeepc_wmi_led_init(eeepc); 796 - if (err) 797 - goto fail_leds; 798 - 799 - err = eeepc_wmi_rfkill_init(eeepc); 800 - if (err) 801 - goto fail_rfkill; 802 - 803 - if (!acpi_video_backlight_support()) { 804 - err = eeepc_wmi_backlight_init(eeepc); 805 - if (err) 806 - goto fail_backlight; 807 - } else 808 - pr_info("Backlight controlled by ACPI video driver\n"); 809 - 810 - status = wmi_install_notify_handler(EEEPC_WMI_EVENT_GUID, 811 - eeepc_wmi_notify, eeepc); 812 - if (ACPI_FAILURE(status)) { 813 - pr_err("Unable to register notify handler - %d\n", 814 - status); 815 - err = -ENODEV; 816 - goto fail_wmi_handler; 817 - } 818 - 819 - err = eeepc_wmi_debugfs_init(eeepc); 820 - if (err) 821 - goto fail_debugfs; 822 - 823 - return eeepc->platform_device; 824 - 825 - fail_debugfs: 826 - wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); 827 - fail_wmi_handler: 828 - eeepc_wmi_backlight_exit(eeepc); 829 - fail_backlight: 830 - eeepc_wmi_rfkill_exit(eeepc); 831 - fail_rfkill: 832 - eeepc_wmi_led_exit(eeepc); 833 - fail_leds: 834 - eeepc_wmi_input_exit(eeepc); 835 - fail_input: 836 - eeepc_wmi_platform_exit(eeepc); 837 - fail_platform: 838 - kfree(eeepc); 839 - return ERR_PTR(err); 840 - } 841 - 842 - static int eeepc_wmi_remove(struct platform_device *device) 843 - { 844 - struct eeepc_wmi *eeepc; 845 - 846 - eeepc = platform_get_drvdata(device); 847 - wmi_remove_notify_handler(EEEPC_WMI_EVENT_GUID); 848 - eeepc_wmi_backlight_exit(eeepc); 849 - eeepc_wmi_input_exit(eeepc); 850 - eeepc_wmi_led_exit(eeepc); 851 - eeepc_wmi_rfkill_exit(eeepc); 852 - eeepc_wmi_debugfs_exit(eeepc); 853 - eeepc_wmi_platform_exit(eeepc); 854 - 855 - kfree(eeepc); 856 - return 0; 857 - } 858 - 859 - static struct platform_driver platform_driver = { 860 - .driver = { 861 - .name = EEEPC_WMI_FILE, 862 - .owner = THIS_MODULE, 863 - }, 864 - }; 865 - 866 - static acpi_status __init eeepc_wmi_parse_device(acpi_handle handle, u32 level, 82 + static acpi_status eeepc_wmi_parse_device(acpi_handle handle, u32 level, 867 83 void *context, void **retval) 868 84 { 869 85 pr_warning("Found legacy ATKD device (%s)", EEEPC_ACPI_HID); ··· 87 871 return AE_CTRL_TERMINATE; 88 872 } 89 873 90 - static int __init eeepc_wmi_check_atkd(void) 874 + static int eeepc_wmi_check_atkd(void) 91 875 { 92 876 acpi_status status; 93 877 bool found = false; ··· 100 884 return -1; 101 885 } 102 886 103 - static int __init eeepc_wmi_init(void) 887 + static int eeepc_wmi_probe(struct platform_device *pdev) 104 888 { 105 - int err; 106 - 107 - if (!wmi_has_guid(EEEPC_WMI_EVENT_GUID) || 108 - !wmi_has_guid(EEEPC_WMI_MGMT_GUID)) { 109 - pr_warning("No known WMI GUID found\n"); 110 - return -ENODEV; 111 - } 112 - 113 889 if (eeepc_wmi_check_atkd()) { 114 890 pr_warning("WMI device present, but legacy ATKD device is also " 115 891 "present and enabled."); ··· 109 901 "acpi_osi=\"!Windows 2009\""); 110 902 pr_warning("Can't load eeepc-wmi, use default acpi_osi " 111 903 "(preferred) or eeepc-laptop"); 112 - return -ENODEV; 904 + return -EBUSY; 113 905 } 114 - 115 - platform_device = eeepc_wmi_add(); 116 - if (IS_ERR(platform_device)) { 117 - err = PTR_ERR(platform_device); 118 - goto fail_eeepc_wmi; 119 - } 120 - 121 - err = platform_driver_register(&platform_driver); 122 - if (err) { 123 - pr_warning("Unable to register platform driver\n"); 124 - goto fail_platform_driver; 125 - } 126 - 127 906 return 0; 907 + } 128 908 129 - fail_platform_driver: 130 - eeepc_wmi_remove(platform_device); 131 - fail_eeepc_wmi: 132 - return err; 909 + static void eeepc_dmi_check(struct asus_wmi_driver *driver) 910 + { 911 + const char *model; 912 + 913 + model = dmi_get_system_info(DMI_PRODUCT_NAME); 914 + if (!model) 915 + return; 916 + 917 + /* 918 + * Whitelist for wlan hotplug 919 + * 920 + * Asus 1000H needs the current hotplug code to handle 921 + * Fn+F2 correctly. We may add other Asus here later, but 922 + * it seems that most of the laptops supported by asus-wmi 923 + * don't need to be on this list 924 + */ 925 + if (strcmp(model, "1000H") == 0) { 926 + driver->hotplug_wireless = true; 927 + pr_info("wlan hotplug enabled\n"); 928 + } 929 + } 930 + 931 + static void eeepc_wmi_quirks(struct asus_wmi_driver *driver) 932 + { 933 + driver->hotplug_wireless = hotplug_wireless; 934 + eeepc_dmi_check(driver); 935 + } 936 + 937 + static struct asus_wmi_driver asus_wmi_driver = { 938 + .name = EEEPC_WMI_FILE, 939 + .owner = THIS_MODULE, 940 + .event_guid = EEEPC_WMI_EVENT_GUID, 941 + .keymap = eeepc_wmi_keymap, 942 + .input_name = "Eee PC WMI hotkeys", 943 + .input_phys = EEEPC_WMI_FILE "/input0", 944 + .probe = eeepc_wmi_probe, 945 + .quirks = eeepc_wmi_quirks, 946 + }; 947 + 948 + 949 + static int __init eeepc_wmi_init(void) 950 + { 951 + return asus_wmi_register_driver(&asus_wmi_driver); 133 952 } 134 953 135 954 static void __exit eeepc_wmi_exit(void) 136 955 { 137 - eeepc_wmi_remove(platform_device); 138 - platform_driver_unregister(&platform_driver); 956 + asus_wmi_unregister_driver(&asus_wmi_driver); 139 957 } 140 958 141 959 module_init(eeepc_wmi_init);
+273 -39
drivers/platform/x86/hp-wmi.c
··· 2 2 * HP WMI hotkeys 3 3 * 4 4 * Copyright (C) 2008 Red Hat <mjg@redhat.com> 5 + * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi> 5 6 * 6 7 * Portions based on wistron_btns.c: 7 8 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz> ··· 52 51 #define HPWMI_HARDWARE_QUERY 0x4 53 52 #define HPWMI_WIRELESS_QUERY 0x5 54 53 #define HPWMI_HOTKEY_QUERY 0xc 54 + #define HPWMI_WIRELESS2_QUERY 0x1b 55 55 56 56 #define PREFIX "HP WMI: " 57 57 #define UNIMP "Unimplemented " ··· 88 86 struct bios_return { 89 87 u32 sigpass; 90 88 u32 return_code; 91 - u32 value; 89 + }; 90 + 91 + enum hp_return_value { 92 + HPWMI_RET_WRONG_SIGNATURE = 0x02, 93 + HPWMI_RET_UNKNOWN_COMMAND = 0x03, 94 + HPWMI_RET_UNKNOWN_CMDTYPE = 0x04, 95 + HPWMI_RET_INVALID_PARAMETERS = 0x05, 96 + }; 97 + 98 + enum hp_wireless2_bits { 99 + HPWMI_POWER_STATE = 0x01, 100 + HPWMI_POWER_SOFT = 0x02, 101 + HPWMI_POWER_BIOS = 0x04, 102 + HPWMI_POWER_HARD = 0x08, 103 + }; 104 + 105 + #define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \ 106 + != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) 107 + #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT) 108 + 109 + struct bios_rfkill2_device_state { 110 + u8 radio_type; 111 + u8 bus_type; 112 + u16 vendor_id; 113 + u16 product_id; 114 + u16 subsys_vendor_id; 115 + u16 subsys_product_id; 116 + u8 rfkill_id; 117 + u8 power; 118 + u8 unknown[4]; 119 + }; 120 + 121 + /* 7 devices fit into the 128 byte buffer */ 122 + #define HPWMI_MAX_RFKILL2_DEVICES 7 123 + 124 + struct bios_rfkill2_state { 125 + u8 unknown[7]; 126 + u8 count; 127 + u8 pad[8]; 128 + struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES]; 92 129 }; 93 130 94 131 static const struct key_entry hp_wmi_keymap[] = { ··· 148 107 static struct rfkill *wifi_rfkill; 149 108 static struct rfkill *bluetooth_rfkill; 150 109 static struct rfkill *wwan_rfkill; 110 + 111 + struct rfkill2_device { 112 + u8 id; 113 + int num; 114 + struct rfkill *rfkill; 115 + }; 116 + 117 + static int rfkill2_count; 118 + static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES]; 151 119 152 120 static const struct dev_pm_ops hp_wmi_pm_ops = { 153 121 .resume = hp_wmi_resume_handler, ··· 179 129 * query: The commandtype -> What should be queried 180 130 * write: The command -> 0 read, 1 write, 3 ODM specific 181 131 * buffer: Buffer used as input and/or output 182 - * buffersize: Size of buffer 132 + * insize: Size of input buffer 133 + * outsize: Size of output buffer 183 134 * 184 135 * returns zero on success 185 136 * an HP WMI query specific error code (which is positive) ··· 191 140 * size. E.g. Battery info query (0x7) is defined to have 1 byte input 192 141 * and 128 byte output. The caller would do: 193 142 * buffer = kzalloc(128, GFP_KERNEL); 194 - * ret = hp_wmi_perform_query(0x7, 0, buffer, 128) 143 + * ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128) 195 144 */ 196 - static int hp_wmi_perform_query(int query, int write, u32 *buffer, 197 - int buffersize) 145 + static int hp_wmi_perform_query(int query, int write, void *buffer, 146 + int insize, int outsize) 198 147 { 199 - struct bios_return bios_return; 200 - acpi_status status; 148 + struct bios_return *bios_return; 149 + int actual_outsize; 201 150 union acpi_object *obj; 202 151 struct bios_args args = { 203 152 .signature = 0x55434553, 204 153 .command = write ? 0x2 : 0x1, 205 154 .commandtype = query, 206 - .datasize = buffersize, 207 - .data = *buffer, 155 + .datasize = insize, 156 + .data = 0, 208 157 }; 209 158 struct acpi_buffer input = { sizeof(struct bios_args), &args }; 210 159 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 211 160 212 - status = wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 161 + if (WARN_ON(insize > sizeof(args.data))) 162 + return -EINVAL; 163 + memcpy(&args.data, buffer, insize); 164 + 165 + wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output); 213 166 214 167 obj = output.pointer; 215 168 ··· 224 169 return -EINVAL; 225 170 } 226 171 227 - bios_return = *((struct bios_return *)obj->buffer.pointer); 172 + bios_return = (struct bios_return *)obj->buffer.pointer; 228 173 229 - memcpy(buffer, &bios_return.value, sizeof(bios_return.value)); 174 + if (bios_return->return_code) { 175 + if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE) 176 + printk(KERN_WARNING PREFIX "query 0x%x returned " 177 + "error 0x%x\n", 178 + query, bios_return->return_code); 179 + kfree(obj); 180 + return bios_return->return_code; 181 + } 230 182 183 + if (!outsize) { 184 + /* ignore output data */ 185 + kfree(obj); 186 + return 0; 187 + } 188 + 189 + actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return))); 190 + memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize); 191 + memset(buffer + actual_outsize, 0, outsize - actual_outsize); 231 192 kfree(obj); 232 193 return 0; 233 194 } ··· 252 181 { 253 182 int state = 0; 254 183 int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state, 255 - sizeof(state)); 184 + sizeof(state), sizeof(state)); 256 185 if (ret) 257 186 return -EINVAL; 258 187 return state; ··· 262 191 { 263 192 int state = 0; 264 193 int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state, 265 - sizeof(state)); 194 + sizeof(state), sizeof(state)); 266 195 if (ret) 267 196 return -EINVAL; 268 197 return state; ··· 272 201 { 273 202 int state = 0; 274 203 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state, 275 - sizeof(state)); 204 + sizeof(state), sizeof(state)); 276 205 if (ret) 277 206 return -EINVAL; 278 207 return state; ··· 282 211 { 283 212 int state = 0; 284 213 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 285 - sizeof(state)); 214 + sizeof(state), sizeof(state)); 286 215 287 216 if (ret) 288 217 return -EINVAL; ··· 294 223 { 295 224 int state = 0; 296 225 int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state, 297 - sizeof(state)); 226 + sizeof(state), sizeof(state)); 298 227 if (ret) 299 228 return ret; 300 229 ··· 308 237 int ret; 309 238 310 239 ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, 311 - &query, sizeof(query)); 240 + &query, sizeof(query), 0); 312 241 if (ret) 313 242 return -EINVAL; 314 243 return 0; ··· 323 252 int wireless = 0; 324 253 int mask; 325 254 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 326 - &wireless, sizeof(wireless)); 255 + &wireless, sizeof(wireless), 256 + sizeof(wireless)); 327 257 /* TBD: Pass error */ 328 258 329 259 mask = 0x200 << (r * 8); ··· 340 268 int wireless = 0; 341 269 int mask; 342 270 hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 343 - &wireless, sizeof(wireless)); 271 + &wireless, sizeof(wireless), 272 + sizeof(wireless)); 344 273 /* TBD: Pass error */ 345 274 346 275 mask = 0x800 << (r * 8); ··· 350 277 return false; 351 278 else 352 279 return true; 280 + } 281 + 282 + static int hp_wmi_rfkill2_set_block(void *data, bool blocked) 283 + { 284 + int rfkill_id = (int)(long)data; 285 + char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked }; 286 + 287 + if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1, 288 + buffer, sizeof(buffer), 0)) 289 + return -EINVAL; 290 + return 0; 291 + } 292 + 293 + static const struct rfkill_ops hp_wmi_rfkill2_ops = { 294 + .set_block = hp_wmi_rfkill2_set_block, 295 + }; 296 + 297 + static int hp_wmi_rfkill2_refresh(void) 298 + { 299 + int err, i; 300 + struct bios_rfkill2_state state; 301 + 302 + err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 303 + 0, sizeof(state)); 304 + if (err) 305 + return err; 306 + 307 + for (i = 0; i < rfkill2_count; i++) { 308 + int num = rfkill2[i].num; 309 + struct bios_rfkill2_device_state *devstate; 310 + devstate = &state.device[num]; 311 + 312 + if (num >= state.count || 313 + devstate->rfkill_id != rfkill2[i].id) { 314 + printk(KERN_WARNING PREFIX "power configuration of " 315 + "the wireless devices unexpectedly changed\n"); 316 + continue; 317 + } 318 + 319 + rfkill_set_states(rfkill2[i].rfkill, 320 + IS_SWBLOCKED(devstate->power), 321 + IS_HWBLOCKED(devstate->power)); 322 + } 323 + 324 + return 0; 353 325 } 354 326 355 327 static ssize_t show_display(struct device *dev, struct device_attribute *attr, ··· 447 329 { 448 330 u32 tmp = simple_strtoul(buf, NULL, 10); 449 331 int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp, 450 - sizeof(tmp)); 332 + sizeof(tmp), sizeof(tmp)); 451 333 if (ret) 452 334 return -EINVAL; 453 335 ··· 520 402 case HPWMI_BEZEL_BUTTON: 521 403 ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, 522 404 &key_code, 405 + sizeof(key_code), 523 406 sizeof(key_code)); 524 407 if (ret) 525 408 break; ··· 531 412 key_code); 532 413 break; 533 414 case HPWMI_WIRELESS: 415 + if (rfkill2_count) { 416 + hp_wmi_rfkill2_refresh(); 417 + break; 418 + } 419 + 534 420 if (wifi_rfkill) 535 421 rfkill_set_states(wifi_rfkill, 536 422 hp_wmi_get_sw_state(HPWMI_WIFI), ··· 626 502 device_remove_file(&device->dev, &dev_attr_tablet); 627 503 } 628 504 629 - static int __devinit hp_wmi_bios_setup(struct platform_device *device) 505 + static int __devinit hp_wmi_rfkill_setup(struct platform_device *device) 630 506 { 631 507 int err; 632 508 int wireless = 0; 633 509 634 510 err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless, 635 - sizeof(wireless)); 511 + sizeof(wireless), sizeof(wireless)); 636 512 if (err) 637 513 return err; 638 - 639 - err = device_create_file(&device->dev, &dev_attr_display); 640 - if (err) 641 - goto add_sysfs_error; 642 - err = device_create_file(&device->dev, &dev_attr_hddtemp); 643 - if (err) 644 - goto add_sysfs_error; 645 - err = device_create_file(&device->dev, &dev_attr_als); 646 - if (err) 647 - goto add_sysfs_error; 648 - err = device_create_file(&device->dev, &dev_attr_dock); 649 - if (err) 650 - goto add_sysfs_error; 651 - err = device_create_file(&device->dev, &dev_attr_tablet); 652 - if (err) 653 - goto add_sysfs_error; 654 514 655 515 if (wireless & 0x1) { 656 516 wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, ··· 681 573 return 0; 682 574 register_wwan_err: 683 575 rfkill_destroy(wwan_rfkill); 576 + wwan_rfkill = NULL; 684 577 if (bluetooth_rfkill) 685 578 rfkill_unregister(bluetooth_rfkill); 686 579 register_bluetooth_error: 687 580 rfkill_destroy(bluetooth_rfkill); 581 + bluetooth_rfkill = NULL; 688 582 if (wifi_rfkill) 689 583 rfkill_unregister(wifi_rfkill); 690 584 register_wifi_error: 691 585 rfkill_destroy(wifi_rfkill); 586 + wifi_rfkill = NULL; 587 + return err; 588 + } 589 + 590 + static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device) 591 + { 592 + int err, i; 593 + struct bios_rfkill2_state state; 594 + err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state, 595 + 0, sizeof(state)); 596 + if (err) 597 + return err; 598 + 599 + if (state.count > HPWMI_MAX_RFKILL2_DEVICES) { 600 + printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n"); 601 + return -EINVAL; 602 + } 603 + 604 + for (i = 0; i < state.count; i++) { 605 + struct rfkill *rfkill; 606 + enum rfkill_type type; 607 + char *name; 608 + switch (state.device[i].radio_type) { 609 + case HPWMI_WIFI: 610 + type = RFKILL_TYPE_WLAN; 611 + name = "hp-wifi"; 612 + break; 613 + case HPWMI_BLUETOOTH: 614 + type = RFKILL_TYPE_BLUETOOTH; 615 + name = "hp-bluetooth"; 616 + break; 617 + case HPWMI_WWAN: 618 + type = RFKILL_TYPE_WWAN; 619 + name = "hp-wwan"; 620 + break; 621 + default: 622 + printk(KERN_WARNING PREFIX "unknown device type 0x%x\n", 623 + state.device[i].radio_type); 624 + continue; 625 + } 626 + 627 + if (!state.device[i].vendor_id) { 628 + printk(KERN_WARNING PREFIX "zero device %d while %d " 629 + "reported\n", i, state.count); 630 + continue; 631 + } 632 + 633 + rfkill = rfkill_alloc(name, &device->dev, type, 634 + &hp_wmi_rfkill2_ops, (void *)(long)i); 635 + if (!rfkill) { 636 + err = -ENOMEM; 637 + goto fail; 638 + } 639 + 640 + rfkill2[rfkill2_count].id = state.device[i].rfkill_id; 641 + rfkill2[rfkill2_count].num = i; 642 + rfkill2[rfkill2_count].rfkill = rfkill; 643 + 644 + rfkill_init_sw_state(rfkill, 645 + IS_SWBLOCKED(state.device[i].power)); 646 + rfkill_set_hw_state(rfkill, 647 + IS_HWBLOCKED(state.device[i].power)); 648 + 649 + if (!(state.device[i].power & HPWMI_POWER_BIOS)) 650 + printk(KERN_INFO PREFIX "device %s blocked by BIOS\n", 651 + name); 652 + 653 + err = rfkill_register(rfkill); 654 + if (err) { 655 + rfkill_destroy(rfkill); 656 + goto fail; 657 + } 658 + 659 + rfkill2_count++; 660 + } 661 + 662 + return 0; 663 + fail: 664 + for (; rfkill2_count > 0; rfkill2_count--) { 665 + rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill); 666 + rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill); 667 + } 668 + return err; 669 + } 670 + 671 + static int __devinit hp_wmi_bios_setup(struct platform_device *device) 672 + { 673 + int err; 674 + 675 + /* clear detected rfkill devices */ 676 + wifi_rfkill = NULL; 677 + bluetooth_rfkill = NULL; 678 + wwan_rfkill = NULL; 679 + rfkill2_count = 0; 680 + 681 + if (hp_wmi_rfkill_setup(device)) 682 + hp_wmi_rfkill2_setup(device); 683 + 684 + err = device_create_file(&device->dev, &dev_attr_display); 685 + if (err) 686 + goto add_sysfs_error; 687 + err = device_create_file(&device->dev, &dev_attr_hddtemp); 688 + if (err) 689 + goto add_sysfs_error; 690 + err = device_create_file(&device->dev, &dev_attr_als); 691 + if (err) 692 + goto add_sysfs_error; 693 + err = device_create_file(&device->dev, &dev_attr_dock); 694 + if (err) 695 + goto add_sysfs_error; 696 + err = device_create_file(&device->dev, &dev_attr_tablet); 697 + if (err) 698 + goto add_sysfs_error; 699 + return 0; 700 + 692 701 add_sysfs_error: 693 702 cleanup_sysfs(device); 694 703 return err; ··· 813 588 814 589 static int __exit hp_wmi_bios_remove(struct platform_device *device) 815 590 { 591 + int i; 816 592 cleanup_sysfs(device); 593 + 594 + for (i = 0; i < rfkill2_count; i++) { 595 + rfkill_unregister(rfkill2[i].rfkill); 596 + rfkill_destroy(rfkill2[i].rfkill); 597 + } 817 598 818 599 if (wifi_rfkill) { 819 600 rfkill_unregister(wifi_rfkill); ··· 852 621 hp_wmi_tablet_state()); 853 622 input_sync(hp_wmi_input_dev); 854 623 } 624 + 625 + if (rfkill2_count) 626 + hp_wmi_rfkill2_refresh(); 855 627 856 628 if (wifi_rfkill) 857 629 rfkill_set_states(wifi_rfkill,
+2
drivers/platform/x86/ideapad-laptop.c
··· 459 459 if (test_bit(vpc_bit, &vpc1)) { 460 460 if (vpc_bit == 9) 461 461 ideapad_sync_rfk_state(adevice); 462 + else if (vpc_bit == 4) 463 + read_ec_data(handle, 0x12, &vpc2); 462 464 else 463 465 ideapad_input_report(priv, vpc_bit); 464 466 }
+1 -1
drivers/platform/x86/intel_ips.c
··· 1111 1111 last_msecs = jiffies_to_msecs(jiffies); 1112 1112 expire = jiffies + msecs_to_jiffies(IPS_SAMPLE_PERIOD); 1113 1113 1114 - __set_current_state(TASK_UNINTERRUPTIBLE); 1114 + __set_current_state(TASK_INTERRUPTIBLE); 1115 1115 mod_timer(&timer, expire); 1116 1116 schedule(); 1117 1117
+148
drivers/platform/x86/intel_mid_powerbtn.c
··· 1 + /* 2 + * Power button driver for Medfield. 3 + * 4 + * Copyright (C) 2010 Intel Corp 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 as published by 8 + * the Free Software Foundation; version 2 of the License. 9 + * 10 + * This program is distributed in the hope that it will be useful, but 11 + * WITHOUT ANY WARRANTY; without even the implied warranty of 12 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 + * General Public License for more details. 14 + * 15 + * You should have received a copy of the GNU General Public License along 16 + * with this program; if not, write to the Free Software Foundation, Inc., 17 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 18 + */ 19 + 20 + #include <linux/module.h> 21 + #include <linux/init.h> 22 + #include <linux/interrupt.h> 23 + #include <linux/slab.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/input.h> 26 + #include <asm/intel_scu_ipc.h> 27 + 28 + #define DRIVER_NAME "msic_power_btn" 29 + 30 + #define MSIC_IRQ_STAT 0x02 31 + #define MSIC_IRQ_PB (1 << 0) 32 + #define MSIC_PB_CONFIG 0x3e 33 + #define MSIC_PB_STATUS 0x3f 34 + #define MSIC_PB_LEVEL (1 << 3) /* 1 - release, 0 - press */ 35 + 36 + struct mfld_pb_priv { 37 + struct input_dev *input; 38 + unsigned int irq; 39 + }; 40 + 41 + static irqreturn_t mfld_pb_isr(int irq, void *dev_id) 42 + { 43 + struct mfld_pb_priv *priv = dev_id; 44 + int ret; 45 + u8 pbstat; 46 + 47 + ret = intel_scu_ipc_ioread8(MSIC_PB_STATUS, &pbstat); 48 + if (ret < 0) 49 + return IRQ_HANDLED; 50 + 51 + input_event(priv->input, EV_KEY, KEY_POWER, !(pbstat & MSIC_PB_LEVEL)); 52 + input_sync(priv->input); 53 + 54 + return IRQ_HANDLED; 55 + } 56 + 57 + static int __devinit mfld_pb_probe(struct platform_device *pdev) 58 + { 59 + struct mfld_pb_priv *priv; 60 + struct input_dev *input; 61 + int irq; 62 + int error; 63 + 64 + irq = platform_get_irq(pdev, 0); 65 + if (irq < 0) 66 + return -EINVAL; 67 + 68 + priv = kzalloc(sizeof(struct mfld_pb_priv), GFP_KERNEL); 69 + input = input_allocate_device(); 70 + if (!priv || !input) { 71 + error = -ENOMEM; 72 + goto err_free_mem; 73 + } 74 + 75 + priv->input = input; 76 + priv->irq = irq; 77 + 78 + input->name = pdev->name; 79 + input->phys = "power-button/input0"; 80 + input->id.bustype = BUS_HOST; 81 + input->dev.parent = &pdev->dev; 82 + 83 + input_set_capability(input, EV_KEY, KEY_POWER); 84 + 85 + error = request_threaded_irq(priv->irq, NULL, mfld_pb_isr, 86 + 0, DRIVER_NAME, priv); 87 + if (error) { 88 + dev_err(&pdev->dev, 89 + "unable to request irq %d for mfld power button\n", 90 + irq); 91 + goto err_free_mem; 92 + } 93 + 94 + error = input_register_device(input); 95 + if (error) { 96 + dev_err(&pdev->dev, 97 + "unable to register input dev, error %d\n", error); 98 + goto err_free_irq; 99 + } 100 + 101 + platform_set_drvdata(pdev, priv); 102 + return 0; 103 + 104 + err_free_irq: 105 + free_irq(priv->irq, priv); 106 + err_free_mem: 107 + input_free_device(input); 108 + kfree(priv); 109 + return error; 110 + } 111 + 112 + static int __devexit mfld_pb_remove(struct platform_device *pdev) 113 + { 114 + struct mfld_pb_priv *priv = platform_get_drvdata(pdev); 115 + 116 + free_irq(priv->irq, priv); 117 + input_unregister_device(priv->input); 118 + kfree(priv); 119 + 120 + platform_set_drvdata(pdev, NULL); 121 + return 0; 122 + } 123 + 124 + static struct platform_driver mfld_pb_driver = { 125 + .driver = { 126 + .name = DRIVER_NAME, 127 + .owner = THIS_MODULE, 128 + }, 129 + .probe = mfld_pb_probe, 130 + .remove = __devexit_p(mfld_pb_remove), 131 + }; 132 + 133 + static int __init mfld_pb_init(void) 134 + { 135 + return platform_driver_register(&mfld_pb_driver); 136 + } 137 + module_init(mfld_pb_init); 138 + 139 + static void __exit mfld_pb_exit(void) 140 + { 141 + platform_driver_unregister(&mfld_pb_driver); 142 + } 143 + module_exit(mfld_pb_exit); 144 + 145 + MODULE_AUTHOR("Hong Liu <hong.liu@intel.com>"); 146 + MODULE_DESCRIPTION("Intel Medfield Power Button Driver"); 147 + MODULE_LICENSE("GPL v2"); 148 + MODULE_ALIAS("platform:" DRIVER_NAME);
+576
drivers/platform/x86/intel_mid_thermal.c
··· 1 + /* 2 + * intel_mid_thermal.c - Intel MID platform thermal driver 3 + * 4 + * Copyright (C) 2011 Intel Corporation 5 + * 6 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; version 2 of the License. 11 + * 12 + * This program is distributed in the hope that it will be useful, but 13 + * WITHOUT ANY WARRANTY; without even the implied warranty of 14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 + * General Public License for more details. 16 + * 17 + * You should have received a copy of the GNU General Public License along 18 + * with this program; if not, write to the Free Software Foundation, Inc., 19 + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 20 + * 21 + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 + * Author: Durgadoss R <durgadoss.r@intel.com> 23 + */ 24 + 25 + #define pr_fmt(fmt) "intel_mid_thermal: " fmt 26 + 27 + #include <linux/module.h> 28 + #include <linux/init.h> 29 + #include <linux/err.h> 30 + #include <linux/param.h> 31 + #include <linux/device.h> 32 + #include <linux/platform_device.h> 33 + #include <linux/slab.h> 34 + #include <linux/pm.h> 35 + #include <linux/thermal.h> 36 + 37 + #include <asm/intel_scu_ipc.h> 38 + 39 + /* Number of thermal sensors */ 40 + #define MSIC_THERMAL_SENSORS 4 41 + 42 + /* ADC1 - thermal registers */ 43 + #define MSIC_THERM_ADC1CNTL1 0x1C0 44 + #define MSIC_ADC_ENBL 0x10 45 + #define MSIC_ADC_START 0x08 46 + 47 + #define MSIC_THERM_ADC1CNTL3 0x1C2 48 + #define MSIC_ADCTHERM_ENBL 0x04 49 + #define MSIC_ADCRRDATA_ENBL 0x05 50 + #define MSIC_CHANL_MASK_VAL 0x0F 51 + 52 + #define MSIC_STOPBIT_MASK 16 53 + #define MSIC_ADCTHERM_MASK 4 54 + #define ADC_CHANLS_MAX 15 /* Number of ADC channels */ 55 + #define ADC_LOOP_MAX (ADC_CHANLS_MAX - MSIC_THERMAL_SENSORS) 56 + 57 + /* ADC channel code values */ 58 + #define SKIN_SENSOR0_CODE 0x08 59 + #define SKIN_SENSOR1_CODE 0x09 60 + #define SYS_SENSOR_CODE 0x0A 61 + #define MSIC_DIE_SENSOR_CODE 0x03 62 + 63 + #define SKIN_THERM_SENSOR0 0 64 + #define SKIN_THERM_SENSOR1 1 65 + #define SYS_THERM_SENSOR2 2 66 + #define MSIC_DIE_THERM_SENSOR3 3 67 + 68 + /* ADC code range */ 69 + #define ADC_MAX 977 70 + #define ADC_MIN 162 71 + #define ADC_VAL0C 887 72 + #define ADC_VAL20C 720 73 + #define ADC_VAL40C 508 74 + #define ADC_VAL60C 315 75 + 76 + /* ADC base addresses */ 77 + #define ADC_CHNL_START_ADDR 0x1C5 /* increments by 1 */ 78 + #define ADC_DATA_START_ADDR 0x1D4 /* increments by 2 */ 79 + 80 + /* MSIC die attributes */ 81 + #define MSIC_DIE_ADC_MIN 488 82 + #define MSIC_DIE_ADC_MAX 1004 83 + 84 + /* This holds the address of the first free ADC channel, 85 + * among the 15 channels 86 + */ 87 + static int channel_index; 88 + 89 + struct platform_info { 90 + struct platform_device *pdev; 91 + struct thermal_zone_device *tzd[MSIC_THERMAL_SENSORS]; 92 + }; 93 + 94 + struct thermal_device_info { 95 + unsigned int chnl_addr; 96 + int direct; 97 + /* This holds the current temperature in millidegree celsius */ 98 + long curr_temp; 99 + }; 100 + 101 + /** 102 + * to_msic_die_temp - converts adc_val to msic_die temperature 103 + * @adc_val: ADC value to be converted 104 + * 105 + * Can sleep 106 + */ 107 + static int to_msic_die_temp(uint16_t adc_val) 108 + { 109 + return (368 * (adc_val) / 1000) - 220; 110 + } 111 + 112 + /** 113 + * is_valid_adc - checks whether the adc code is within the defined range 114 + * @min: minimum value for the sensor 115 + * @max: maximum value for the sensor 116 + * 117 + * Can sleep 118 + */ 119 + static int is_valid_adc(uint16_t adc_val, uint16_t min, uint16_t max) 120 + { 121 + return (adc_val >= min) && (adc_val <= max); 122 + } 123 + 124 + /** 125 + * adc_to_temp - converts the ADC code to temperature in C 126 + * @direct: true if ths channel is direct index 127 + * @adc_val: the adc_val that needs to be converted 128 + * @tp: temperature return value 129 + * 130 + * Linear approximation is used to covert the skin adc value into temperature. 131 + * This technique is used to avoid very long look-up table to get 132 + * the appropriate temp value from ADC value. 133 + * The adc code vs sensor temp curve is split into five parts 134 + * to achieve very close approximate temp value with less than 135 + * 0.5C error 136 + */ 137 + static int adc_to_temp(int direct, uint16_t adc_val, unsigned long *tp) 138 + { 139 + int temp; 140 + 141 + /* Direct conversion for die temperature */ 142 + if (direct) { 143 + if (is_valid_adc(adc_val, MSIC_DIE_ADC_MIN, MSIC_DIE_ADC_MAX)) { 144 + *tp = to_msic_die_temp(adc_val) * 1000; 145 + return 0; 146 + } 147 + return -ERANGE; 148 + } 149 + 150 + if (!is_valid_adc(adc_val, ADC_MIN, ADC_MAX)) 151 + return -ERANGE; 152 + 153 + /* Linear approximation for skin temperature */ 154 + if (adc_val > ADC_VAL0C) 155 + temp = 177 - (adc_val/5); 156 + else if ((adc_val <= ADC_VAL0C) && (adc_val > ADC_VAL20C)) 157 + temp = 111 - (adc_val/8); 158 + else if ((adc_val <= ADC_VAL20C) && (adc_val > ADC_VAL40C)) 159 + temp = 92 - (adc_val/10); 160 + else if ((adc_val <= ADC_VAL40C) && (adc_val > ADC_VAL60C)) 161 + temp = 91 - (adc_val/10); 162 + else 163 + temp = 112 - (adc_val/6); 164 + 165 + /* Convert temperature in celsius to milli degree celsius */ 166 + *tp = temp * 1000; 167 + return 0; 168 + } 169 + 170 + /** 171 + * mid_read_temp - read sensors for temperature 172 + * @temp: holds the current temperature for the sensor after reading 173 + * 174 + * reads the adc_code from the channel and converts it to real 175 + * temperature. The converted value is stored in temp. 176 + * 177 + * Can sleep 178 + */ 179 + static int mid_read_temp(struct thermal_zone_device *tzd, unsigned long *temp) 180 + { 181 + struct thermal_device_info *td_info = tzd->devdata; 182 + uint16_t adc_val, addr; 183 + uint8_t data = 0; 184 + int ret; 185 + unsigned long curr_temp; 186 + 187 + 188 + addr = td_info->chnl_addr; 189 + 190 + /* Enable the msic for conversion before reading */ 191 + ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCRRDATA_ENBL); 192 + if (ret) 193 + return ret; 194 + 195 + /* Re-toggle the RRDATARD bit (temporary workaround) */ 196 + ret = intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL3, MSIC_ADCTHERM_ENBL); 197 + if (ret) 198 + return ret; 199 + 200 + /* Read the higher bits of data */ 201 + ret = intel_scu_ipc_ioread8(addr, &data); 202 + if (ret) 203 + return ret; 204 + 205 + /* Shift bits to accomodate the lower two data bits */ 206 + adc_val = (data << 2); 207 + addr++; 208 + 209 + ret = intel_scu_ipc_ioread8(addr, &data);/* Read lower bits */ 210 + if (ret) 211 + return ret; 212 + 213 + /* Adding lower two bits to the higher bits */ 214 + data &= 03; 215 + adc_val += data; 216 + 217 + /* Convert ADC value to temperature */ 218 + ret = adc_to_temp(td_info->direct, adc_val, &curr_temp); 219 + if (ret == 0) 220 + *temp = td_info->curr_temp = curr_temp; 221 + return ret; 222 + } 223 + 224 + /** 225 + * configure_adc - enables/disables the ADC for conversion 226 + * @val: zero: disables the ADC non-zero:enables the ADC 227 + * 228 + * Enable/Disable the ADC depending on the argument 229 + * 230 + * Can sleep 231 + */ 232 + static int configure_adc(int val) 233 + { 234 + int ret; 235 + uint8_t data; 236 + 237 + ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); 238 + if (ret) 239 + return ret; 240 + 241 + if (val) { 242 + /* Enable and start the ADC */ 243 + data |= (MSIC_ADC_ENBL | MSIC_ADC_START); 244 + } else { 245 + /* Just stop the ADC */ 246 + data &= (~MSIC_ADC_START); 247 + } 248 + 249 + return intel_scu_ipc_iowrite8(MSIC_THERM_ADC1CNTL1, data); 250 + } 251 + 252 + /** 253 + * set_up_therm_channel - enable thermal channel for conversion 254 + * @base_addr: index of free msic ADC channel 255 + * 256 + * Enable all the three channels for conversion 257 + * 258 + * Can sleep 259 + */ 260 + static int set_up_therm_channel(u16 base_addr) 261 + { 262 + int ret; 263 + 264 + /* Enable all the sensor channels */ 265 + ret = intel_scu_ipc_iowrite8(base_addr, SKIN_SENSOR0_CODE); 266 + if (ret) 267 + return ret; 268 + 269 + ret = intel_scu_ipc_iowrite8(base_addr + 1, SKIN_SENSOR1_CODE); 270 + if (ret) 271 + return ret; 272 + 273 + ret = intel_scu_ipc_iowrite8(base_addr + 2, SYS_SENSOR_CODE); 274 + if (ret) 275 + return ret; 276 + 277 + /* Since this is the last channel, set the stop bit 278 + to 1 by ORing the DIE_SENSOR_CODE with 0x10 */ 279 + ret = intel_scu_ipc_iowrite8(base_addr + 3, 280 + (MSIC_DIE_SENSOR_CODE | 0x10)); 281 + if (ret) 282 + return ret; 283 + 284 + /* Enable ADC and start it */ 285 + return configure_adc(1); 286 + } 287 + 288 + /** 289 + * reset_stopbit - sets the stop bit to 0 on the given channel 290 + * @addr: address of the channel 291 + * 292 + * Can sleep 293 + */ 294 + static int reset_stopbit(uint16_t addr) 295 + { 296 + int ret; 297 + uint8_t data; 298 + ret = intel_scu_ipc_ioread8(addr, &data); 299 + if (ret) 300 + return ret; 301 + /* Set the stop bit to zero */ 302 + return intel_scu_ipc_iowrite8(addr, (data & 0xEF)); 303 + } 304 + 305 + /** 306 + * find_free_channel - finds an empty channel for conversion 307 + * 308 + * If the ADC is not enabled then start using 0th channel 309 + * itself. Otherwise find an empty channel by looking for a 310 + * channel in which the stopbit is set to 1. returns the index 311 + * of the first free channel if succeeds or an error code. 312 + * 313 + * Context: can sleep 314 + * 315 + * FIXME: Ultimately the channel allocator will move into the intel_scu_ipc 316 + * code. 317 + */ 318 + static int find_free_channel(void) 319 + { 320 + int ret; 321 + int i; 322 + uint8_t data; 323 + 324 + /* check whether ADC is enabled */ 325 + ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL1, &data); 326 + if (ret) 327 + return ret; 328 + 329 + if ((data & MSIC_ADC_ENBL) == 0) 330 + return 0; 331 + 332 + /* ADC is already enabled; Looking for an empty channel */ 333 + for (i = 0; i < ADC_CHANLS_MAX; i++) { 334 + ret = intel_scu_ipc_ioread8(ADC_CHNL_START_ADDR + i, &data); 335 + if (ret) 336 + return ret; 337 + 338 + if (data & MSIC_STOPBIT_MASK) { 339 + ret = i; 340 + break; 341 + } 342 + } 343 + return (ret > ADC_LOOP_MAX) ? (-EINVAL) : ret; 344 + } 345 + 346 + /** 347 + * mid_initialize_adc - initializing the ADC 348 + * @dev: our device structure 349 + * 350 + * Initialize the ADC for reading thermistor values. Can sleep. 351 + */ 352 + static int mid_initialize_adc(struct device *dev) 353 + { 354 + u8 data; 355 + u16 base_addr; 356 + int ret; 357 + 358 + /* 359 + * Ensure that adctherm is disabled before we 360 + * initialize the ADC 361 + */ 362 + ret = intel_scu_ipc_ioread8(MSIC_THERM_ADC1CNTL3, &data); 363 + if (ret) 364 + return ret; 365 + 366 + if (data & MSIC_ADCTHERM_MASK) 367 + dev_warn(dev, "ADCTHERM already set"); 368 + 369 + /* Index of the first channel in which the stop bit is set */ 370 + channel_index = find_free_channel(); 371 + if (channel_index < 0) { 372 + dev_err(dev, "No free ADC channels"); 373 + return channel_index; 374 + } 375 + 376 + base_addr = ADC_CHNL_START_ADDR + channel_index; 377 + 378 + if (!(channel_index == 0 || channel_index == ADC_LOOP_MAX)) { 379 + /* Reset stop bit for channels other than 0 and 12 */ 380 + ret = reset_stopbit(base_addr); 381 + if (ret) 382 + return ret; 383 + 384 + /* Index of the first free channel */ 385 + base_addr++; 386 + channel_index++; 387 + } 388 + 389 + ret = set_up_therm_channel(base_addr); 390 + if (ret) { 391 + dev_err(dev, "unable to enable ADC"); 392 + return ret; 393 + } 394 + dev_dbg(dev, "ADC initialization successful"); 395 + return ret; 396 + } 397 + 398 + /** 399 + * initialize_sensor - sets default temp and timer ranges 400 + * @index: index of the sensor 401 + * 402 + * Context: can sleep 403 + */ 404 + static struct thermal_device_info *initialize_sensor(int index) 405 + { 406 + struct thermal_device_info *td_info = 407 + kzalloc(sizeof(struct thermal_device_info), GFP_KERNEL); 408 + 409 + if (!td_info) 410 + return NULL; 411 + 412 + /* Set the base addr of the channel for this sensor */ 413 + td_info->chnl_addr = ADC_DATA_START_ADDR + 2 * (channel_index + index); 414 + /* Sensor 3 is direct conversion */ 415 + if (index == 3) 416 + td_info->direct = 1; 417 + return td_info; 418 + } 419 + 420 + /** 421 + * mid_thermal_resume - resume routine 422 + * @pdev: platform device structure 423 + * 424 + * mid thermal resume: re-initializes the adc. Can sleep. 425 + */ 426 + static int mid_thermal_resume(struct platform_device *pdev) 427 + { 428 + return mid_initialize_adc(&pdev->dev); 429 + } 430 + 431 + /** 432 + * mid_thermal_suspend - suspend routine 433 + * @pdev: platform device structure 434 + * 435 + * mid thermal suspend implements the suspend functionality 436 + * by stopping the ADC. Can sleep. 437 + */ 438 + static int mid_thermal_suspend(struct platform_device *pdev, pm_message_t mesg) 439 + { 440 + /* 441 + * This just stops the ADC and does not disable it. 442 + * temporary workaround until we have a generic ADC driver. 443 + * If 0 is passed, it disables the ADC. 444 + */ 445 + return configure_adc(0); 446 + } 447 + 448 + /** 449 + * read_curr_temp - reads the current temperature and stores in temp 450 + * @temp: holds the current temperature value after reading 451 + * 452 + * Can sleep 453 + */ 454 + static int read_curr_temp(struct thermal_zone_device *tzd, unsigned long *temp) 455 + { 456 + WARN_ON(tzd == NULL); 457 + return mid_read_temp(tzd, temp); 458 + } 459 + 460 + /* Can't be const */ 461 + static struct thermal_zone_device_ops tzd_ops = { 462 + .get_temp = read_curr_temp, 463 + }; 464 + 465 + 466 + /** 467 + * mid_thermal_probe - mfld thermal initialize 468 + * @pdev: platform device structure 469 + * 470 + * mid thermal probe initializes the hardware and registers 471 + * all the sensors with the generic thermal framework. Can sleep. 472 + */ 473 + static int mid_thermal_probe(struct platform_device *pdev) 474 + { 475 + static char *name[MSIC_THERMAL_SENSORS] = { 476 + "skin0", "skin1", "sys", "msicdie" 477 + }; 478 + 479 + int ret; 480 + int i; 481 + struct platform_info *pinfo; 482 + 483 + pinfo = kzalloc(sizeof(struct platform_info), GFP_KERNEL); 484 + if (!pinfo) 485 + return -ENOMEM; 486 + 487 + /* Initializing the hardware */ 488 + ret = mid_initialize_adc(&pdev->dev); 489 + if (ret) { 490 + dev_err(&pdev->dev, "ADC init failed"); 491 + kfree(pinfo); 492 + return ret; 493 + } 494 + 495 + /* Register each sensor with the generic thermal framework*/ 496 + for (i = 0; i < MSIC_THERMAL_SENSORS; i++) { 497 + pinfo->tzd[i] = thermal_zone_device_register(name[i], 498 + 0, initialize_sensor(i), 499 + &tzd_ops, 0, 0, 0, 0); 500 + if (IS_ERR(pinfo->tzd[i])) 501 + goto reg_fail; 502 + } 503 + 504 + pinfo->pdev = pdev; 505 + platform_set_drvdata(pdev, pinfo); 506 + return 0; 507 + 508 + reg_fail: 509 + ret = PTR_ERR(pinfo->tzd[i]); 510 + while (--i >= 0) 511 + thermal_zone_device_unregister(pinfo->tzd[i]); 512 + configure_adc(0); 513 + kfree(pinfo); 514 + return ret; 515 + } 516 + 517 + /** 518 + * mid_thermal_remove - mfld thermal finalize 519 + * @dev: platform device structure 520 + * 521 + * MLFD thermal remove unregisters all the sensors from the generic 522 + * thermal framework. Can sleep. 523 + */ 524 + static int mid_thermal_remove(struct platform_device *pdev) 525 + { 526 + int i; 527 + struct platform_info *pinfo = platform_get_drvdata(pdev); 528 + 529 + for (i = 0; i < MSIC_THERMAL_SENSORS; i++) 530 + thermal_zone_device_unregister(pinfo->tzd[i]); 531 + 532 + platform_set_drvdata(pdev, NULL); 533 + 534 + /* Stop the ADC */ 535 + return configure_adc(0); 536 + } 537 + 538 + /********************************************************************* 539 + * Driver initialisation and finalization 540 + *********************************************************************/ 541 + 542 + #define DRIVER_NAME "msic_sensor" 543 + 544 + static const struct platform_device_id therm_id_table[] = { 545 + { DRIVER_NAME, 1 }, 546 + { } 547 + }; 548 + 549 + static struct platform_driver mid_thermal_driver = { 550 + .driver = { 551 + .name = DRIVER_NAME, 552 + .owner = THIS_MODULE, 553 + }, 554 + .probe = mid_thermal_probe, 555 + .suspend = mid_thermal_suspend, 556 + .resume = mid_thermal_resume, 557 + .remove = __devexit_p(mid_thermal_remove), 558 + .id_table = therm_id_table, 559 + }; 560 + 561 + static int __init mid_thermal_module_init(void) 562 + { 563 + return platform_driver_register(&mid_thermal_driver); 564 + } 565 + 566 + static void __exit mid_thermal_module_exit(void) 567 + { 568 + platform_driver_unregister(&mid_thermal_driver); 569 + } 570 + 571 + module_init(mid_thermal_module_init); 572 + module_exit(mid_thermal_module_exit); 573 + 574 + MODULE_AUTHOR("Durgadoss R <durgadoss.r@intel.com>"); 575 + MODULE_DESCRIPTION("Intel Medfield Platform Thermal Driver"); 576 + MODULE_LICENSE("GPL");
+1 -1
drivers/platform/x86/intel_rar_register.c
··· 485 485 * 486 486 * The register_rar function is to used by other device drivers 487 487 * to ensure that this driver is ready. As we cannot be sure of 488 - * the compile/execute order of drivers in ther kernel, it is 488 + * the compile/execute order of drivers in the kernel, it is 489 489 * best to give this driver a callback function to call when 490 490 * it is ready to give out addresses. The callback function 491 491 * would have those steps that continue the initialization of
+1 -1
drivers/platform/x86/intel_scu_ipc.c
··· 9 9 * as published by the Free Software Foundation; version 2 10 10 * of the License. 11 11 * 12 - * SCU runing in ARC processor communicates with other entity running in IA 12 + * SCU running in ARC processor communicates with other entity running in IA 13 13 * core through IPC mechanism which in turn messaging between IA core ad SCU. 14 14 * SCU has two IPC mechanism IPC-1 and IPC-2. IPC-1 is used between IA32 and 15 15 * SCU where IPC-2 is used between P-Unit and SCU. This driver delas with
+86 -9
drivers/platform/x86/msi-laptop.c
··· 51 51 * laptop as MSI S270. YMMV. 52 52 */ 53 53 54 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 55 + 54 56 #include <linux/module.h> 55 57 #include <linux/kernel.h> 56 58 #include <linux/init.h> ··· 62 60 #include <linux/platform_device.h> 63 61 #include <linux/rfkill.h> 64 62 #include <linux/i8042.h> 63 + #include <linux/input.h> 64 + #include <linux/input/sparse-keymap.h> 65 65 66 66 #define MSI_DRIVER_VERSION "0.5" 67 67 ··· 82 78 #define MSI_STANDARD_EC_SCM_LOAD_ADDRESS 0x2d 83 79 #define MSI_STANDARD_EC_SCM_LOAD_MASK (1 << 0) 84 80 81 + #define MSI_STANDARD_EC_TOUCHPAD_ADDRESS 0xe4 82 + #define MSI_STANDARD_EC_TOUCHPAD_MASK (1 << 4) 83 + 85 84 static int msi_laptop_resume(struct platform_device *device); 86 85 87 86 #define MSI_STANDARD_EC_DEVICES_EXISTS_ADDRESS 0x2f ··· 96 89 static int auto_brightness; 97 90 module_param(auto_brightness, int, 0); 98 91 MODULE_PARM_DESC(auto_brightness, "Enable automatic brightness control (0: disabled; 1: enabled; 2: don't touch)"); 92 + 93 + static const struct key_entry msi_laptop_keymap[] = { 94 + {KE_KEY, KEY_TOUCHPAD_ON, {KEY_TOUCHPAD_ON} }, /* Touch Pad On */ 95 + {KE_KEY, KEY_TOUCHPAD_OFF, {KEY_TOUCHPAD_OFF} },/* Touch Pad On */ 96 + {KE_END, 0} 97 + }; 98 + 99 + static struct input_dev *msi_laptop_input_dev; 99 100 100 101 static bool old_ec_model; 101 102 static int wlan_s, bluetooth_s, threeg_s; ··· 447 432 448 433 static int dmi_check_cb(const struct dmi_system_id *id) 449 434 { 450 - printk(KERN_INFO "msi-laptop: Identified laptop model '%s'.\n", 451 - id->ident); 435 + pr_info("Identified laptop model '%s'.\n", id->ident); 452 436 return 1; 453 437 } 454 438 ··· 619 605 } 620 606 static DECLARE_DELAYED_WORK(msi_rfkill_work, msi_update_rfkill); 621 607 608 + static void msi_send_touchpad_key(struct work_struct *ignored) 609 + { 610 + u8 rdata; 611 + int result; 612 + 613 + result = ec_read(MSI_STANDARD_EC_TOUCHPAD_ADDRESS, &rdata); 614 + if (result < 0) 615 + return; 616 + 617 + sparse_keymap_report_event(msi_laptop_input_dev, 618 + (rdata & MSI_STANDARD_EC_TOUCHPAD_MASK) ? 619 + KEY_TOUCHPAD_ON : KEY_TOUCHPAD_OFF, 1, true); 620 + } 621 + static DECLARE_DELAYED_WORK(msi_touchpad_work, msi_send_touchpad_key); 622 + 622 623 static bool msi_laptop_i8042_filter(unsigned char data, unsigned char str, 623 624 struct serio *port) 624 625 { ··· 642 613 if (str & 0x20) 643 614 return false; 644 615 645 - /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan*/ 616 + /* 0x54 wwan, 0x62 bluetooth, 0x76 wlan, 0xE4 touchpad toggle*/ 646 617 if (unlikely(data == 0xe0)) { 647 618 extended = true; 648 619 return false; 649 620 } else if (unlikely(extended)) { 621 + extended = false; 650 622 switch (data) { 623 + case 0xE4: 624 + schedule_delayed_work(&msi_touchpad_work, 625 + round_jiffies_relative(0.5 * HZ)); 626 + break; 651 627 case 0x54: 652 628 case 0x62: 653 629 case 0x76: ··· 660 626 round_jiffies_relative(0.5 * HZ)); 661 627 break; 662 628 } 663 - extended = false; 664 629 } 665 630 666 631 return false; ··· 764 731 return 0; 765 732 } 766 733 734 + static int __init msi_laptop_input_setup(void) 735 + { 736 + int err; 737 + 738 + msi_laptop_input_dev = input_allocate_device(); 739 + if (!msi_laptop_input_dev) 740 + return -ENOMEM; 741 + 742 + msi_laptop_input_dev->name = "MSI Laptop hotkeys"; 743 + msi_laptop_input_dev->phys = "msi-laptop/input0"; 744 + msi_laptop_input_dev->id.bustype = BUS_HOST; 745 + 746 + err = sparse_keymap_setup(msi_laptop_input_dev, 747 + msi_laptop_keymap, NULL); 748 + if (err) 749 + goto err_free_dev; 750 + 751 + err = input_register_device(msi_laptop_input_dev); 752 + if (err) 753 + goto err_free_keymap; 754 + 755 + return 0; 756 + 757 + err_free_keymap: 758 + sparse_keymap_free(msi_laptop_input_dev); 759 + err_free_dev: 760 + input_free_device(msi_laptop_input_dev); 761 + return err; 762 + } 763 + 764 + static void msi_laptop_input_destroy(void) 765 + { 766 + sparse_keymap_free(msi_laptop_input_dev); 767 + input_unregister_device(msi_laptop_input_dev); 768 + } 769 + 767 770 static int load_scm_model_init(struct platform_device *sdev) 768 771 { 769 772 u8 data; ··· 828 759 if (result < 0) 829 760 goto fail_rfkill; 830 761 762 + /* setup input device */ 763 + result = msi_laptop_input_setup(); 764 + if (result) 765 + goto fail_input; 766 + 831 767 result = i8042_install_filter(msi_laptop_i8042_filter); 832 768 if (result) { 833 - printk(KERN_ERR 834 - "msi-laptop: Unable to install key filter\n"); 769 + pr_err("Unable to install key filter\n"); 835 770 goto fail_filter; 836 771 } 837 772 838 773 return 0; 839 774 840 775 fail_filter: 776 + msi_laptop_input_destroy(); 777 + 778 + fail_input: 841 779 rfkill_cleanup(); 842 780 843 781 fail_rfkill: ··· 875 799 /* Register backlight stuff */ 876 800 877 801 if (acpi_video_backlight_support()) { 878 - printk(KERN_INFO "MSI: Brightness ignored, must be controlled " 802 + pr_info("Brightness ignored, must be controlled " 879 803 "by ACPI video driver\n"); 880 804 } else { 881 805 struct backlight_properties props; ··· 930 854 if (auto_brightness != 2) 931 855 set_auto_brightness(auto_brightness); 932 856 933 - printk(KERN_INFO "msi-laptop: driver "MSI_DRIVER_VERSION" successfully loaded.\n"); 857 + pr_info("driver "MSI_DRIVER_VERSION" successfully loaded.\n"); 934 858 935 859 return 0; 936 860 ··· 962 886 { 963 887 if (load_scm_model) { 964 888 i8042_remove_filter(msi_laptop_i8042_filter); 889 + msi_laptop_input_destroy(); 965 890 cancel_delayed_work_sync(&msi_rfkill_work); 966 891 rfkill_cleanup(); 967 892 } ··· 978 901 if (auto_brightness != 2) 979 902 set_auto_brightness(1); 980 903 981 - printk(KERN_INFO "msi-laptop: driver unloaded.\n"); 904 + pr_info("driver unloaded.\n"); 982 905 } 983 906 984 907 module_init(msi_init);
+832
drivers/platform/x86/samsung-laptop.c
··· 1 + /* 2 + * Samsung Laptop driver 3 + * 4 + * Copyright (C) 2009,2011 Greg Kroah-Hartman (gregkh@suse.de) 5 + * Copyright (C) 2009,2011 Novell Inc. 6 + * 7 + * This program is free software; you can redistribute it and/or modify it 8 + * under the terms of the GNU General Public License version 2 as published by 9 + * the Free Software Foundation. 10 + * 11 + */ 12 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 + 14 + #include <linux/kernel.h> 15 + #include <linux/init.h> 16 + #include <linux/module.h> 17 + #include <linux/delay.h> 18 + #include <linux/pci.h> 19 + #include <linux/backlight.h> 20 + #include <linux/fb.h> 21 + #include <linux/dmi.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/rfkill.h> 24 + 25 + /* 26 + * This driver is needed because a number of Samsung laptops do not hook 27 + * their control settings through ACPI. So we have to poke around in the 28 + * BIOS to do things like brightness values, and "special" key controls. 29 + */ 30 + 31 + /* 32 + * We have 0 - 8 as valid brightness levels. The specs say that level 0 should 33 + * be reserved by the BIOS (which really doesn't make much sense), we tell 34 + * userspace that the value is 0 - 7 and then just tell the hardware 1 - 8 35 + */ 36 + #define MAX_BRIGHT 0x07 37 + 38 + 39 + #define SABI_IFACE_MAIN 0x00 40 + #define SABI_IFACE_SUB 0x02 41 + #define SABI_IFACE_COMPLETE 0x04 42 + #define SABI_IFACE_DATA 0x05 43 + 44 + /* Structure to get data back to the calling function */ 45 + struct sabi_retval { 46 + u8 retval[20]; 47 + }; 48 + 49 + struct sabi_header_offsets { 50 + u8 port; 51 + u8 re_mem; 52 + u8 iface_func; 53 + u8 en_mem; 54 + u8 data_offset; 55 + u8 data_segment; 56 + }; 57 + 58 + struct sabi_commands { 59 + /* 60 + * Brightness is 0 - 8, as described above. 61 + * Value 0 is for the BIOS to use 62 + */ 63 + u8 get_brightness; 64 + u8 set_brightness; 65 + 66 + /* 67 + * first byte: 68 + * 0x00 - wireless is off 69 + * 0x01 - wireless is on 70 + * second byte: 71 + * 0x02 - 3G is off 72 + * 0x03 - 3G is on 73 + * TODO, verify 3G is correct, that doesn't seem right... 74 + */ 75 + u8 get_wireless_button; 76 + u8 set_wireless_button; 77 + 78 + /* 0 is off, 1 is on */ 79 + u8 get_backlight; 80 + u8 set_backlight; 81 + 82 + /* 83 + * 0x80 or 0x00 - no action 84 + * 0x81 - recovery key pressed 85 + */ 86 + u8 get_recovery_mode; 87 + u8 set_recovery_mode; 88 + 89 + /* 90 + * on seclinux: 0 is low, 1 is high, 91 + * on swsmi: 0 is normal, 1 is silent, 2 is turbo 92 + */ 93 + u8 get_performance_level; 94 + u8 set_performance_level; 95 + 96 + /* 97 + * Tell the BIOS that Linux is running on this machine. 98 + * 81 is on, 80 is off 99 + */ 100 + u8 set_linux; 101 + }; 102 + 103 + struct sabi_performance_level { 104 + const char *name; 105 + u8 value; 106 + }; 107 + 108 + struct sabi_config { 109 + const char *test_string; 110 + u16 main_function; 111 + const struct sabi_header_offsets header_offsets; 112 + const struct sabi_commands commands; 113 + const struct sabi_performance_level performance_levels[4]; 114 + u8 min_brightness; 115 + u8 max_brightness; 116 + }; 117 + 118 + static const struct sabi_config sabi_configs[] = { 119 + { 120 + .test_string = "SECLINUX", 121 + 122 + .main_function = 0x4c49, 123 + 124 + .header_offsets = { 125 + .port = 0x00, 126 + .re_mem = 0x02, 127 + .iface_func = 0x03, 128 + .en_mem = 0x04, 129 + .data_offset = 0x05, 130 + .data_segment = 0x07, 131 + }, 132 + 133 + .commands = { 134 + .get_brightness = 0x00, 135 + .set_brightness = 0x01, 136 + 137 + .get_wireless_button = 0x02, 138 + .set_wireless_button = 0x03, 139 + 140 + .get_backlight = 0x04, 141 + .set_backlight = 0x05, 142 + 143 + .get_recovery_mode = 0x06, 144 + .set_recovery_mode = 0x07, 145 + 146 + .get_performance_level = 0x08, 147 + .set_performance_level = 0x09, 148 + 149 + .set_linux = 0x0a, 150 + }, 151 + 152 + .performance_levels = { 153 + { 154 + .name = "silent", 155 + .value = 0, 156 + }, 157 + { 158 + .name = "normal", 159 + .value = 1, 160 + }, 161 + { }, 162 + }, 163 + .min_brightness = 1, 164 + .max_brightness = 8, 165 + }, 166 + { 167 + .test_string = "SwSmi@", 168 + 169 + .main_function = 0x5843, 170 + 171 + .header_offsets = { 172 + .port = 0x00, 173 + .re_mem = 0x04, 174 + .iface_func = 0x02, 175 + .en_mem = 0x03, 176 + .data_offset = 0x05, 177 + .data_segment = 0x07, 178 + }, 179 + 180 + .commands = { 181 + .get_brightness = 0x10, 182 + .set_brightness = 0x11, 183 + 184 + .get_wireless_button = 0x12, 185 + .set_wireless_button = 0x13, 186 + 187 + .get_backlight = 0x2d, 188 + .set_backlight = 0x2e, 189 + 190 + .get_recovery_mode = 0xff, 191 + .set_recovery_mode = 0xff, 192 + 193 + .get_performance_level = 0x31, 194 + .set_performance_level = 0x32, 195 + 196 + .set_linux = 0xff, 197 + }, 198 + 199 + .performance_levels = { 200 + { 201 + .name = "normal", 202 + .value = 0, 203 + }, 204 + { 205 + .name = "silent", 206 + .value = 1, 207 + }, 208 + { 209 + .name = "overclock", 210 + .value = 2, 211 + }, 212 + { }, 213 + }, 214 + .min_brightness = 0, 215 + .max_brightness = 8, 216 + }, 217 + { }, 218 + }; 219 + 220 + static const struct sabi_config *sabi_config; 221 + 222 + static void __iomem *sabi; 223 + static void __iomem *sabi_iface; 224 + static void __iomem *f0000_segment; 225 + static struct backlight_device *backlight_device; 226 + static struct mutex sabi_mutex; 227 + static struct platform_device *sdev; 228 + static struct rfkill *rfk; 229 + 230 + static int force; 231 + module_param(force, bool, 0); 232 + MODULE_PARM_DESC(force, 233 + "Disable the DMI check and forces the driver to be loaded"); 234 + 235 + static int debug; 236 + module_param(debug, bool, S_IRUGO | S_IWUSR); 237 + MODULE_PARM_DESC(debug, "Debug enabled or not"); 238 + 239 + static int sabi_get_command(u8 command, struct sabi_retval *sretval) 240 + { 241 + int retval = 0; 242 + u16 port = readw(sabi + sabi_config->header_offsets.port); 243 + u8 complete, iface_data; 244 + 245 + mutex_lock(&sabi_mutex); 246 + 247 + /* enable memory to be able to write to it */ 248 + outb(readb(sabi + sabi_config->header_offsets.en_mem), port); 249 + 250 + /* write out the command */ 251 + writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); 252 + writew(command, sabi_iface + SABI_IFACE_SUB); 253 + writeb(0, sabi_iface + SABI_IFACE_COMPLETE); 254 + outb(readb(sabi + sabi_config->header_offsets.iface_func), port); 255 + 256 + /* write protect memory to make it safe */ 257 + outb(readb(sabi + sabi_config->header_offsets.re_mem), port); 258 + 259 + /* see if the command actually succeeded */ 260 + complete = readb(sabi_iface + SABI_IFACE_COMPLETE); 261 + iface_data = readb(sabi_iface + SABI_IFACE_DATA); 262 + if (complete != 0xaa || iface_data == 0xff) { 263 + pr_warn("SABI get command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", 264 + command, complete, iface_data); 265 + retval = -EINVAL; 266 + goto exit; 267 + } 268 + /* 269 + * Save off the data into a structure so the caller use it. 270 + * Right now we only want the first 4 bytes, 271 + * There are commands that need more, but not for the ones we 272 + * currently care about. 273 + */ 274 + sretval->retval[0] = readb(sabi_iface + SABI_IFACE_DATA); 275 + sretval->retval[1] = readb(sabi_iface + SABI_IFACE_DATA + 1); 276 + sretval->retval[2] = readb(sabi_iface + SABI_IFACE_DATA + 2); 277 + sretval->retval[3] = readb(sabi_iface + SABI_IFACE_DATA + 3); 278 + 279 + exit: 280 + mutex_unlock(&sabi_mutex); 281 + return retval; 282 + 283 + } 284 + 285 + static int sabi_set_command(u8 command, u8 data) 286 + { 287 + int retval = 0; 288 + u16 port = readw(sabi + sabi_config->header_offsets.port); 289 + u8 complete, iface_data; 290 + 291 + mutex_lock(&sabi_mutex); 292 + 293 + /* enable memory to be able to write to it */ 294 + outb(readb(sabi + sabi_config->header_offsets.en_mem), port); 295 + 296 + /* write out the command */ 297 + writew(sabi_config->main_function, sabi_iface + SABI_IFACE_MAIN); 298 + writew(command, sabi_iface + SABI_IFACE_SUB); 299 + writeb(0, sabi_iface + SABI_IFACE_COMPLETE); 300 + writeb(data, sabi_iface + SABI_IFACE_DATA); 301 + outb(readb(sabi + sabi_config->header_offsets.iface_func), port); 302 + 303 + /* write protect memory to make it safe */ 304 + outb(readb(sabi + sabi_config->header_offsets.re_mem), port); 305 + 306 + /* see if the command actually succeeded */ 307 + complete = readb(sabi_iface + SABI_IFACE_COMPLETE); 308 + iface_data = readb(sabi_iface + SABI_IFACE_DATA); 309 + if (complete != 0xaa || iface_data == 0xff) { 310 + pr_warn("SABI set command 0x%02x failed with completion flag 0x%02x and data 0x%02x\n", 311 + command, complete, iface_data); 312 + retval = -EINVAL; 313 + } 314 + 315 + mutex_unlock(&sabi_mutex); 316 + return retval; 317 + } 318 + 319 + static void test_backlight(void) 320 + { 321 + struct sabi_retval sretval; 322 + 323 + sabi_get_command(sabi_config->commands.get_backlight, &sretval); 324 + printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); 325 + 326 + sabi_set_command(sabi_config->commands.set_backlight, 0); 327 + printk(KERN_DEBUG "backlight should be off\n"); 328 + 329 + sabi_get_command(sabi_config->commands.get_backlight, &sretval); 330 + printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); 331 + 332 + msleep(1000); 333 + 334 + sabi_set_command(sabi_config->commands.set_backlight, 1); 335 + printk(KERN_DEBUG "backlight should be on\n"); 336 + 337 + sabi_get_command(sabi_config->commands.get_backlight, &sretval); 338 + printk(KERN_DEBUG "backlight = 0x%02x\n", sretval.retval[0]); 339 + } 340 + 341 + static void test_wireless(void) 342 + { 343 + struct sabi_retval sretval; 344 + 345 + sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); 346 + printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); 347 + 348 + sabi_set_command(sabi_config->commands.set_wireless_button, 0); 349 + printk(KERN_DEBUG "wireless led should be off\n"); 350 + 351 + sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); 352 + printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); 353 + 354 + msleep(1000); 355 + 356 + sabi_set_command(sabi_config->commands.set_wireless_button, 1); 357 + printk(KERN_DEBUG "wireless led should be on\n"); 358 + 359 + sabi_get_command(sabi_config->commands.get_wireless_button, &sretval); 360 + printk(KERN_DEBUG "wireless led = 0x%02x\n", sretval.retval[0]); 361 + } 362 + 363 + static u8 read_brightness(void) 364 + { 365 + struct sabi_retval sretval; 366 + int user_brightness = 0; 367 + int retval; 368 + 369 + retval = sabi_get_command(sabi_config->commands.get_brightness, 370 + &sretval); 371 + if (!retval) { 372 + user_brightness = sretval.retval[0]; 373 + if (user_brightness != 0) 374 + user_brightness -= sabi_config->min_brightness; 375 + } 376 + return user_brightness; 377 + } 378 + 379 + static void set_brightness(u8 user_brightness) 380 + { 381 + u8 user_level = user_brightness - sabi_config->min_brightness; 382 + 383 + sabi_set_command(sabi_config->commands.set_brightness, user_level); 384 + } 385 + 386 + static int get_brightness(struct backlight_device *bd) 387 + { 388 + return (int)read_brightness(); 389 + } 390 + 391 + static int update_status(struct backlight_device *bd) 392 + { 393 + set_brightness(bd->props.brightness); 394 + 395 + if (bd->props.power == FB_BLANK_UNBLANK) 396 + sabi_set_command(sabi_config->commands.set_backlight, 1); 397 + else 398 + sabi_set_command(sabi_config->commands.set_backlight, 0); 399 + return 0; 400 + } 401 + 402 + static const struct backlight_ops backlight_ops = { 403 + .get_brightness = get_brightness, 404 + .update_status = update_status, 405 + }; 406 + 407 + static int rfkill_set(void *data, bool blocked) 408 + { 409 + /* Do something with blocked...*/ 410 + /* 411 + * blocked == false is on 412 + * blocked == true is off 413 + */ 414 + if (blocked) 415 + sabi_set_command(sabi_config->commands.set_wireless_button, 0); 416 + else 417 + sabi_set_command(sabi_config->commands.set_wireless_button, 1); 418 + 419 + return 0; 420 + } 421 + 422 + static struct rfkill_ops rfkill_ops = { 423 + .set_block = rfkill_set, 424 + }; 425 + 426 + static int init_wireless(struct platform_device *sdev) 427 + { 428 + int retval; 429 + 430 + rfk = rfkill_alloc("samsung-wifi", &sdev->dev, RFKILL_TYPE_WLAN, 431 + &rfkill_ops, NULL); 432 + if (!rfk) 433 + return -ENOMEM; 434 + 435 + retval = rfkill_register(rfk); 436 + if (retval) { 437 + rfkill_destroy(rfk); 438 + return -ENODEV; 439 + } 440 + 441 + return 0; 442 + } 443 + 444 + static void destroy_wireless(void) 445 + { 446 + rfkill_unregister(rfk); 447 + rfkill_destroy(rfk); 448 + } 449 + 450 + static ssize_t get_performance_level(struct device *dev, 451 + struct device_attribute *attr, char *buf) 452 + { 453 + struct sabi_retval sretval; 454 + int retval; 455 + int i; 456 + 457 + /* Read the state */ 458 + retval = sabi_get_command(sabi_config->commands.get_performance_level, 459 + &sretval); 460 + if (retval) 461 + return retval; 462 + 463 + /* The logic is backwards, yeah, lots of fun... */ 464 + for (i = 0; sabi_config->performance_levels[i].name; ++i) { 465 + if (sretval.retval[0] == sabi_config->performance_levels[i].value) 466 + return sprintf(buf, "%s\n", sabi_config->performance_levels[i].name); 467 + } 468 + return sprintf(buf, "%s\n", "unknown"); 469 + } 470 + 471 + static ssize_t set_performance_level(struct device *dev, 472 + struct device_attribute *attr, const char *buf, 473 + size_t count) 474 + { 475 + if (count >= 1) { 476 + int i; 477 + for (i = 0; sabi_config->performance_levels[i].name; ++i) { 478 + const struct sabi_performance_level *level = 479 + &sabi_config->performance_levels[i]; 480 + if (!strncasecmp(level->name, buf, strlen(level->name))) { 481 + sabi_set_command(sabi_config->commands.set_performance_level, 482 + level->value); 483 + break; 484 + } 485 + } 486 + if (!sabi_config->performance_levels[i].name) 487 + return -EINVAL; 488 + } 489 + return count; 490 + } 491 + static DEVICE_ATTR(performance_level, S_IWUSR | S_IRUGO, 492 + get_performance_level, set_performance_level); 493 + 494 + 495 + static int __init dmi_check_cb(const struct dmi_system_id *id) 496 + { 497 + pr_info("found laptop model '%s'\n", 498 + id->ident); 499 + return 1; 500 + } 501 + 502 + static struct dmi_system_id __initdata samsung_dmi_table[] = { 503 + { 504 + .ident = "N128", 505 + .matches = { 506 + DMI_MATCH(DMI_SYS_VENDOR, 507 + "SAMSUNG ELECTRONICS CO., LTD."), 508 + DMI_MATCH(DMI_PRODUCT_NAME, "N128"), 509 + DMI_MATCH(DMI_BOARD_NAME, "N128"), 510 + }, 511 + .callback = dmi_check_cb, 512 + }, 513 + { 514 + .ident = "N130", 515 + .matches = { 516 + DMI_MATCH(DMI_SYS_VENDOR, 517 + "SAMSUNG ELECTRONICS CO., LTD."), 518 + DMI_MATCH(DMI_PRODUCT_NAME, "N130"), 519 + DMI_MATCH(DMI_BOARD_NAME, "N130"), 520 + }, 521 + .callback = dmi_check_cb, 522 + }, 523 + { 524 + .ident = "X125", 525 + .matches = { 526 + DMI_MATCH(DMI_SYS_VENDOR, 527 + "SAMSUNG ELECTRONICS CO., LTD."), 528 + DMI_MATCH(DMI_PRODUCT_NAME, "X125"), 529 + DMI_MATCH(DMI_BOARD_NAME, "X125"), 530 + }, 531 + .callback = dmi_check_cb, 532 + }, 533 + { 534 + .ident = "X120/X170", 535 + .matches = { 536 + DMI_MATCH(DMI_SYS_VENDOR, 537 + "SAMSUNG ELECTRONICS CO., LTD."), 538 + DMI_MATCH(DMI_PRODUCT_NAME, "X120/X170"), 539 + DMI_MATCH(DMI_BOARD_NAME, "X120/X170"), 540 + }, 541 + .callback = dmi_check_cb, 542 + }, 543 + { 544 + .ident = "NC10", 545 + .matches = { 546 + DMI_MATCH(DMI_SYS_VENDOR, 547 + "SAMSUNG ELECTRONICS CO., LTD."), 548 + DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), 549 + DMI_MATCH(DMI_BOARD_NAME, "NC10"), 550 + }, 551 + .callback = dmi_check_cb, 552 + }, 553 + { 554 + .ident = "NP-Q45", 555 + .matches = { 556 + DMI_MATCH(DMI_SYS_VENDOR, 557 + "SAMSUNG ELECTRONICS CO., LTD."), 558 + DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), 559 + DMI_MATCH(DMI_BOARD_NAME, "SQ45S70S"), 560 + }, 561 + .callback = dmi_check_cb, 562 + }, 563 + { 564 + .ident = "X360", 565 + .matches = { 566 + DMI_MATCH(DMI_SYS_VENDOR, 567 + "SAMSUNG ELECTRONICS CO., LTD."), 568 + DMI_MATCH(DMI_PRODUCT_NAME, "X360"), 569 + DMI_MATCH(DMI_BOARD_NAME, "X360"), 570 + }, 571 + .callback = dmi_check_cb, 572 + }, 573 + { 574 + .ident = "R518", 575 + .matches = { 576 + DMI_MATCH(DMI_SYS_VENDOR, 577 + "SAMSUNG ELECTRONICS CO., LTD."), 578 + DMI_MATCH(DMI_PRODUCT_NAME, "R518"), 579 + DMI_MATCH(DMI_BOARD_NAME, "R518"), 580 + }, 581 + .callback = dmi_check_cb, 582 + }, 583 + { 584 + .ident = "R519/R719", 585 + .matches = { 586 + DMI_MATCH(DMI_SYS_VENDOR, 587 + "SAMSUNG ELECTRONICS CO., LTD."), 588 + DMI_MATCH(DMI_PRODUCT_NAME, "R519/R719"), 589 + DMI_MATCH(DMI_BOARD_NAME, "R519/R719"), 590 + }, 591 + .callback = dmi_check_cb, 592 + }, 593 + { 594 + .ident = "N150/N210/N220", 595 + .matches = { 596 + DMI_MATCH(DMI_SYS_VENDOR, 597 + "SAMSUNG ELECTRONICS CO., LTD."), 598 + DMI_MATCH(DMI_PRODUCT_NAME, "N150/N210/N220"), 599 + DMI_MATCH(DMI_BOARD_NAME, "N150/N210/N220"), 600 + }, 601 + .callback = dmi_check_cb, 602 + }, 603 + { 604 + .ident = "N150P/N210P/N220P", 605 + .matches = { 606 + DMI_MATCH(DMI_SYS_VENDOR, 607 + "SAMSUNG ELECTRONICS CO., LTD."), 608 + DMI_MATCH(DMI_PRODUCT_NAME, "N150P/N210P/N220P"), 609 + DMI_MATCH(DMI_BOARD_NAME, "N150P/N210P/N220P"), 610 + }, 611 + .callback = dmi_check_cb, 612 + }, 613 + { 614 + .ident = "R530/R730", 615 + .matches = { 616 + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 617 + DMI_MATCH(DMI_PRODUCT_NAME, "R530/R730"), 618 + DMI_MATCH(DMI_BOARD_NAME, "R530/R730"), 619 + }, 620 + .callback = dmi_check_cb, 621 + }, 622 + { 623 + .ident = "NF110/NF210/NF310", 624 + .matches = { 625 + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 626 + DMI_MATCH(DMI_PRODUCT_NAME, "NF110/NF210/NF310"), 627 + DMI_MATCH(DMI_BOARD_NAME, "NF110/NF210/NF310"), 628 + }, 629 + .callback = dmi_check_cb, 630 + }, 631 + { 632 + .ident = "N145P/N250P/N260P", 633 + .matches = { 634 + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 635 + DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"), 636 + DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"), 637 + }, 638 + .callback = dmi_check_cb, 639 + }, 640 + { 641 + .ident = "R70/R71", 642 + .matches = { 643 + DMI_MATCH(DMI_SYS_VENDOR, 644 + "SAMSUNG ELECTRONICS CO., LTD."), 645 + DMI_MATCH(DMI_PRODUCT_NAME, "R70/R71"), 646 + DMI_MATCH(DMI_BOARD_NAME, "R70/R71"), 647 + }, 648 + .callback = dmi_check_cb, 649 + }, 650 + { 651 + .ident = "P460", 652 + .matches = { 653 + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), 654 + DMI_MATCH(DMI_PRODUCT_NAME, "P460"), 655 + DMI_MATCH(DMI_BOARD_NAME, "P460"), 656 + }, 657 + .callback = dmi_check_cb, 658 + }, 659 + { }, 660 + }; 661 + MODULE_DEVICE_TABLE(dmi, samsung_dmi_table); 662 + 663 + static int find_signature(void __iomem *memcheck, const char *testStr) 664 + { 665 + int i = 0; 666 + int loca; 667 + 668 + for (loca = 0; loca < 0xffff; loca++) { 669 + char temp = readb(memcheck + loca); 670 + 671 + if (temp == testStr[i]) { 672 + if (i == strlen(testStr)-1) 673 + break; 674 + ++i; 675 + } else { 676 + i = 0; 677 + } 678 + } 679 + return loca; 680 + } 681 + 682 + static int __init samsung_init(void) 683 + { 684 + struct backlight_properties props; 685 + struct sabi_retval sretval; 686 + unsigned int ifaceP; 687 + int i; 688 + int loca; 689 + int retval; 690 + 691 + mutex_init(&sabi_mutex); 692 + 693 + if (!force && !dmi_check_system(samsung_dmi_table)) 694 + return -ENODEV; 695 + 696 + f0000_segment = ioremap_nocache(0xf0000, 0xffff); 697 + if (!f0000_segment) { 698 + pr_err("Can't map the segment at 0xf0000\n"); 699 + return -EINVAL; 700 + } 701 + 702 + /* Try to find one of the signatures in memory to find the header */ 703 + for (i = 0; sabi_configs[i].test_string != 0; ++i) { 704 + sabi_config = &sabi_configs[i]; 705 + loca = find_signature(f0000_segment, sabi_config->test_string); 706 + if (loca != 0xffff) 707 + break; 708 + } 709 + 710 + if (loca == 0xffff) { 711 + pr_err("This computer does not support SABI\n"); 712 + goto error_no_signature; 713 + } 714 + 715 + /* point to the SMI port Number */ 716 + loca += 1; 717 + sabi = (f0000_segment + loca); 718 + 719 + if (debug) { 720 + printk(KERN_DEBUG "This computer supports SABI==%x\n", 721 + loca + 0xf0000 - 6); 722 + printk(KERN_DEBUG "SABI header:\n"); 723 + printk(KERN_DEBUG " SMI Port Number = 0x%04x\n", 724 + readw(sabi + sabi_config->header_offsets.port)); 725 + printk(KERN_DEBUG " SMI Interface Function = 0x%02x\n", 726 + readb(sabi + sabi_config->header_offsets.iface_func)); 727 + printk(KERN_DEBUG " SMI enable memory buffer = 0x%02x\n", 728 + readb(sabi + sabi_config->header_offsets.en_mem)); 729 + printk(KERN_DEBUG " SMI restore memory buffer = 0x%02x\n", 730 + readb(sabi + sabi_config->header_offsets.re_mem)); 731 + printk(KERN_DEBUG " SABI data offset = 0x%04x\n", 732 + readw(sabi + sabi_config->header_offsets.data_offset)); 733 + printk(KERN_DEBUG " SABI data segment = 0x%04x\n", 734 + readw(sabi + sabi_config->header_offsets.data_segment)); 735 + } 736 + 737 + /* Get a pointer to the SABI Interface */ 738 + ifaceP = (readw(sabi + sabi_config->header_offsets.data_segment) & 0x0ffff) << 4; 739 + ifaceP += readw(sabi + sabi_config->header_offsets.data_offset) & 0x0ffff; 740 + sabi_iface = ioremap_nocache(ifaceP, 16); 741 + if (!sabi_iface) { 742 + pr_err("Can't remap %x\n", ifaceP); 743 + goto exit; 744 + } 745 + if (debug) { 746 + printk(KERN_DEBUG "ifaceP = 0x%08x\n", ifaceP); 747 + printk(KERN_DEBUG "sabi_iface = %p\n", sabi_iface); 748 + 749 + test_backlight(); 750 + test_wireless(); 751 + 752 + retval = sabi_get_command(sabi_config->commands.get_brightness, 753 + &sretval); 754 + printk(KERN_DEBUG "brightness = 0x%02x\n", sretval.retval[0]); 755 + } 756 + 757 + /* Turn on "Linux" mode in the BIOS */ 758 + if (sabi_config->commands.set_linux != 0xff) { 759 + retval = sabi_set_command(sabi_config->commands.set_linux, 760 + 0x81); 761 + if (retval) { 762 + pr_warn("Linux mode was not set!\n"); 763 + goto error_no_platform; 764 + } 765 + } 766 + 767 + /* knock up a platform device to hang stuff off of */ 768 + sdev = platform_device_register_simple("samsung", -1, NULL, 0); 769 + if (IS_ERR(sdev)) 770 + goto error_no_platform; 771 + 772 + /* create a backlight device to talk to this one */ 773 + memset(&props, 0, sizeof(struct backlight_properties)); 774 + props.max_brightness = sabi_config->max_brightness; 775 + backlight_device = backlight_device_register("samsung", &sdev->dev, 776 + NULL, &backlight_ops, 777 + &props); 778 + if (IS_ERR(backlight_device)) 779 + goto error_no_backlight; 780 + 781 + backlight_device->props.brightness = read_brightness(); 782 + backlight_device->props.power = FB_BLANK_UNBLANK; 783 + backlight_update_status(backlight_device); 784 + 785 + retval = init_wireless(sdev); 786 + if (retval) 787 + goto error_no_rfk; 788 + 789 + retval = device_create_file(&sdev->dev, &dev_attr_performance_level); 790 + if (retval) 791 + goto error_file_create; 792 + 793 + exit: 794 + return 0; 795 + 796 + error_file_create: 797 + destroy_wireless(); 798 + 799 + error_no_rfk: 800 + backlight_device_unregister(backlight_device); 801 + 802 + error_no_backlight: 803 + platform_device_unregister(sdev); 804 + 805 + error_no_platform: 806 + iounmap(sabi_iface); 807 + 808 + error_no_signature: 809 + iounmap(f0000_segment); 810 + return -EINVAL; 811 + } 812 + 813 + static void __exit samsung_exit(void) 814 + { 815 + /* Turn off "Linux" mode in the BIOS */ 816 + if (sabi_config->commands.set_linux != 0xff) 817 + sabi_set_command(sabi_config->commands.set_linux, 0x80); 818 + 819 + device_remove_file(&sdev->dev, &dev_attr_performance_level); 820 + backlight_device_unregister(backlight_device); 821 + destroy_wireless(); 822 + iounmap(sabi_iface); 823 + iounmap(f0000_segment); 824 + platform_device_unregister(sdev); 825 + } 826 + 827 + module_init(samsung_init); 828 + module_exit(samsung_exit); 829 + 830 + MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>"); 831 + MODULE_DESCRIPTION("Samsung Backlight driver"); 832 + MODULE_LICENSE("GPL");
+402 -103
drivers/platform/x86/sony-laptop.c
··· 71 71 #endif 72 72 73 73 #define DRV_PFX "sony-laptop: " 74 - #define dprintk(msg...) do { \ 75 - if (debug) printk(KERN_WARNING DRV_PFX msg); \ 74 + #define dprintk(msg...) do { \ 75 + if (debug) \ 76 + pr_warn(DRV_PFX msg); \ 76 77 } while (0) 77 78 78 79 #define SONY_LAPTOP_DRIVER_VERSION "0.6" ··· 124 123 "minor number of the misc device for the SPIC compatibility code, " 125 124 "default is -1 (automatic)"); 126 125 #endif 126 + 127 + static int kbd_backlight; /* = 1 */ 128 + module_param(kbd_backlight, int, 0444); 129 + MODULE_PARM_DESC(kbd_backlight, 130 + "set this to 0 to disable keyboard backlight, " 131 + "1 to enable it (default: 0)"); 132 + 133 + static int kbd_backlight_timeout; /* = 0 */ 134 + module_param(kbd_backlight_timeout, int, 0444); 135 + MODULE_PARM_DESC(kbd_backlight_timeout, 136 + "set this to 0 to set the default 10 seconds timeout, " 137 + "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout " 138 + "(default: 0)"); 127 139 128 140 enum sony_nc_rfkill { 129 141 SONY_WIFI, ··· 416 402 error = kfifo_alloc(&sony_laptop_input.fifo, 417 403 SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); 418 404 if (error) { 419 - printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 405 + pr_err(DRV_PFX "kfifo_alloc failed\n"); 420 406 goto err_dec_users; 421 407 } 422 408 ··· 605 591 int value; /* current setting */ 606 592 int valid; /* Has ever been set */ 607 593 int debug; /* active only in debug mode ? */ 608 - struct device_attribute devattr; /* sysfs atribute */ 594 + struct device_attribute devattr; /* sysfs attribute */ 609 595 }; 610 596 611 597 #define SNC_HANDLE_NAMES(_name, _values...) \ ··· 700 686 return 0; 701 687 } 702 688 703 - printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); 689 + pr_warn(DRV_PFX "acpi_callreadfunc failed\n"); 704 690 705 691 return -1; 706 692 } ··· 726 712 if (status == AE_OK) { 727 713 if (result != NULL) { 728 714 if (out_obj.type != ACPI_TYPE_INTEGER) { 729 - printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " 715 + pr_warn(DRV_PFX "acpi_evaluate_object bad " 730 716 "return type\n"); 731 717 return -1; 732 718 } ··· 735 721 return 0; 736 722 } 737 723 738 - printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); 724 + pr_warn(DRV_PFX "acpi_evaluate_object failed\n"); 739 725 740 726 return -1; 727 + } 728 + 729 + struct sony_nc_handles { 730 + u16 cap[0x10]; 731 + struct device_attribute devattr; 732 + }; 733 + 734 + static struct sony_nc_handles *handles; 735 + 736 + static ssize_t sony_nc_handles_show(struct device *dev, 737 + struct device_attribute *attr, char *buffer) 738 + { 739 + ssize_t len = 0; 740 + int i; 741 + 742 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 743 + len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ", 744 + handles->cap[i]); 745 + } 746 + len += snprintf(buffer + len, PAGE_SIZE - len, "\n"); 747 + 748 + return len; 749 + } 750 + 751 + static int sony_nc_handles_setup(struct platform_device *pd) 752 + { 753 + int i; 754 + int result; 755 + 756 + handles = kzalloc(sizeof(*handles), GFP_KERNEL); 757 + if (!handles) 758 + return -ENOMEM; 759 + 760 + sysfs_attr_init(&handles->devattr.attr); 761 + handles->devattr.attr.name = "handles"; 762 + handles->devattr.attr.mode = S_IRUGO; 763 + handles->devattr.show = sony_nc_handles_show; 764 + 765 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 766 + if (!acpi_callsetfunc(sony_nc_acpi_handle, 767 + "SN00", i + 0x20, &result)) { 768 + dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", 769 + result, i); 770 + handles->cap[i] = result; 771 + } 772 + } 773 + 774 + /* allow reading capabilities via sysfs */ 775 + if (device_create_file(&pd->dev, &handles->devattr)) { 776 + kfree(handles); 777 + handles = NULL; 778 + return -1; 779 + } 780 + 781 + return 0; 782 + } 783 + 784 + static int sony_nc_handles_cleanup(struct platform_device *pd) 785 + { 786 + if (handles) { 787 + device_remove_file(&pd->dev, &handles->devattr); 788 + kfree(handles); 789 + handles = NULL; 790 + } 791 + return 0; 741 792 } 742 793 743 794 static int sony_find_snc_handle(int handle) 744 795 { 745 796 int i; 746 - int result; 747 - 748 - for (i = 0x20; i < 0x30; i++) { 749 - acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result); 750 - if (result == handle) 751 - return i-0x20; 797 + for (i = 0; i < 0x10; i++) { 798 + if (handles->cap[i] == handle) { 799 + dprintk("found handle 0x%.4x (offset: 0x%.2x)\n", 800 + handle, i); 801 + return i; 802 + } 752 803 } 753 - 804 + dprintk("handle 0x%.4x not found\n", handle); 754 805 return -1; 755 806 } 756 807 757 808 static int sony_call_snc_handle(int handle, int argument, int *result) 758 809 { 810 + int ret = 0; 759 811 int offset = sony_find_snc_handle(handle); 760 812 761 813 if (offset < 0) 762 814 return -1; 763 815 764 - return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, 765 - result); 816 + ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, 817 + result); 818 + dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, 819 + *result); 820 + return ret; 766 821 } 767 822 768 823 /* ··· 940 857 return value - 1; 941 858 } 942 859 943 - static struct backlight_device *sony_backlight_device; 860 + static int sony_nc_get_brightness_ng(struct backlight_device *bd) 861 + { 862 + int result; 863 + int *handle = (int *)bl_get_data(bd); 864 + 865 + sony_call_snc_handle(*handle, 0x0200, &result); 866 + 867 + return result & 0xff; 868 + } 869 + 870 + static int sony_nc_update_status_ng(struct backlight_device *bd) 871 + { 872 + int value, result; 873 + int *handle = (int *)bl_get_data(bd); 874 + 875 + value = bd->props.brightness; 876 + sony_call_snc_handle(*handle, 0x0100 | (value << 16), &result); 877 + 878 + return sony_nc_get_brightness_ng(bd); 879 + } 880 + 944 881 static const struct backlight_ops sony_backlight_ops = { 882 + .options = BL_CORE_SUSPENDRESUME, 945 883 .update_status = sony_backlight_update_status, 946 884 .get_brightness = sony_backlight_get_brightness, 947 885 }; 886 + static const struct backlight_ops sony_backlight_ng_ops = { 887 + .options = BL_CORE_SUSPENDRESUME, 888 + .update_status = sony_nc_update_status_ng, 889 + .get_brightness = sony_nc_get_brightness_ng, 890 + }; 891 + static int backlight_ng_handle; 892 + static struct backlight_device *sony_backlight_device; 948 893 949 894 /* 950 895 * New SNC-only Vaios event mapping to driver known keys ··· 1083 972 } 1084 973 1085 974 if (!key_event->data) 1086 - printk(KERN_INFO DRV_PFX 975 + pr_info(DRV_PFX 1087 976 "Unknown event: 0x%x 0x%x\n", 1088 977 key_handle, 1089 978 ev); ··· 1107 996 struct acpi_device_info *info; 1108 997 1109 998 if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) { 1110 - printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", 999 + pr_warn(DRV_PFX "method: name: %4.4s, args %X\n", 1111 1000 (char *)&info->name, info->param_count); 1112 1001 1113 1002 kfree(info); ··· 1148 1037 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, 1149 1038 item->value, NULL); 1150 1039 if (ret < 0) { 1151 - printk("%s: %d\n", __func__, ret); 1040 + pr_err(DRV_PFX "%s: %d\n", __func__, ret); 1152 1041 break; 1153 1042 } 1154 1043 } ··· 1164 1053 dprintk("Doing SNC setup\n"); 1165 1054 sony_nc_function_setup(device); 1166 1055 } 1167 - 1168 - /* set the last requested brightness level */ 1169 - if (sony_backlight_device && 1170 - sony_backlight_update_status(sony_backlight_device) < 0) 1171 - printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n"); 1172 1056 1173 1057 /* re-read rfkill state */ 1174 1058 sony_nc_rfkill_update(); ··· 1312 1206 1313 1207 device_enum = (union acpi_object *) buffer.pointer; 1314 1208 if (!device_enum) { 1315 - pr_err("Invalid SN06 return object\n"); 1209 + pr_err(DRV_PFX "No SN06 return object."); 1316 1210 goto out_no_enum; 1317 1211 } 1318 1212 if (device_enum->type != ACPI_TYPE_BUFFER) { 1319 - pr_err("Invalid SN06 return object type 0x%.2x\n", 1320 - device_enum->type); 1213 + pr_err(DRV_PFX "Invalid SN06 return object 0x%.2x\n", 1214 + device_enum->type); 1321 1215 goto out_no_enum; 1322 1216 } 1323 1217 ··· 1351 1245 return; 1352 1246 } 1353 1247 1248 + /* Keyboard backlight feature */ 1249 + #define KBDBL_HANDLER 0x137 1250 + #define KBDBL_PRESENT 0xB00 1251 + #define SET_MODE 0xC00 1252 + #define SET_TIMEOUT 0xE00 1253 + 1254 + struct kbd_backlight { 1255 + int mode; 1256 + int timeout; 1257 + struct device_attribute mode_attr; 1258 + struct device_attribute timeout_attr; 1259 + }; 1260 + 1261 + static struct kbd_backlight *kbdbl_handle; 1262 + 1263 + static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) 1264 + { 1265 + int result; 1266 + 1267 + if (value > 1) 1268 + return -EINVAL; 1269 + 1270 + if (sony_call_snc_handle(KBDBL_HANDLER, 1271 + (value << 0x10) | SET_MODE, &result)) 1272 + return -EIO; 1273 + 1274 + kbdbl_handle->mode = value; 1275 + 1276 + return 0; 1277 + } 1278 + 1279 + static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev, 1280 + struct device_attribute *attr, 1281 + const char *buffer, size_t count) 1282 + { 1283 + int ret = 0; 1284 + unsigned long value; 1285 + 1286 + if (count > 31) 1287 + return -EINVAL; 1288 + 1289 + if (strict_strtoul(buffer, 10, &value)) 1290 + return -EINVAL; 1291 + 1292 + ret = __sony_nc_kbd_backlight_mode_set(value); 1293 + if (ret < 0) 1294 + return ret; 1295 + 1296 + return count; 1297 + } 1298 + 1299 + static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev, 1300 + struct device_attribute *attr, char *buffer) 1301 + { 1302 + ssize_t count = 0; 1303 + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); 1304 + return count; 1305 + } 1306 + 1307 + static int __sony_nc_kbd_backlight_timeout_set(u8 value) 1308 + { 1309 + int result; 1310 + 1311 + if (value > 3) 1312 + return -EINVAL; 1313 + 1314 + if (sony_call_snc_handle(KBDBL_HANDLER, 1315 + (value << 0x10) | SET_TIMEOUT, &result)) 1316 + return -EIO; 1317 + 1318 + kbdbl_handle->timeout = value; 1319 + 1320 + return 0; 1321 + } 1322 + 1323 + static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev, 1324 + struct device_attribute *attr, 1325 + const char *buffer, size_t count) 1326 + { 1327 + int ret = 0; 1328 + unsigned long value; 1329 + 1330 + if (count > 31) 1331 + return -EINVAL; 1332 + 1333 + if (strict_strtoul(buffer, 10, &value)) 1334 + return -EINVAL; 1335 + 1336 + ret = __sony_nc_kbd_backlight_timeout_set(value); 1337 + if (ret < 0) 1338 + return ret; 1339 + 1340 + return count; 1341 + } 1342 + 1343 + static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev, 1344 + struct device_attribute *attr, char *buffer) 1345 + { 1346 + ssize_t count = 0; 1347 + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); 1348 + return count; 1349 + } 1350 + 1351 + static int sony_nc_kbd_backlight_setup(struct platform_device *pd) 1352 + { 1353 + int result; 1354 + 1355 + if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result)) 1356 + return 0; 1357 + if (!(result & 0x02)) 1358 + return 0; 1359 + 1360 + kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); 1361 + if (!kbdbl_handle) 1362 + return -ENOMEM; 1363 + 1364 + sysfs_attr_init(&kbdbl_handle->mode_attr.attr); 1365 + kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; 1366 + kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; 1367 + kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; 1368 + kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; 1369 + 1370 + sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); 1371 + kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; 1372 + kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; 1373 + kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; 1374 + kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; 1375 + 1376 + if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) 1377 + goto outkzalloc; 1378 + 1379 + if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) 1380 + goto outmode; 1381 + 1382 + __sony_nc_kbd_backlight_mode_set(kbd_backlight); 1383 + __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout); 1384 + 1385 + return 0; 1386 + 1387 + outmode: 1388 + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1389 + outkzalloc: 1390 + kfree(kbdbl_handle); 1391 + kbdbl_handle = NULL; 1392 + return -1; 1393 + } 1394 + 1395 + static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) 1396 + { 1397 + if (kbdbl_handle) { 1398 + device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1399 + device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); 1400 + kfree(kbdbl_handle); 1401 + } 1402 + return 0; 1403 + } 1404 + 1405 + static void sony_nc_backlight_setup(void) 1406 + { 1407 + acpi_handle unused; 1408 + int max_brightness = 0; 1409 + const struct backlight_ops *ops = NULL; 1410 + struct backlight_properties props; 1411 + 1412 + if (sony_find_snc_handle(0x12f) != -1) { 1413 + backlight_ng_handle = 0x12f; 1414 + ops = &sony_backlight_ng_ops; 1415 + max_brightness = 0xff; 1416 + 1417 + } else if (sony_find_snc_handle(0x137) != -1) { 1418 + backlight_ng_handle = 0x137; 1419 + ops = &sony_backlight_ng_ops; 1420 + max_brightness = 0xff; 1421 + 1422 + } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", 1423 + &unused))) { 1424 + ops = &sony_backlight_ops; 1425 + max_brightness = SONY_MAX_BRIGHTNESS - 1; 1426 + 1427 + } else 1428 + return; 1429 + 1430 + memset(&props, 0, sizeof(struct backlight_properties)); 1431 + props.type = BACKLIGHT_PLATFORM; 1432 + props.max_brightness = max_brightness; 1433 + sony_backlight_device = backlight_device_register("sony", NULL, 1434 + &backlight_ng_handle, 1435 + ops, &props); 1436 + 1437 + if (IS_ERR(sony_backlight_device)) { 1438 + pr_warning(DRV_PFX "unable to register backlight device\n"); 1439 + sony_backlight_device = NULL; 1440 + } else 1441 + sony_backlight_device->props.brightness = 1442 + ops->get_brightness(sony_backlight_device); 1443 + } 1444 + 1445 + static void sony_nc_backlight_cleanup(void) 1446 + { 1447 + if (sony_backlight_device) 1448 + backlight_device_unregister(sony_backlight_device); 1449 + } 1450 + 1354 1451 static int sony_nc_add(struct acpi_device *device) 1355 1452 { 1356 1453 acpi_status status; ··· 1561 1252 acpi_handle handle; 1562 1253 struct sony_nc_value *item; 1563 1254 1564 - printk(KERN_INFO DRV_PFX "%s v%s.\n", 1565 - SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 1255 + pr_info(DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME, 1256 + SONY_LAPTOP_DRIVER_VERSION); 1566 1257 1567 1258 sony_nc_acpi_device = device; 1568 1259 strcpy(acpi_device_class(device), "sony/hotkey"); ··· 1578 1269 goto outwalk; 1579 1270 } 1580 1271 1272 + result = sony_pf_add(); 1273 + if (result) 1274 + goto outpresent; 1275 + 1581 1276 if (debug) { 1582 - status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle, 1583 - 1, sony_walk_callback, NULL, NULL, NULL); 1277 + status = acpi_walk_namespace(ACPI_TYPE_METHOD, 1278 + sony_nc_acpi_handle, 1, sony_walk_callback, 1279 + NULL, NULL, NULL); 1584 1280 if (ACPI_FAILURE(status)) { 1585 - printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n"); 1281 + pr_warn(DRV_PFX "unable to walk acpi resources\n"); 1586 1282 result = -ENODEV; 1587 - goto outwalk; 1283 + goto outpresent; 1588 1284 } 1589 1285 } 1590 1286 ··· 1602 1288 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 1603 1289 &handle))) { 1604 1290 dprintk("Doing SNC setup\n"); 1291 + result = sony_nc_handles_setup(sony_pf_device); 1292 + if (result) 1293 + goto outpresent; 1294 + result = sony_nc_kbd_backlight_setup(sony_pf_device); 1295 + if (result) 1296 + goto outsnc; 1605 1297 sony_nc_function_setup(device); 1606 1298 sony_nc_rfkill_setup(device); 1607 1299 } ··· 1615 1295 /* setup input devices and helper fifo */ 1616 1296 result = sony_laptop_setup_input(device); 1617 1297 if (result) { 1618 - printk(KERN_ERR DRV_PFX 1619 - "Unable to create input devices.\n"); 1620 - goto outwalk; 1298 + pr_err(DRV_PFX "Unable to create input devices.\n"); 1299 + goto outkbdbacklight; 1621 1300 } 1622 1301 1623 1302 if (acpi_video_backlight_support()) { 1624 - printk(KERN_INFO DRV_PFX "brightness ignored, must be " 1303 + pr_info(DRV_PFX "brightness ignored, must be " 1625 1304 "controlled by ACPI video driver\n"); 1626 - } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT", 1627 - &handle))) { 1628 - struct backlight_properties props; 1629 - memset(&props, 0, sizeof(struct backlight_properties)); 1630 - props.type = BACKLIGHT_PLATFORM; 1631 - props.max_brightness = SONY_MAX_BRIGHTNESS - 1; 1632 - sony_backlight_device = backlight_device_register("sony", NULL, 1633 - NULL, 1634 - &sony_backlight_ops, 1635 - &props); 1636 - 1637 - if (IS_ERR(sony_backlight_device)) { 1638 - printk(KERN_WARNING DRV_PFX "unable to register backlight device\n"); 1639 - sony_backlight_device = NULL; 1640 - } else { 1641 - sony_backlight_device->props.brightness = 1642 - sony_backlight_get_brightness 1643 - (sony_backlight_device); 1644 - } 1645 - 1305 + } else { 1306 + sony_nc_backlight_setup(); 1646 1307 } 1647 - 1648 - result = sony_pf_add(); 1649 - if (result) 1650 - goto outbacklight; 1651 1308 1652 1309 /* create sony_pf sysfs attributes related to the SNC device */ 1653 1310 for (item = sony_nc_values; item->name; ++item) { ··· 1671 1374 for (item = sony_nc_values; item->name; ++item) { 1672 1375 device_remove_file(&sony_pf_device->dev, &item->devattr); 1673 1376 } 1674 - sony_pf_remove(); 1675 - 1676 - outbacklight: 1677 - if (sony_backlight_device) 1678 - backlight_device_unregister(sony_backlight_device); 1377 + sony_nc_backlight_cleanup(); 1679 1378 1680 1379 sony_laptop_remove_input(); 1380 + 1381 + outkbdbacklight: 1382 + sony_nc_kbd_backlight_cleanup(sony_pf_device); 1383 + 1384 + outsnc: 1385 + sony_nc_handles_cleanup(sony_pf_device); 1386 + 1387 + outpresent: 1388 + sony_pf_remove(); 1681 1389 1682 1390 outwalk: 1683 1391 sony_nc_rfkill_cleanup(); ··· 1693 1391 { 1694 1392 struct sony_nc_value *item; 1695 1393 1696 - if (sony_backlight_device) 1697 - backlight_device_unregister(sony_backlight_device); 1394 + sony_nc_backlight_cleanup(); 1698 1395 1699 1396 sony_nc_acpi_device = NULL; 1700 1397 ··· 1701 1400 device_remove_file(&sony_pf_device->dev, &item->devattr); 1702 1401 } 1703 1402 1403 + sony_nc_kbd_backlight_cleanup(sony_pf_device); 1404 + sony_nc_handles_cleanup(sony_pf_device); 1704 1405 sony_pf_remove(); 1705 1406 sony_laptop_remove_input(); 1706 1407 sony_nc_rfkill_cleanup(); ··· 1741 1438 #define SONYPI_DEVICE_TYPE1 0x00000001 1742 1439 #define SONYPI_DEVICE_TYPE2 0x00000002 1743 1440 #define SONYPI_DEVICE_TYPE3 0x00000004 1744 - #define SONYPI_DEVICE_TYPE4 0x00000008 1745 1441 1746 1442 #define SONYPI_TYPE1_OFFSET 0x04 1747 1443 #define SONYPI_TYPE2_OFFSET 0x12 ··· 1886 1584 1887 1585 /* The set of possible wireless events */ 1888 1586 static struct sonypi_event sonypi_wlessev[] = { 1889 - { 0x59, SONYPI_EVENT_WIRELESS_ON }, 1890 - { 0x5a, SONYPI_EVENT_WIRELESS_OFF }, 1587 + { 0x59, SONYPI_EVENT_IGNORE }, 1588 + { 0x5a, SONYPI_EVENT_IGNORE }, 1891 1589 { 0, 0 } 1892 1590 }; 1893 1591 ··· 2144 1842 if (pcidev) 2145 1843 pci_dev_put(pcidev); 2146 1844 2147 - printk(KERN_INFO DRV_PFX "detected Type%d model\n", 1845 + pr_info(DRV_PFX "detected Type%d model\n", 2148 1846 dev->model == SONYPI_DEVICE_TYPE1 ? 1 : 2149 1847 dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3); 2150 1848 } ··· 2192 1890 static int __sony_pic_camera_off(void) 2193 1891 { 2194 1892 if (!camera) { 2195 - printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 1893 + pr_warn(DRV_PFX "camera control not enabled\n"); 2196 1894 return -ENODEV; 2197 1895 } 2198 1896 ··· 2212 1910 int i, j, x; 2213 1911 2214 1912 if (!camera) { 2215 - printk(KERN_WARNING DRV_PFX "camera control not enabled\n"); 1913 + pr_warn(DRV_PFX "camera control not enabled\n"); 2216 1914 return -ENODEV; 2217 1915 } 2218 1916 ··· 2235 1933 } 2236 1934 2237 1935 if (j == 0) { 2238 - printk(KERN_WARNING DRV_PFX "failed to power on camera\n"); 1936 + pr_warn(DRV_PFX "failed to power on camera\n"); 2239 1937 return -ENODEV; 2240 1938 } 2241 1939 ··· 2291 1989 ITERATIONS_SHORT); 2292 1990 break; 2293 1991 default: 2294 - printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n", 1992 + pr_err(DRV_PFX "sony_pic_camera_command invalid: %d\n", 2295 1993 command); 2296 1994 break; 2297 1995 } ··· 2698 2396 error = 2699 2397 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL); 2700 2398 if (error) { 2701 - printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n"); 2399 + pr_err(DRV_PFX "kfifo_alloc failed\n"); 2702 2400 return error; 2703 2401 } 2704 2402 ··· 2708 2406 sonypi_misc_device.minor = minor; 2709 2407 error = misc_register(&sonypi_misc_device); 2710 2408 if (error) { 2711 - printk(KERN_ERR DRV_PFX "misc_register failed\n"); 2409 + pr_err(DRV_PFX "misc_register failed\n"); 2712 2410 goto err_free_kfifo; 2713 2411 } 2714 2412 if (minor == -1) 2715 - printk(KERN_INFO DRV_PFX "device allocated minor is %d\n", 2413 + pr_info(DRV_PFX "device allocated minor is %d\n", 2716 2414 sonypi_misc_device.minor); 2717 2415 2718 2416 return 0; ··· 2772 2470 } 2773 2471 for (i = 0; i < p->interrupt_count; i++) { 2774 2472 if (!p->interrupts[i]) { 2775 - printk(KERN_WARNING DRV_PFX 2776 - "Invalid IRQ %d\n", 2473 + pr_warn(DRV_PFX "Invalid IRQ %d\n", 2777 2474 p->interrupts[i]); 2778 2475 continue; 2779 2476 } ··· 2811 2510 ioport->io2.address_length); 2812 2511 } 2813 2512 else { 2814 - printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); 2513 + pr_err(DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n"); 2815 2514 return AE_ERROR; 2816 2515 } 2817 2516 return AE_OK; ··· 2839 2538 dprintk("Evaluating _STA\n"); 2840 2539 result = acpi_bus_get_status(device); 2841 2540 if (result) { 2842 - printk(KERN_WARNING DRV_PFX "Unable to read status\n"); 2541 + pr_warn(DRV_PFX "Unable to read status\n"); 2843 2542 goto end; 2844 2543 } 2845 2544 ··· 2855 2554 status = acpi_walk_resources(device->handle, METHOD_NAME__PRS, 2856 2555 sony_pic_read_possible_resource, &spic_dev); 2857 2556 if (ACPI_FAILURE(status)) { 2858 - printk(KERN_WARNING DRV_PFX 2859 - "Failure evaluating %s\n", 2557 + pr_warn(DRV_PFX "Failure evaluating %s\n", 2860 2558 METHOD_NAME__PRS); 2861 2559 result = -ENODEV; 2862 2560 } ··· 2969 2669 2970 2670 /* check for total failure */ 2971 2671 if (ACPI_FAILURE(status)) { 2972 - printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n"); 2672 + pr_err(DRV_PFX "Error evaluating _SRS\n"); 2973 2673 result = -ENODEV; 2974 2674 goto end; 2975 2675 } ··· 3025 2725 if (ev == dev->event_types[i].events[j].data) { 3026 2726 device_event = 3027 2727 dev->event_types[i].events[j].event; 2728 + /* some events may require ignoring */ 2729 + if (!device_event) 2730 + return IRQ_HANDLED; 3028 2731 goto found; 3029 2732 } 3030 2733 } ··· 3047 2744 sony_laptop_report_input_event(device_event); 3048 2745 acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event); 3049 2746 sonypi_compat_report_event(device_event); 3050 - 3051 2747 return IRQ_HANDLED; 3052 2748 } 3053 2749 ··· 3061 2759 struct sony_pic_irq *irq, *tmp_irq; 3062 2760 3063 2761 if (sony_pic_disable(device)) { 3064 - printk(KERN_ERR DRV_PFX "Couldn't disable device.\n"); 2762 + pr_err(DRV_PFX "Couldn't disable device.\n"); 3065 2763 return -ENXIO; 3066 2764 } 3067 2765 ··· 3101 2799 struct sony_pic_ioport *io, *tmp_io; 3102 2800 struct sony_pic_irq *irq, *tmp_irq; 3103 2801 3104 - printk(KERN_INFO DRV_PFX "%s v%s.\n", 3105 - SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION); 2802 + pr_info(DRV_PFX "%s v%s.\n", SONY_PIC_DRIVER_NAME, 2803 + SONY_LAPTOP_DRIVER_VERSION); 3106 2804 3107 2805 spic_dev.acpi_dev = device; 3108 2806 strcpy(acpi_device_class(device), "sony/hotkey"); ··· 3112 2810 /* read _PRS resources */ 3113 2811 result = sony_pic_possible_resources(device); 3114 2812 if (result) { 3115 - printk(KERN_ERR DRV_PFX 3116 - "Unable to read possible resources.\n"); 2813 + pr_err(DRV_PFX "Unable to read possible resources.\n"); 3117 2814 goto err_free_resources; 3118 2815 } 3119 2816 3120 2817 /* setup input devices and helper fifo */ 3121 2818 result = sony_laptop_setup_input(device); 3122 2819 if (result) { 3123 - printk(KERN_ERR DRV_PFX 3124 - "Unable to create input devices.\n"); 2820 + pr_err(DRV_PFX "Unable to create input devices.\n"); 3125 2821 goto err_free_resources; 3126 2822 } 3127 2823 ··· 3129 2829 /* request io port */ 3130 2830 list_for_each_entry_reverse(io, &spic_dev.ioports, list) { 3131 2831 if (request_region(io->io1.minimum, io->io1.address_length, 3132 - "Sony Programable I/O Device")) { 2832 + "Sony Programmable I/O Device")) { 3133 2833 dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n", 3134 2834 io->io1.minimum, io->io1.maximum, 3135 2835 io->io1.address_length); ··· 3137 2837 if (io->io2.minimum) { 3138 2838 if (request_region(io->io2.minimum, 3139 2839 io->io2.address_length, 3140 - "Sony Programable I/O Device")) { 2840 + "Sony Programmable I/O Device")) { 3141 2841 dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n", 3142 2842 io->io2.minimum, io->io2.maximum, 3143 2843 io->io2.address_length); ··· 3160 2860 } 3161 2861 } 3162 2862 if (!spic_dev.cur_ioport) { 3163 - printk(KERN_ERR DRV_PFX "Failed to request_region.\n"); 2863 + pr_err(DRV_PFX "Failed to request_region.\n"); 3164 2864 result = -ENODEV; 3165 2865 goto err_remove_compat; 3166 2866 } ··· 3180 2880 } 3181 2881 } 3182 2882 if (!spic_dev.cur_irq) { 3183 - printk(KERN_ERR DRV_PFX "Failed to request_irq.\n"); 2883 + pr_err(DRV_PFX "Failed to request_irq.\n"); 3184 2884 result = -ENODEV; 3185 2885 goto err_release_region; 3186 2886 } ··· 3188 2888 /* set resource status _SRS */ 3189 2889 result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq); 3190 2890 if (result) { 3191 - printk(KERN_ERR DRV_PFX "Couldn't enable device.\n"); 2891 + pr_err(DRV_PFX "Couldn't enable device.\n"); 3192 2892 goto err_free_irq; 3193 2893 } 3194 2894 ··· 3297 2997 if (!no_spic && dmi_check_system(sonypi_dmi_table)) { 3298 2998 result = acpi_bus_register_driver(&sony_pic_driver); 3299 2999 if (result) { 3300 - printk(KERN_ERR DRV_PFX 3301 - "Unable to register SPIC driver."); 3000 + pr_err(DRV_PFX "Unable to register SPIC driver."); 3302 3001 goto out; 3303 3002 } 3304 3003 spic_drv_registered = 1; ··· 3305 3006 3306 3007 result = acpi_bus_register_driver(&sony_nc_driver); 3307 3008 if (result) { 3308 - printk(KERN_ERR DRV_PFX "Unable to register SNC driver."); 3009 + pr_err(DRV_PFX "Unable to register SNC driver."); 3309 3010 goto out_unregister_pic; 3310 3011 } 3311 3012
+2 -2
drivers/platform/x86/thinkpad_acpi.c
··· 2407 2407 * This code is supposed to duplicate the IBM firmware behaviour: 2408 2408 * - Pressing MUTE issues mute hotkey message, even when already mute 2409 2409 * - Pressing Volume up/down issues volume up/down hotkey messages, 2410 - * even when already at maximum or minumum volume 2410 + * even when already at maximum or minimum volume 2411 2411 * - The act of unmuting issues volume up/down notification, 2412 2412 * depending which key was used to unmute 2413 2413 * ··· 2990 2990 * rfkill input events, or we will race the rfkill core input 2991 2991 * handler. 2992 2992 * 2993 - * tpacpi_inputdev_send_mutex works as a syncronization point 2993 + * tpacpi_inputdev_send_mutex works as a synchronization point 2994 2994 * for the above. 2995 2995 * 2996 2996 * We optimize to avoid numerous calls to hotkey_get_wlsw.
+180
drivers/platform/x86/xo15-ebook.c
··· 1 + /* 2 + * OLPC XO-1.5 ebook switch driver 3 + * (based on generic ACPI button driver) 4 + * 5 + * Copyright (C) 2009 Paul Fox <pgf@laptop.org> 6 + * Copyright (C) 2010 One Laptop per Child 7 + * 8 + * This program is free software; you can redistribute it and/or modify 9 + * it under the terms of the GNU General Public License as published by 10 + * the Free Software Foundation; either version 2 of the License, or (at 11 + * your option) any later version. 12 + */ 13 + 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/init.h> 17 + #include <linux/types.h> 18 + #include <linux/input.h> 19 + #include <acpi/acpi_bus.h> 20 + #include <acpi/acpi_drivers.h> 21 + 22 + #define MODULE_NAME "xo15-ebook" 23 + #define PREFIX MODULE_NAME ": " 24 + 25 + #define XO15_EBOOK_CLASS MODULE_NAME 26 + #define XO15_EBOOK_TYPE_UNKNOWN 0x00 27 + #define XO15_EBOOK_NOTIFY_STATUS 0x80 28 + 29 + #define XO15_EBOOK_SUBCLASS "ebook" 30 + #define XO15_EBOOK_HID "XO15EBK" 31 + #define XO15_EBOOK_DEVICE_NAME "EBook Switch" 32 + 33 + ACPI_MODULE_NAME(MODULE_NAME); 34 + 35 + MODULE_DESCRIPTION("OLPC XO-1.5 ebook switch driver"); 36 + MODULE_LICENSE("GPL"); 37 + 38 + static const struct acpi_device_id ebook_device_ids[] = { 39 + { XO15_EBOOK_HID, 0 }, 40 + { "", 0 }, 41 + }; 42 + MODULE_DEVICE_TABLE(acpi, ebook_device_ids); 43 + 44 + struct ebook_switch { 45 + struct input_dev *input; 46 + char phys[32]; /* for input device */ 47 + }; 48 + 49 + static int ebook_send_state(struct acpi_device *device) 50 + { 51 + struct ebook_switch *button = acpi_driver_data(device); 52 + unsigned long long state; 53 + acpi_status status; 54 + 55 + status = acpi_evaluate_integer(device->handle, "EBK", NULL, &state); 56 + if (ACPI_FAILURE(status)) 57 + return -EIO; 58 + 59 + /* input layer checks if event is redundant */ 60 + input_report_switch(button->input, SW_TABLET_MODE, !state); 61 + input_sync(button->input); 62 + return 0; 63 + } 64 + 65 + static void ebook_switch_notify(struct acpi_device *device, u32 event) 66 + { 67 + switch (event) { 68 + case ACPI_FIXED_HARDWARE_EVENT: 69 + case XO15_EBOOK_NOTIFY_STATUS: 70 + ebook_send_state(device); 71 + break; 72 + default: 73 + ACPI_DEBUG_PRINT((ACPI_DB_INFO, 74 + "Unsupported event [0x%x]\n", event)); 75 + break; 76 + } 77 + } 78 + 79 + static int ebook_switch_resume(struct acpi_device *device) 80 + { 81 + return ebook_send_state(device); 82 + } 83 + 84 + static int ebook_switch_add(struct acpi_device *device) 85 + { 86 + struct ebook_switch *button; 87 + struct input_dev *input; 88 + const char *hid = acpi_device_hid(device); 89 + char *name, *class; 90 + int error; 91 + 92 + button = kzalloc(sizeof(struct ebook_switch), GFP_KERNEL); 93 + if (!button) 94 + return -ENOMEM; 95 + 96 + device->driver_data = button; 97 + 98 + button->input = input = input_allocate_device(); 99 + if (!input) { 100 + error = -ENOMEM; 101 + goto err_free_button; 102 + } 103 + 104 + name = acpi_device_name(device); 105 + class = acpi_device_class(device); 106 + 107 + if (strcmp(hid, XO15_EBOOK_HID)) { 108 + printk(KERN_ERR PREFIX "Unsupported hid [%s]\n", hid); 109 + error = -ENODEV; 110 + goto err_free_input; 111 + } 112 + 113 + strcpy(name, XO15_EBOOK_DEVICE_NAME); 114 + sprintf(class, "%s/%s", XO15_EBOOK_CLASS, XO15_EBOOK_SUBCLASS); 115 + 116 + snprintf(button->phys, sizeof(button->phys), "%s/button/input0", hid); 117 + 118 + input->name = name; 119 + input->phys = button->phys; 120 + input->id.bustype = BUS_HOST; 121 + input->dev.parent = &device->dev; 122 + 123 + input->evbit[0] = BIT_MASK(EV_SW); 124 + set_bit(SW_TABLET_MODE, input->swbit); 125 + 126 + error = input_register_device(input); 127 + if (error) 128 + goto err_free_input; 129 + 130 + ebook_send_state(device); 131 + 132 + if (device->wakeup.flags.valid) { 133 + /* Button's GPE is run-wake GPE */ 134 + acpi_enable_gpe(device->wakeup.gpe_device, 135 + device->wakeup.gpe_number); 136 + device_set_wakeup_enable(&device->dev, true); 137 + } 138 + 139 + return 0; 140 + 141 + err_free_input: 142 + input_free_device(input); 143 + err_free_button: 144 + kfree(button); 145 + return error; 146 + } 147 + 148 + static int ebook_switch_remove(struct acpi_device *device, int type) 149 + { 150 + struct ebook_switch *button = acpi_driver_data(device); 151 + 152 + input_unregister_device(button->input); 153 + kfree(button); 154 + return 0; 155 + } 156 + 157 + static struct acpi_driver xo15_ebook_driver = { 158 + .name = MODULE_NAME, 159 + .class = XO15_EBOOK_CLASS, 160 + .ids = ebook_device_ids, 161 + .ops = { 162 + .add = ebook_switch_add, 163 + .resume = ebook_switch_resume, 164 + .remove = ebook_switch_remove, 165 + .notify = ebook_switch_notify, 166 + }, 167 + }; 168 + 169 + static int __init xo15_ebook_init(void) 170 + { 171 + return acpi_bus_register_driver(&xo15_ebook_driver); 172 + } 173 + 174 + static void __exit xo15_ebook_exit(void) 175 + { 176 + acpi_bus_unregister_driver(&xo15_ebook_driver); 177 + } 178 + 179 + module_init(xo15_ebook_init); 180 + module_exit(xo15_ebook_exit);
+7
include/linux/input.h
··· 664 664 #define KEY_TOUCHPAD_ON 0x213 665 665 #define KEY_TOUCHPAD_OFF 0x214 666 666 667 + #define KEY_CAMERA_ZOOMIN 0x215 668 + #define KEY_CAMERA_ZOOMOUT 0x216 669 + #define KEY_CAMERA_UP 0x217 670 + #define KEY_CAMERA_DOWN 0x218 671 + #define KEY_CAMERA_LEFT 0x219 672 + #define KEY_CAMERA_RIGHT 0x21a 673 + 667 674 #define BTN_TRIGGER_HAPPY 0x2c0 668 675 #define BTN_TRIGGER_HAPPY1 0x2c0 669 676 #define BTN_TRIGGER_HAPPY2 0x2c1
+1
include/linux/sonypi.h
··· 40 40 41 41 /* events the user application reading /dev/sonypi can use */ 42 42 43 + #define SONYPI_EVENT_IGNORE 0 43 44 #define SONYPI_EVENT_JOGDIAL_DOWN 1 44 45 #define SONYPI_EVENT_JOGDIAL_UP 2 45 46 #define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED 3