diff options
| author | Len Brown <len.brown@intel.com> | 2009-04-05 01:42:09 -0400 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2009-04-05 01:42:09 -0400 |
| commit | 336d63b8a3cadc1c678f4b16d6105633c7f6af75 (patch) | |
| tree | d8d713eb39500139ec637c55cc38e62d863d1845 | |
| parent | 07290bed7968c0e08fb3efe193fb148f1fea5e08 (diff) | |
| parent | 0e501834f8c2ba7de2a56e332d346dcf4ac0b593 (diff) | |
Merge branch 'thinkpad-acpi' into release
| -rw-r--r-- | Documentation/laptops/thinkpad-acpi.txt | 144 | ||||
| -rw-r--r-- | drivers/platform/x86/Kconfig | 24 | ||||
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 735 |
3 files changed, 657 insertions, 246 deletions
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 41bc99fa1884..3d7650768bb5 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
| @@ -20,7 +20,8 @@ moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel | |||
| 20 | kernel 2.6.29 and release 0.22. | 20 | kernel 2.6.29 and release 0.22. |
| 21 | 21 | ||
| 22 | The driver is named "thinkpad-acpi". In some places, like module | 22 | The driver is named "thinkpad-acpi". In some places, like module |
| 23 | names, "thinkpad_acpi" is used because of userspace issues. | 23 | names and log messages, "thinkpad_acpi" is used because of userspace |
| 24 | issues. | ||
| 24 | 25 | ||
| 25 | "tpacpi" is used as a shorthand where "thinkpad-acpi" would be too | 26 | "tpacpi" is used as a shorthand where "thinkpad-acpi" would be too |
| 26 | long due to length limitations on some Linux kernel versions. | 27 | long due to length limitations on some Linux kernel versions. |
| @@ -37,7 +38,7 @@ detailed description): | |||
| 37 | - ThinkLight on and off | 38 | - ThinkLight on and off |
| 38 | - limited docking and undocking | 39 | - limited docking and undocking |
| 39 | - UltraBay eject | 40 | - UltraBay eject |
| 40 | - CMOS control | 41 | - CMOS/UCMS control |
| 41 | - LED control | 42 | - LED control |
| 42 | - ACPI sounds | 43 | - ACPI sounds |
| 43 | - temperature sensors | 44 | - temperature sensors |
| @@ -46,6 +47,7 @@ detailed description): | |||
| 46 | - Volume control | 47 | - Volume control |
| 47 | - Fan control and monitoring: fan speed, fan enable/disable | 48 | - Fan control and monitoring: fan speed, fan enable/disable |
| 48 | - WAN enable and disable | 49 | - WAN enable and disable |
| 50 | - UWB enable and disable | ||
| 49 | 51 | ||
| 50 | A compatibility table by model and feature is maintained on the web | 52 | A compatibility table by model and feature is maintained on the web |
| 51 | site, http://ibm-acpi.sf.net/. I appreciate any success or failure | 53 | site, http://ibm-acpi.sf.net/. I appreciate any success or failure |
| @@ -53,7 +55,7 @@ reports, especially if they add to or correct the compatibility table. | |||
| 53 | Please include the following information in your report: | 55 | Please include the following information in your report: |
| 54 | 56 | ||
| 55 | - ThinkPad model name | 57 | - ThinkPad model name |
| 56 | - a copy of your DSDT, from /proc/acpi/dsdt | 58 | - a copy of your ACPI tables, using the "acpidump" utility |
| 57 | - a copy of the output of dmidecode, with serial numbers | 59 | - a copy of the output of dmidecode, with serial numbers |
| 58 | and UUIDs masked off | 60 | and UUIDs masked off |
| 59 | - which driver features work and which don't | 61 | - which driver features work and which don't |
| @@ -66,17 +68,18 @@ Installation | |||
| 66 | ------------ | 68 | ------------ |
| 67 | 69 | ||
| 68 | If you are compiling this driver as included in the Linux kernel | 70 | If you are compiling this driver as included in the Linux kernel |
| 69 | sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally | 71 | sources, look for the CONFIG_THINKPAD_ACPI Kconfig option. |
| 70 | enable the CONFIG_THINKPAD_ACPI_BAY option if you want the | 72 | It is located on the menu path: "Device Drivers" -> "X86 Platform |
| 71 | thinkpad-specific bay functionality. | 73 | Specific Device Drivers" -> "ThinkPad ACPI Laptop Extras". |
| 74 | |||
| 72 | 75 | ||
| 73 | Features | 76 | Features |
| 74 | -------- | 77 | -------- |
| 75 | 78 | ||
| 76 | The driver exports two different interfaces to userspace, which can be | 79 | The driver exports two different interfaces to userspace, which can be |
| 77 | used to access the features it provides. One is a legacy procfs-based | 80 | used to access the features it provides. One is a legacy procfs-based |
| 78 | interface, which will be removed at some time in the distant future. | 81 | interface, which will be removed at some time in the future. The other |
| 79 | The other is a new sysfs-based interface which is not complete yet. | 82 | is a new sysfs-based interface which is not complete yet. |
| 80 | 83 | ||
| 81 | The procfs interface creates the /proc/acpi/ibm directory. There is a | 84 | The procfs interface creates the /proc/acpi/ibm directory. There is a |
| 82 | file under that directory for each feature it supports. The procfs | 85 | file under that directory for each feature it supports. The procfs |
| @@ -111,15 +114,17 @@ The version of thinkpad-acpi's sysfs interface is exported by the driver | |||
| 111 | as a driver attribute (see below). | 114 | as a driver attribute (see below). |
| 112 | 115 | ||
| 113 | Sysfs driver attributes are on the driver's sysfs attribute space, | 116 | Sysfs driver attributes are on the driver's sysfs attribute space, |
| 114 | for 2.6.23 this is /sys/bus/platform/drivers/thinkpad_acpi/ and | 117 | for 2.6.23+ this is /sys/bus/platform/drivers/thinkpad_acpi/ and |
| 115 | /sys/bus/platform/drivers/thinkpad_hwmon/ | 118 | /sys/bus/platform/drivers/thinkpad_hwmon/ |
| 116 | 119 | ||
| 117 | Sysfs device attributes are on the thinkpad_acpi device sysfs attribute | 120 | Sysfs device attributes are on the thinkpad_acpi device sysfs attribute |
| 118 | space, for 2.6.23 this is /sys/devices/platform/thinkpad_acpi/. | 121 | space, for 2.6.23+ this is /sys/devices/platform/thinkpad_acpi/. |
| 119 | 122 | ||
| 120 | Sysfs device attributes for the sensors and fan are on the | 123 | Sysfs device attributes for the sensors and fan are on the |
| 121 | thinkpad_hwmon device's sysfs attribute space, but you should locate it | 124 | thinkpad_hwmon device's sysfs attribute space, but you should locate it |
| 122 | looking for a hwmon device with the name attribute of "thinkpad". | 125 | looking for a hwmon device with the name attribute of "thinkpad", or |
| 126 | better yet, through libsensors. | ||
| 127 | |||
| 123 | 128 | ||
| 124 | Driver version | 129 | Driver version |
| 125 | -------------- | 130 | -------------- |
| @@ -129,6 +134,7 @@ sysfs driver attribute: version | |||
| 129 | 134 | ||
| 130 | The driver name and version. No commands can be written to this file. | 135 | The driver name and version. No commands can be written to this file. |
| 131 | 136 | ||
| 137 | |||
| 132 | Sysfs interface version | 138 | Sysfs interface version |
| 133 | ----------------------- | 139 | ----------------------- |
| 134 | 140 | ||
| @@ -160,6 +166,7 @@ expect that an attribute might not be there, and deal with it properly | |||
| 160 | (an attribute not being there *is* a valid way to make it clear that a | 166 | (an attribute not being there *is* a valid way to make it clear that a |
| 161 | feature is not available in sysfs). | 167 | feature is not available in sysfs). |
| 162 | 168 | ||
| 169 | |||
| 163 | Hot keys | 170 | Hot keys |
| 164 | -------- | 171 | -------- |
| 165 | 172 | ||
| @@ -172,17 +179,14 @@ system. Enabling the hotkey functionality of thinkpad-acpi signals the | |||
| 172 | firmware that such a driver is present, and modifies how the ThinkPad | 179 | firmware that such a driver is present, and modifies how the ThinkPad |
| 173 | firmware will behave in many situations. | 180 | firmware will behave in many situations. |
| 174 | 181 | ||
| 175 | The driver enables the hot key feature automatically when loaded. The | 182 | The driver enables the HKEY ("hot key") event reporting automatically |
| 176 | feature can later be disabled and enabled back at runtime. The driver | 183 | when loaded, and disables it when it is removed. |
| 177 | will also restore the hot key feature to its previous state and mask | ||
| 178 | when it is unloaded. | ||
| 179 | 184 | ||
| 180 | When the hotkey feature is enabled and the hot key mask is set (see | 185 | The driver will report HKEY events in the following format: |
| 181 | below), the driver will report HKEY events in the following format: | ||
| 182 | 186 | ||
| 183 | ibm/hotkey HKEY 00000080 0000xxxx | 187 | ibm/hotkey HKEY 00000080 0000xxxx |
| 184 | 188 | ||
| 185 | Some of these events refer to hot key presses, but not all. | 189 | Some of these events refer to hot key presses, but not all of them. |
| 186 | 190 | ||
| 187 | The driver will generate events over the input layer for hot keys and | 191 | The driver will generate events over the input layer for hot keys and |
| 188 | radio switches, and over the ACPI netlink layer for other events. The | 192 | radio switches, and over the ACPI netlink layer for other events. The |
| @@ -214,13 +218,17 @@ procfs notes: | |||
| 214 | 218 | ||
| 215 | The following commands can be written to the /proc/acpi/ibm/hotkey file: | 219 | The following commands can be written to the /proc/acpi/ibm/hotkey file: |
| 216 | 220 | ||
| 217 | echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature | ||
| 218 | echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature | ||
| 219 | echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys | 221 | echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys |
| 220 | echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys | 222 | echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys |
| 221 | ... any other 8-hex-digit mask ... | 223 | ... any other 8-hex-digit mask ... |
| 222 | echo reset > /proc/acpi/ibm/hotkey -- restore the original mask | 224 | echo reset > /proc/acpi/ibm/hotkey -- restore the original mask |
| 223 | 225 | ||
| 226 | The following commands have been deprecated and will cause the kernel | ||
| 227 | to log a warning: | ||
| 228 | |||
| 229 | echo enable > /proc/acpi/ibm/hotkey -- does nothing | ||
| 230 | echo disable > /proc/acpi/ibm/hotkey -- returns an error | ||
| 231 | |||
| 224 | The procfs interface does not support NVRAM polling control. So as to | 232 | The procfs interface does not support NVRAM polling control. So as to |
| 225 | maintain maximum bug-to-bug compatibility, it does not report any masks, | 233 | maintain maximum bug-to-bug compatibility, it does not report any masks, |
| 226 | nor does it allow one to manipulate the hot key mask when the firmware | 234 | nor does it allow one to manipulate the hot key mask when the firmware |
| @@ -229,12 +237,9 @@ does not support masks at all, even if NVRAM polling is in use. | |||
| 229 | sysfs notes: | 237 | sysfs notes: |
| 230 | 238 | ||
| 231 | hotkey_bios_enabled: | 239 | hotkey_bios_enabled: |
| 232 | Returns the status of the hot keys feature when | 240 | DEPRECATED, WILL BE REMOVED SOON. |
| 233 | thinkpad-acpi was loaded. Upon module unload, the hot | ||
| 234 | key feature status will be restored to this value. | ||
| 235 | 241 | ||
| 236 | 0: hot keys were disabled | 242 | Returns 0. |
| 237 | 1: hot keys were enabled (unusual) | ||
| 238 | 243 | ||
| 239 | hotkey_bios_mask: | 244 | hotkey_bios_mask: |
| 240 | Returns the hot keys mask when thinkpad-acpi was loaded. | 245 | Returns the hot keys mask when thinkpad-acpi was loaded. |
| @@ -242,13 +247,10 @@ sysfs notes: | |||
| 242 | to this value. | 247 | to this value. |
| 243 | 248 | ||
| 244 | hotkey_enable: | 249 | hotkey_enable: |
| 245 | Enables/disables the hot keys feature in the ACPI | 250 | DEPRECATED, WILL BE REMOVED SOON. |
| 246 | firmware, and reports current status of the hot keys | ||
| 247 | feature. Has no effect on the NVRAM hot key polling | ||
| 248 | functionality. | ||
| 249 | 251 | ||
| 250 | 0: disables the hot keys feature / feature disabled | 252 | 0: returns -EPERM |
| 251 | 1: enables the hot keys feature / feature enabled | 253 | 1: does nothing |
| 252 | 254 | ||
| 253 | hotkey_mask: | 255 | hotkey_mask: |
| 254 | bit mask to enable driver-handling (and depending on | 256 | bit mask to enable driver-handling (and depending on |
| @@ -618,6 +620,7 @@ For Lenovo models *with* ACPI backlight control: | |||
| 618 | and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process | 620 | and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process |
| 619 | these keys on userspace somehow (e.g. by calling xbacklight). | 621 | these keys on userspace somehow (e.g. by calling xbacklight). |
| 620 | 622 | ||
| 623 | |||
| 621 | Bluetooth | 624 | Bluetooth |
| 622 | --------- | 625 | --------- |
| 623 | 626 | ||
| @@ -628,6 +631,9 @@ sysfs rfkill class: switch "tpacpi_bluetooth_sw" | |||
| 628 | This feature shows the presence and current state of a ThinkPad | 631 | This feature shows the presence and current state of a ThinkPad |
| 629 | Bluetooth device in the internal ThinkPad CDC slot. | 632 | Bluetooth device in the internal ThinkPad CDC slot. |
| 630 | 633 | ||
| 634 | If the ThinkPad supports it, the Bluetooth state is stored in NVRAM, | ||
| 635 | so it is kept across reboots and power-off. | ||
| 636 | |||
| 631 | Procfs notes: | 637 | Procfs notes: |
| 632 | 638 | ||
| 633 | If Bluetooth is installed, the following commands can be used: | 639 | If Bluetooth is installed, the following commands can be used: |
| @@ -652,6 +658,7 @@ Sysfs notes: | |||
| 652 | rfkill controller switch "tpacpi_bluetooth_sw": refer to | 658 | rfkill controller switch "tpacpi_bluetooth_sw": refer to |
| 653 | Documentation/rfkill.txt for details. | 659 | Documentation/rfkill.txt for details. |
| 654 | 660 | ||
| 661 | |||
| 655 | Video output control -- /proc/acpi/ibm/video | 662 | Video output control -- /proc/acpi/ibm/video |
| 656 | -------------------------------------------- | 663 | -------------------------------------------- |
| 657 | 664 | ||
| @@ -693,11 +700,8 @@ Fn-F7 from working. This also disables the video output switching | |||
| 693 | features of this driver, as it uses the same ACPI methods as | 700 | features of this driver, as it uses the same ACPI methods as |
| 694 | Fn-F7. Video switching on the console should still work. | 701 | Fn-F7. Video switching on the console should still work. |
| 695 | 702 | ||
| 696 | UPDATE: There's now a patch for the X.org Radeon driver which | 703 | UPDATE: refer to https://bugs.freedesktop.org/show_bug.cgi?id=2000 |
| 697 | addresses this issue. Some people are reporting success with the patch | ||
| 698 | while others are still having problems. For more information: | ||
| 699 | 704 | ||
| 700 | https://bugs.freedesktop.org/show_bug.cgi?id=2000 | ||
| 701 | 705 | ||
| 702 | ThinkLight control | 706 | ThinkLight control |
| 703 | ------------------ | 707 | ------------------ |
| @@ -720,10 +724,11 @@ The ThinkLight sysfs interface is documented by the LED class | |||
| 720 | documentation, in Documentation/leds-class.txt. The ThinkLight LED name | 724 | documentation, in Documentation/leds-class.txt. The ThinkLight LED name |
| 721 | is "tpacpi::thinklight". | 725 | is "tpacpi::thinklight". |
| 722 | 726 | ||
| 723 | Due to limitations in the sysfs LED class, if the status of the thinklight | 727 | Due to limitations in the sysfs LED class, if the status of the ThinkLight |
| 724 | cannot be read or if it is unknown, thinkpad-acpi will report it as "off". | 728 | cannot be read or if it is unknown, thinkpad-acpi will report it as "off". |
| 725 | It is impossible to know if the status returned through sysfs is valid. | 729 | It is impossible to know if the status returned through sysfs is valid. |
| 726 | 730 | ||
| 731 | |||
| 727 | Docking / undocking -- /proc/acpi/ibm/dock | 732 | Docking / undocking -- /proc/acpi/ibm/dock |
| 728 | ------------------------------------------ | 733 | ------------------------------------------ |
| 729 | 734 | ||
| @@ -784,6 +789,7 @@ the only docking stations currently supported are the X-series | |||
| 784 | UltraBase docks and "dumb" port replicators like the Mini Dock (the | 789 | UltraBase docks and "dumb" port replicators like the Mini Dock (the |
| 785 | latter don't need any ACPI support, actually). | 790 | latter don't need any ACPI support, actually). |
| 786 | 791 | ||
| 792 | |||
| 787 | UltraBay eject -- /proc/acpi/ibm/bay | 793 | UltraBay eject -- /proc/acpi/ibm/bay |
| 788 | ------------------------------------ | 794 | ------------------------------------ |
| 789 | 795 | ||
| @@ -847,8 +853,9 @@ supported. Use "eject2" instead of "eject" for the second bay. | |||
| 847 | Note: the UltraBay eject support on the 600e/x, A22p and A3x is | 853 | Note: the UltraBay eject support on the 600e/x, A22p and A3x is |
| 848 | EXPERIMENTAL and may not work as expected. USE WITH CAUTION! | 854 | EXPERIMENTAL and may not work as expected. USE WITH CAUTION! |
| 849 | 855 | ||
| 850 | CMOS control | 856 | |
| 851 | ------------ | 857 | CMOS/UCMS control |
| 858 | ----------------- | ||
| 852 | 859 | ||
| 853 | procfs: /proc/acpi/ibm/cmos | 860 | procfs: /proc/acpi/ibm/cmos |
| 854 | sysfs device attribute: cmos_command | 861 | sysfs device attribute: cmos_command |
| @@ -882,6 +889,7 @@ The cmos command interface is prone to firmware split-brain problems, as | |||
| 882 | in newer ThinkPads it is just a compatibility layer. Do not use it, it is | 889 | in newer ThinkPads it is just a compatibility layer. Do not use it, it is |
| 883 | exported just as a debug tool. | 890 | exported just as a debug tool. |
| 884 | 891 | ||
| 892 | |||
| 885 | LED control | 893 | LED control |
| 886 | ----------- | 894 | ----------- |
| 887 | 895 | ||
| @@ -893,6 +901,17 @@ some older ThinkPad models, it is possible to query the status of the | |||
| 893 | LED indicators as well. Newer ThinkPads cannot query the real status | 901 | LED indicators as well. Newer ThinkPads cannot query the real status |
| 894 | of the LED indicators. | 902 | of the LED indicators. |
| 895 | 903 | ||
| 904 | Because misuse of the LEDs could induce an unaware user to perform | ||
| 905 | dangerous actions (like undocking or ejecting a bay device while the | ||
| 906 | buses are still active), or mask an important alarm (such as a nearly | ||
| 907 | empty battery, or a broken battery), access to most LEDs is | ||
| 908 | restricted. | ||
| 909 | |||
| 910 | Unrestricted access to all LEDs requires that thinkpad-acpi be | ||
| 911 | compiled with the CONFIG_THINKPAD_ACPI_UNSAFE_LEDS option enabled. | ||
| 912 | Distributions must never enable this option. Individual users that | ||
| 913 | are aware of the consequences are welcome to enabling it. | ||
| 914 | |||
| 896 | procfs notes: | 915 | procfs notes: |
| 897 | 916 | ||
| 898 | The available commands are: | 917 | The available commands are: |
| @@ -939,6 +958,7 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the | |||
| 939 | "timer" trigger, and leave the delay_on and delay_off parameters set to | 958 | "timer" trigger, and leave the delay_on and delay_off parameters set to |
| 940 | zero (to request hardware acceleration autodetection). | 959 | zero (to request hardware acceleration autodetection). |
| 941 | 960 | ||
| 961 | |||
| 942 | ACPI sounds -- /proc/acpi/ibm/beep | 962 | ACPI sounds -- /proc/acpi/ibm/beep |
| 943 | ---------------------------------- | 963 | ---------------------------------- |
| 944 | 964 | ||
| @@ -968,6 +988,7 @@ X40: | |||
| 968 | 16 - one medium-pitched beep repeating constantly, stop with 17 | 988 | 16 - one medium-pitched beep repeating constantly, stop with 17 |
| 969 | 17 - stop 16 | 989 | 17 - stop 16 |
| 970 | 990 | ||
| 991 | |||
| 971 | Temperature sensors | 992 | Temperature sensors |
| 972 | ------------------- | 993 | ------------------- |
| 973 | 994 | ||
| @@ -1115,6 +1136,7 @@ registers contain the current battery capacity, etc. If you experiment | |||
| 1115 | with this, do send me your results (including some complete dumps with | 1136 | with this, do send me your results (including some complete dumps with |
| 1116 | a description of the conditions when they were taken.) | 1137 | a description of the conditions when they were taken.) |
| 1117 | 1138 | ||
| 1139 | |||
| 1118 | LCD brightness control | 1140 | LCD brightness control |
| 1119 | ---------------------- | 1141 | ---------------------- |
| 1120 | 1142 | ||
| @@ -1124,10 +1146,9 @@ sysfs backlight device "thinkpad_screen" | |||
| 1124 | This feature allows software control of the LCD brightness on ThinkPad | 1146 | This feature allows software control of the LCD brightness on ThinkPad |
| 1125 | models which don't have a hardware brightness slider. | 1147 | models which don't have a hardware brightness slider. |
| 1126 | 1148 | ||
| 1127 | It has some limitations: the LCD backlight cannot be actually turned on or | 1149 | It has some limitations: the LCD backlight cannot be actually turned |
| 1128 | off by this interface, and in many ThinkPad models, the "dim while on | 1150 | on or off by this interface, it just controls the backlight brightness |
| 1129 | battery" functionality will be enabled by the BIOS when this interface is | 1151 | level. |
| 1130 | used, and cannot be controlled. | ||
| 1131 | 1152 | ||
| 1132 | On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control | 1153 | On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control |
| 1133 | has eight brightness levels, ranging from 0 to 7. Some of the levels | 1154 | has eight brightness levels, ranging from 0 to 7. Some of the levels |
| @@ -1136,10 +1157,15 @@ display backlight brightness control methods have 16 levels, ranging | |||
| 1136 | from 0 to 15. | 1157 | from 0 to 15. |
| 1137 | 1158 | ||
| 1138 | There are two interfaces to the firmware for direct brightness control, | 1159 | There are two interfaces to the firmware for direct brightness control, |
| 1139 | EC and CMOS. To select which one should be used, use the | 1160 | EC and UCMS (or CMOS). To select which one should be used, use the |
| 1140 | brightness_mode module parameter: brightness_mode=1 selects EC mode, | 1161 | brightness_mode module parameter: brightness_mode=1 selects EC mode, |
| 1141 | brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC | 1162 | brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC |
| 1142 | and CMOS. The driver tries to auto-detect which interface to use. | 1163 | mode with NVRAM backing (so that brightness changes are remembered |
| 1164 | across shutdown/reboot). | ||
| 1165 | |||
| 1166 | The driver tries to select which interface to use from a table of | ||
| 1167 | defaults for each ThinkPad model. If it makes a wrong choice, please | ||
| 1168 | report this as a bug, so that we can fix it. | ||
| 1143 | 1169 | ||
| 1144 | When display backlight brightness controls are available through the | 1170 | When display backlight brightness controls are available through the |
| 1145 | standard ACPI interface, it is best to use it instead of this direct | 1171 | standard ACPI interface, it is best to use it instead of this direct |
| @@ -1201,6 +1227,7 @@ WARNING: | |||
| 1201 | and maybe reduce the life of the backlight lamps by needlessly kicking | 1227 | and maybe reduce the life of the backlight lamps by needlessly kicking |
| 1202 | its level up and down at every change. | 1228 | its level up and down at every change. |
| 1203 | 1229 | ||
| 1230 | |||
| 1204 | Volume control -- /proc/acpi/ibm/volume | 1231 | Volume control -- /proc/acpi/ibm/volume |
| 1205 | --------------------------------------- | 1232 | --------------------------------------- |
| 1206 | 1233 | ||
| @@ -1217,6 +1244,11 @@ distinct. The unmute the volume after the mute command, use either the | |||
| 1217 | up or down command (the level command will not unmute the volume). | 1244 | up or down command (the level command will not unmute the volume). |
| 1218 | The current volume level and mute state is shown in the file. | 1245 | The current volume level and mute state is shown in the file. |
| 1219 | 1246 | ||
| 1247 | The ALSA mixer interface to this feature is still missing, but patches | ||
| 1248 | to add it exist. That problem should be addressed in the not so | ||
| 1249 | distant future. | ||
| 1250 | |||
| 1251 | |||
| 1220 | Fan control and monitoring: fan speed, fan enable/disable | 1252 | Fan control and monitoring: fan speed, fan enable/disable |
| 1221 | --------------------------------------------------------- | 1253 | --------------------------------------------------------- |
| 1222 | 1254 | ||
| @@ -1383,8 +1415,11 @@ procfs: /proc/acpi/ibm/wan | |||
| 1383 | sysfs device attribute: wwan_enable (deprecated) | 1415 | sysfs device attribute: wwan_enable (deprecated) |
| 1384 | sysfs rfkill class: switch "tpacpi_wwan_sw" | 1416 | sysfs rfkill class: switch "tpacpi_wwan_sw" |
| 1385 | 1417 | ||
| 1386 | This feature shows the presence and current state of a W-WAN (Sierra | 1418 | This feature shows the presence and current state of the built-in |
| 1387 | Wireless EV-DO) device. | 1419 | Wireless WAN device. |
| 1420 | |||
| 1421 | If the ThinkPad supports it, the WWAN state is stored in NVRAM, | ||
| 1422 | so it is kept across reboots and power-off. | ||
| 1388 | 1423 | ||
| 1389 | It was tested on a Lenovo ThinkPad X60. It should probably work on other | 1424 | It was tested on a Lenovo ThinkPad X60. It should probably work on other |
| 1390 | ThinkPad models which come with this module installed. | 1425 | ThinkPad models which come with this module installed. |
| @@ -1413,6 +1448,7 @@ Sysfs notes: | |||
| 1413 | rfkill controller switch "tpacpi_wwan_sw": refer to | 1448 | rfkill controller switch "tpacpi_wwan_sw": refer to |
| 1414 | Documentation/rfkill.txt for details. | 1449 | Documentation/rfkill.txt for details. |
| 1415 | 1450 | ||
| 1451 | |||
| 1416 | EXPERIMENTAL: UWB | 1452 | EXPERIMENTAL: UWB |
| 1417 | ----------------- | 1453 | ----------------- |
| 1418 | 1454 | ||
| @@ -1431,6 +1467,7 @@ Sysfs notes: | |||
| 1431 | rfkill controller switch "tpacpi_uwb_sw": refer to | 1467 | rfkill controller switch "tpacpi_uwb_sw": refer to |
| 1432 | Documentation/rfkill.txt for details. | 1468 | Documentation/rfkill.txt for details. |
| 1433 | 1469 | ||
| 1470 | |||
| 1434 | Multiple Commands, Module Parameters | 1471 | Multiple Commands, Module Parameters |
| 1435 | ------------------------------------ | 1472 | ------------------------------------ |
| 1436 | 1473 | ||
| @@ -1445,6 +1482,7 @@ for example: | |||
| 1445 | 1482 | ||
| 1446 | modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable | 1483 | modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable |
| 1447 | 1484 | ||
| 1485 | |||
| 1448 | Enabling debugging output | 1486 | Enabling debugging output |
| 1449 | ------------------------- | 1487 | ------------------------- |
| 1450 | 1488 | ||
| @@ -1457,8 +1495,15 @@ will enable all debugging output classes. It takes a bitmask, so | |||
| 1457 | to enable more than one output class, just add their values. | 1495 | to enable more than one output class, just add their values. |
| 1458 | 1496 | ||
| 1459 | Debug bitmask Description | 1497 | Debug bitmask Description |
| 1498 | 0x8000 Disclose PID of userspace programs | ||
| 1499 | accessing some functions of the driver | ||
| 1460 | 0x0001 Initialization and probing | 1500 | 0x0001 Initialization and probing |
| 1461 | 0x0002 Removal | 1501 | 0x0002 Removal |
| 1502 | 0x0004 RF Transmitter control (RFKILL) | ||
| 1503 | (bluetooth, WWAN, UWB...) | ||
| 1504 | 0x0008 HKEY event interface, hotkeys | ||
| 1505 | 0x0010 Fan control | ||
| 1506 | 0x0020 Backlight brightness | ||
| 1462 | 1507 | ||
| 1463 | There is also a kernel build option to enable more debugging | 1508 | There is also a kernel build option to enable more debugging |
| 1464 | information, which may be necessary to debug driver problems. | 1509 | information, which may be necessary to debug driver problems. |
| @@ -1467,6 +1512,7 @@ The level of debugging information output by the driver can be changed | |||
| 1467 | at runtime through sysfs, using the driver attribute debug_level. The | 1512 | at runtime through sysfs, using the driver attribute debug_level. The |
| 1468 | attribute takes the same bitmask as the debug module parameter above. | 1513 | attribute takes the same bitmask as the debug module parameter above. |
| 1469 | 1514 | ||
| 1515 | |||
| 1470 | Force loading of module | 1516 | Force loading of module |
| 1471 | ----------------------- | 1517 | ----------------------- |
| 1472 | 1518 | ||
| @@ -1505,3 +1551,7 @@ Sysfs interface changelog: | |||
| 1505 | 1551 | ||
| 1506 | 0x020200: Add poll()/select() support to the following attributes: | 1552 | 0x020200: Add poll()/select() support to the following attributes: |
| 1507 | hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason | 1553 | hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason |
| 1554 | |||
| 1555 | 0x020300: hotkey enable/disable support removed, attributes | ||
| 1556 | hotkey_bios_enabled and hotkey_enable deprecated and | ||
| 1557 | marked for removal. | ||
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 3608081bc3e0..d45c6ab729f8 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
| @@ -226,6 +226,30 @@ config THINKPAD_ACPI_DEBUG | |||
| 226 | 226 | ||
| 227 | If you are not sure, say N here. | 227 | If you are not sure, say N here. |
| 228 | 228 | ||
| 229 | config THINKPAD_ACPI_UNSAFE_LEDS | ||
| 230 | bool "Allow control of important LEDs (unsafe)" | ||
| 231 | depends on THINKPAD_ACPI | ||
| 232 | default n | ||
| 233 | ---help--- | ||
| 234 | Overriding LED state on ThinkPads can mask important | ||
| 235 | firmware alerts (like critical battery condition), or misled | ||
| 236 | the user into damaging the hardware (undocking or ejecting | ||
| 237 | the bay while buses are still active), etc. | ||
| 238 | |||
| 239 | LED control on the ThinkPad is write-only (with very few | ||
| 240 | exceptions on very ancient models), which makes it | ||
| 241 | impossible to know beforehand if important information will | ||
| 242 | be lost when one changes LED state. | ||
| 243 | |||
| 244 | Users that know what they are doing can enable this option | ||
| 245 | and the driver will allow control of every LED, including | ||
| 246 | the ones on the dock stations. | ||
| 247 | |||
| 248 | Never enable this option on a distribution kernel. | ||
| 249 | |||
| 250 | Say N here, unless you are building a kernel for your own | ||
| 251 | use, and need to control the important firmware LEDs. | ||
| 252 | |||
| 229 | config THINKPAD_ACPI_DOCK | 253 | config THINKPAD_ACPI_DOCK |
| 230 | bool "Legacy Docking Station Support" | 254 | bool "Legacy Docking Station Support" |
| 231 | depends on THINKPAD_ACPI | 255 | depends on THINKPAD_ACPI |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index d2433204a40c..ba3682c5cde0 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -3,7 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * | 4 | * |
| 5 | * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> | 5 | * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> |
| 6 | * Copyright (C) 2006-2008 Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 6 | * Copyright (C) 2006-2009 Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
| 7 | * | 7 | * |
| 8 | * This program is free software; you can redistribute it and/or modify | 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 | 9 | * it under the terms of the GNU General Public License as published by |
| @@ -22,7 +22,7 @@ | |||
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #define TPACPI_VERSION "0.22" | 24 | #define TPACPI_VERSION "0.22" |
| 25 | #define TPACPI_SYSFS_VERSION 0x020200 | 25 | #define TPACPI_SYSFS_VERSION 0x020300 |
| 26 | 26 | ||
| 27 | /* | 27 | /* |
| 28 | * Changelog: | 28 | * Changelog: |
| @@ -54,6 +54,7 @@ | |||
| 54 | #include <linux/string.h> | 54 | #include <linux/string.h> |
| 55 | #include <linux/list.h> | 55 | #include <linux/list.h> |
| 56 | #include <linux/mutex.h> | 56 | #include <linux/mutex.h> |
| 57 | #include <linux/sched.h> | ||
| 57 | #include <linux/kthread.h> | 58 | #include <linux/kthread.h> |
| 58 | #include <linux/freezer.h> | 59 | #include <linux/freezer.h> |
| 59 | #include <linux/delay.h> | 60 | #include <linux/delay.h> |
| @@ -172,29 +173,26 @@ enum { | |||
| 172 | TPACPI_RFK_UWB_SW_ID, | 173 | TPACPI_RFK_UWB_SW_ID, |
| 173 | }; | 174 | }; |
| 174 | 175 | ||
| 175 | /* Debugging */ | 176 | /* printk headers */ |
| 176 | #define TPACPI_LOG TPACPI_FILE ": " | 177 | #define TPACPI_LOG TPACPI_FILE ": " |
| 177 | #define TPACPI_ALERT KERN_ALERT TPACPI_LOG | 178 | #define TPACPI_EMERG KERN_EMERG TPACPI_LOG |
| 178 | #define TPACPI_CRIT KERN_CRIT TPACPI_LOG | 179 | #define TPACPI_ALERT KERN_ALERT TPACPI_LOG |
| 179 | #define TPACPI_ERR KERN_ERR TPACPI_LOG | 180 | #define TPACPI_CRIT KERN_CRIT TPACPI_LOG |
| 180 | #define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG | 181 | #define TPACPI_ERR KERN_ERR TPACPI_LOG |
| 181 | #define TPACPI_INFO KERN_INFO TPACPI_LOG | 182 | #define TPACPI_WARN KERN_WARNING TPACPI_LOG |
| 182 | #define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG | 183 | #define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG |
| 183 | 184 | #define TPACPI_INFO KERN_INFO TPACPI_LOG | |
| 185 | #define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG | ||
| 186 | |||
| 187 | /* Debugging printk groups */ | ||
| 184 | #define TPACPI_DBG_ALL 0xffff | 188 | #define TPACPI_DBG_ALL 0xffff |
| 189 | #define TPACPI_DBG_DISCLOSETASK 0x8000 | ||
| 185 | #define TPACPI_DBG_INIT 0x0001 | 190 | #define TPACPI_DBG_INIT 0x0001 |
| 186 | #define TPACPI_DBG_EXIT 0x0002 | 191 | #define TPACPI_DBG_EXIT 0x0002 |
| 187 | #define dbg_printk(a_dbg_level, format, arg...) \ | 192 | #define TPACPI_DBG_RFKILL 0x0004 |
| 188 | do { if (dbg_level & a_dbg_level) \ | 193 | #define TPACPI_DBG_HKEY 0x0008 |
| 189 | printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \ | 194 | #define TPACPI_DBG_FAN 0x0010 |
| 190 | } while (0) | 195 | #define TPACPI_DBG_BRGHT 0x0020 |
| 191 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG | ||
| 192 | #define vdbg_printk(a_dbg_level, format, arg...) \ | ||
| 193 | dbg_printk(a_dbg_level, format, ## arg) | ||
| 194 | static const char *str_supported(int is_supported); | ||
| 195 | #else | ||
| 196 | #define vdbg_printk(a_dbg_level, format, arg...) | ||
| 197 | #endif | ||
| 198 | 196 | ||
| 199 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") | 197 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") |
| 200 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") | 198 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") |
| @@ -277,7 +275,6 @@ static struct { | |||
| 277 | 275 | ||
| 278 | static struct { | 276 | static struct { |
| 279 | u16 hotkey_mask_ff:1; | 277 | u16 hotkey_mask_ff:1; |
| 280 | u16 bright_cmos_ec_unsync:1; | ||
| 281 | } tp_warned; | 278 | } tp_warned; |
| 282 | 279 | ||
| 283 | struct thinkpad_id_data { | 280 | struct thinkpad_id_data { |
| @@ -326,6 +323,39 @@ static int tpacpi_uwb_emulstate; | |||
| 326 | #endif | 323 | #endif |
| 327 | 324 | ||
| 328 | 325 | ||
| 326 | /************************************************************************* | ||
| 327 | * Debugging helpers | ||
| 328 | */ | ||
| 329 | |||
| 330 | #define dbg_printk(a_dbg_level, format, arg...) \ | ||
| 331 | do { if (dbg_level & (a_dbg_level)) \ | ||
| 332 | printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \ | ||
| 333 | } while (0) | ||
| 334 | |||
| 335 | #ifdef CONFIG_THINKPAD_ACPI_DEBUG | ||
| 336 | #define vdbg_printk dbg_printk | ||
| 337 | static const char *str_supported(int is_supported); | ||
| 338 | #else | ||
| 339 | #define vdbg_printk(a_dbg_level, format, arg...) \ | ||
| 340 | do { } while (0) | ||
| 341 | #endif | ||
| 342 | |||
| 343 | static void tpacpi_log_usertask(const char * const what) | ||
| 344 | { | ||
| 345 | printk(TPACPI_DEBUG "%s: access by process with PID %d\n", | ||
| 346 | what, task_tgid_vnr(current)); | ||
| 347 | } | ||
| 348 | |||
| 349 | #define tpacpi_disclose_usertask(what, format, arg...) \ | ||
| 350 | do { \ | ||
| 351 | if (unlikely( \ | ||
| 352 | (dbg_level & TPACPI_DBG_DISCLOSETASK) && \ | ||
| 353 | (tpacpi_lifecycle == TPACPI_LIFE_RUNNING))) { \ | ||
| 354 | printk(TPACPI_DEBUG "%s: PID %d: " format, \ | ||
| 355 | what, task_tgid_vnr(current), ## arg); \ | ||
| 356 | } \ | ||
| 357 | } while (0) | ||
| 358 | |||
| 329 | /**************************************************************************** | 359 | /**************************************************************************** |
| 330 | **************************************************************************** | 360 | **************************************************************************** |
| 331 | * | 361 | * |
| @@ -989,10 +1019,13 @@ static int __init tpacpi_new_rfkill(const unsigned int id, | |||
| 989 | /* try to set the initial state as the default for the rfkill | 1019 | /* try to set the initial state as the default for the rfkill |
| 990 | * type, since we ask the firmware to preserve it across S5 in | 1020 | * type, since we ask the firmware to preserve it across S5 in |
| 991 | * NVRAM */ | 1021 | * NVRAM */ |
| 992 | rfkill_set_default(rfktype, | 1022 | if (rfkill_set_default(rfktype, |
| 993 | (initial_state == RFKILL_STATE_UNBLOCKED) ? | 1023 | (initial_state == RFKILL_STATE_UNBLOCKED) ? |
| 994 | RFKILL_STATE_UNBLOCKED : | 1024 | RFKILL_STATE_UNBLOCKED : |
| 995 | RFKILL_STATE_SOFT_BLOCKED); | 1025 | RFKILL_STATE_SOFT_BLOCKED) == -EPERM) |
| 1026 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 1027 | "Default state for %s cannot be changed\n", | ||
| 1028 | name); | ||
| 996 | } | 1029 | } |
| 997 | 1030 | ||
| 998 | *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); | 1031 | *rfk = rfkill_allocate(&tpacpi_pdev->dev, rfktype); |
| @@ -1020,6 +1053,21 @@ static int __init tpacpi_new_rfkill(const unsigned int id, | |||
| 1020 | return 0; | 1053 | return 0; |
| 1021 | } | 1054 | } |
| 1022 | 1055 | ||
| 1056 | static void printk_deprecated_attribute(const char * const what, | ||
| 1057 | const char * const details) | ||
| 1058 | { | ||
| 1059 | tpacpi_log_usertask("deprecated sysfs attribute"); | ||
| 1060 | printk(TPACPI_WARN "WARNING: sysfs attribute %s is deprecated and " | ||
| 1061 | "will be removed. %s\n", | ||
| 1062 | what, details); | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | static void printk_deprecated_rfkill_attribute(const char * const what) | ||
| 1066 | { | ||
| 1067 | printk_deprecated_attribute(what, | ||
| 1068 | "Please switch to generic rfkill before year 2010"); | ||
| 1069 | } | ||
| 1070 | |||
| 1023 | /************************************************************************* | 1071 | /************************************************************************* |
| 1024 | * thinkpad-acpi driver attributes | 1072 | * thinkpad-acpi driver attributes |
| 1025 | */ | 1073 | */ |
| @@ -1382,7 +1430,6 @@ static enum { /* Reasons for waking up */ | |||
| 1382 | 1430 | ||
| 1383 | static int hotkey_autosleep_ack; | 1431 | static int hotkey_autosleep_ack; |
| 1384 | 1432 | ||
| 1385 | static int hotkey_orig_status; | ||
| 1386 | static u32 hotkey_orig_mask; | 1433 | static u32 hotkey_orig_mask; |
| 1387 | static u32 hotkey_all_mask; | 1434 | static u32 hotkey_all_mask; |
| 1388 | static u32 hotkey_reserved_mask; | 1435 | static u32 hotkey_reserved_mask; |
| @@ -1529,9 +1576,9 @@ static int hotkey_status_get(int *status) | |||
| 1529 | return 0; | 1576 | return 0; |
| 1530 | } | 1577 | } |
| 1531 | 1578 | ||
| 1532 | static int hotkey_status_set(int status) | 1579 | static int hotkey_status_set(bool enable) |
| 1533 | { | 1580 | { |
| 1534 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) | 1581 | if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", enable ? 1 : 0)) |
| 1535 | return -EIO; | 1582 | return -EIO; |
| 1536 | 1583 | ||
| 1537 | return 0; | 1584 | return 0; |
| @@ -1847,6 +1894,9 @@ static ssize_t hotkey_enable_show(struct device *dev, | |||
| 1847 | { | 1894 | { |
| 1848 | int res, status; | 1895 | int res, status; |
| 1849 | 1896 | ||
| 1897 | printk_deprecated_attribute("hotkey_enable", | ||
| 1898 | "Hotkey reporting is always enabled"); | ||
| 1899 | |||
| 1850 | res = hotkey_status_get(&status); | 1900 | res = hotkey_status_get(&status); |
| 1851 | if (res) | 1901 | if (res) |
| 1852 | return res; | 1902 | return res; |
| @@ -1859,14 +1909,17 @@ static ssize_t hotkey_enable_store(struct device *dev, | |||
| 1859 | const char *buf, size_t count) | 1909 | const char *buf, size_t count) |
| 1860 | { | 1910 | { |
| 1861 | unsigned long t; | 1911 | unsigned long t; |
| 1862 | int res; | 1912 | |
| 1913 | printk_deprecated_attribute("hotkey_enable", | ||
| 1914 | "Hotkeys can be disabled through hotkey_mask"); | ||
| 1863 | 1915 | ||
| 1864 | if (parse_strtoul(buf, 1, &t)) | 1916 | if (parse_strtoul(buf, 1, &t)) |
| 1865 | return -EINVAL; | 1917 | return -EINVAL; |
| 1866 | 1918 | ||
| 1867 | res = hotkey_status_set(t); | 1919 | if (t == 0) |
| 1920 | return -EPERM; | ||
| 1868 | 1921 | ||
| 1869 | return (res) ? res : count; | 1922 | return count; |
| 1870 | } | 1923 | } |
| 1871 | 1924 | ||
| 1872 | static struct device_attribute dev_attr_hotkey_enable = | 1925 | static struct device_attribute dev_attr_hotkey_enable = |
| @@ -1910,6 +1963,8 @@ static ssize_t hotkey_mask_store(struct device *dev, | |||
| 1910 | 1963 | ||
| 1911 | mutex_unlock(&hotkey_mutex); | 1964 | mutex_unlock(&hotkey_mutex); |
| 1912 | 1965 | ||
| 1966 | tpacpi_disclose_usertask("hotkey_mask", "set to 0x%08lx\n", t); | ||
| 1967 | |||
| 1913 | return (res) ? res : count; | 1968 | return (res) ? res : count; |
| 1914 | } | 1969 | } |
| 1915 | 1970 | ||
| @@ -1922,7 +1977,7 @@ static ssize_t hotkey_bios_enabled_show(struct device *dev, | |||
| 1922 | struct device_attribute *attr, | 1977 | struct device_attribute *attr, |
| 1923 | char *buf) | 1978 | char *buf) |
| 1924 | { | 1979 | { |
| 1925 | return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status); | 1980 | return sprintf(buf, "0\n"); |
| 1926 | } | 1981 | } |
| 1927 | 1982 | ||
| 1928 | static struct device_attribute dev_attr_hotkey_bios_enabled = | 1983 | static struct device_attribute dev_attr_hotkey_bios_enabled = |
| @@ -1996,6 +2051,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev, | |||
| 1996 | 2051 | ||
| 1997 | mutex_unlock(&hotkey_mutex); | 2052 | mutex_unlock(&hotkey_mutex); |
| 1998 | 2053 | ||
| 2054 | tpacpi_disclose_usertask("hotkey_source_mask", "set to 0x%08lx\n", t); | ||
| 2055 | |||
| 1999 | return count; | 2056 | return count; |
| 2000 | } | 2057 | } |
| 2001 | 2058 | ||
| @@ -2028,6 +2085,8 @@ static ssize_t hotkey_poll_freq_store(struct device *dev, | |||
| 2028 | hotkey_poll_setup(1); | 2085 | hotkey_poll_setup(1); |
| 2029 | mutex_unlock(&hotkey_mutex); | 2086 | mutex_unlock(&hotkey_mutex); |
| 2030 | 2087 | ||
| 2088 | tpacpi_disclose_usertask("hotkey_poll_freq", "set to %lu\n", t); | ||
| 2089 | |||
| 2031 | return count; | 2090 | return count; |
| 2032 | } | 2091 | } |
| 2033 | 2092 | ||
| @@ -2197,11 +2256,11 @@ static void hotkey_exit(void) | |||
| 2197 | kfree(hotkey_keycode_map); | 2256 | kfree(hotkey_keycode_map); |
| 2198 | 2257 | ||
| 2199 | if (tp_features.hotkey) { | 2258 | if (tp_features.hotkey) { |
| 2200 | dbg_printk(TPACPI_DBG_EXIT, | 2259 | dbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_HKEY, |
| 2201 | "restoring original hot key mask\n"); | 2260 | "restoring original hot key mask\n"); |
| 2202 | /* no short-circuit boolean operator below! */ | 2261 | /* no short-circuit boolean operator below! */ |
| 2203 | if ((hotkey_mask_set(hotkey_orig_mask) | | 2262 | if ((hotkey_mask_set(hotkey_orig_mask) | |
| 2204 | hotkey_status_set(hotkey_orig_status)) != 0) | 2263 | hotkey_status_set(false)) != 0) |
| 2205 | printk(TPACPI_ERR | 2264 | printk(TPACPI_ERR |
| 2206 | "failed to restore hot key mask " | 2265 | "failed to restore hot key mask " |
| 2207 | "to BIOS defaults\n"); | 2266 | "to BIOS defaults\n"); |
| @@ -2327,7 +2386,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2327 | int status; | 2386 | int status; |
| 2328 | int hkeyv; | 2387 | int hkeyv; |
| 2329 | 2388 | ||
| 2330 | vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n"); | 2389 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2390 | "initializing hotkey subdriver\n"); | ||
| 2331 | 2391 | ||
| 2332 | BUG_ON(!tpacpi_inputdev); | 2392 | BUG_ON(!tpacpi_inputdev); |
| 2333 | BUG_ON(tpacpi_inputdev->open != NULL || | 2393 | BUG_ON(tpacpi_inputdev->open != NULL || |
| @@ -2344,7 +2404,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2344 | /* hotkey not supported on 570 */ | 2404 | /* hotkey not supported on 570 */ |
| 2345 | tp_features.hotkey = hkey_handle != NULL; | 2405 | tp_features.hotkey = hkey_handle != NULL; |
| 2346 | 2406 | ||
| 2347 | vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n", | 2407 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2408 | "hotkeys are %s\n", | ||
| 2348 | str_supported(tp_features.hotkey)); | 2409 | str_supported(tp_features.hotkey)); |
| 2349 | 2410 | ||
| 2350 | if (!tp_features.hotkey) | 2411 | if (!tp_features.hotkey) |
| @@ -2376,10 +2437,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2376 | * T4x, X31, and later | 2437 | * T4x, X31, and later |
| 2377 | */ | 2438 | */ |
| 2378 | tp_features.hotkey_mask = 1; | 2439 | tp_features.hotkey_mask = 1; |
| 2440 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, | ||
| 2441 | "firmware HKEY interface version: 0x%x\n", | ||
| 2442 | hkeyv); | ||
| 2379 | } | 2443 | } |
| 2380 | } | 2444 | } |
| 2381 | 2445 | ||
| 2382 | vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n", | 2446 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2447 | "hotkey masks are %s\n", | ||
| 2383 | str_supported(tp_features.hotkey_mask)); | 2448 | str_supported(tp_features.hotkey_mask)); |
| 2384 | 2449 | ||
| 2385 | if (tp_features.hotkey_mask) { | 2450 | if (tp_features.hotkey_mask) { |
| @@ -2396,10 +2461,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2396 | 2461 | ||
| 2397 | /* hotkey_source_mask *must* be zero for | 2462 | /* hotkey_source_mask *must* be zero for |
| 2398 | * the first hotkey_mask_get */ | 2463 | * the first hotkey_mask_get */ |
| 2399 | res = hotkey_status_get(&hotkey_orig_status); | ||
| 2400 | if (res) | ||
| 2401 | goto err_exit; | ||
| 2402 | |||
| 2403 | if (tp_features.hotkey_mask) { | 2464 | if (tp_features.hotkey_mask) { |
| 2404 | res = hotkey_mask_get(); | 2465 | res = hotkey_mask_get(); |
| 2405 | if (res) | 2466 | if (res) |
| @@ -2422,7 +2483,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2422 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; | 2483 | hotkey_source_mask = TPACPI_HKEY_NVRAM_GOOD_MASK; |
| 2423 | } | 2484 | } |
| 2424 | 2485 | ||
| 2425 | vdbg_printk(TPACPI_DBG_INIT, | 2486 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2426 | "hotkey source mask 0x%08x, polling freq %d\n", | 2487 | "hotkey source mask 0x%08x, polling freq %d\n", |
| 2427 | hotkey_source_mask, hotkey_poll_freq); | 2488 | hotkey_source_mask, hotkey_poll_freq); |
| 2428 | #endif | 2489 | #endif |
| @@ -2476,12 +2537,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2476 | } | 2537 | } |
| 2477 | 2538 | ||
| 2478 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { | 2539 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { |
| 2479 | dbg_printk(TPACPI_DBG_INIT, | 2540 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2480 | "using Lenovo default hot key map\n"); | 2541 | "using Lenovo default hot key map\n"); |
| 2481 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, | 2542 | memcpy(hotkey_keycode_map, &lenovo_keycode_map, |
| 2482 | TPACPI_HOTKEY_MAP_SIZE); | 2543 | TPACPI_HOTKEY_MAP_SIZE); |
| 2483 | } else { | 2544 | } else { |
| 2484 | dbg_printk(TPACPI_DBG_INIT, | 2545 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2485 | "using IBM default hot key map\n"); | 2546 | "using IBM default hot key map\n"); |
| 2486 | memcpy(hotkey_keycode_map, &ibm_keycode_map, | 2547 | memcpy(hotkey_keycode_map, &ibm_keycode_map, |
| 2487 | TPACPI_HOTKEY_MAP_SIZE); | 2548 | TPACPI_HOTKEY_MAP_SIZE); |
| @@ -2538,8 +2599,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2538 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); | 2599 | | (1 << TP_ACPI_HOTKEYSCAN_FNEND); |
| 2539 | } | 2600 | } |
| 2540 | 2601 | ||
| 2541 | dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); | 2602 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2542 | res = hotkey_status_set(1); | 2603 | "enabling firmware HKEY event interface...\n"); |
| 2604 | res = hotkey_status_set(true); | ||
| 2543 | if (res) { | 2605 | if (res) { |
| 2544 | hotkey_exit(); | 2606 | hotkey_exit(); |
| 2545 | return res; | 2607 | return res; |
| @@ -2552,8 +2614,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 2552 | return res; | 2614 | return res; |
| 2553 | } | 2615 | } |
| 2554 | 2616 | ||
| 2555 | dbg_printk(TPACPI_DBG_INIT, | 2617 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_HKEY, |
| 2556 | "legacy hot key reporting over procfs %s\n", | 2618 | "legacy ibm/hotkey event reporting over procfs %s\n", |
| 2557 | (hotkey_report_mode < 2) ? | 2619 | (hotkey_report_mode < 2) ? |
| 2558 | "enabled" : "disabled"); | 2620 | "enabled" : "disabled"); |
| 2559 | 2621 | ||
| @@ -2884,9 +2946,17 @@ static int hotkey_read(char *p) | |||
| 2884 | return len; | 2946 | return len; |
| 2885 | } | 2947 | } |
| 2886 | 2948 | ||
| 2949 | static void hotkey_enabledisable_warn(void) | ||
| 2950 | { | ||
| 2951 | tpacpi_log_usertask("procfs hotkey enable/disable"); | ||
| 2952 | WARN(1, TPACPI_WARN | ||
| 2953 | "hotkey enable/disable functionality has been " | ||
| 2954 | "removed from the driver. Hotkeys are always enabled.\n"); | ||
| 2955 | } | ||
| 2956 | |||
| 2887 | static int hotkey_write(char *buf) | 2957 | static int hotkey_write(char *buf) |
| 2888 | { | 2958 | { |
| 2889 | int res, status; | 2959 | int res; |
| 2890 | u32 mask; | 2960 | u32 mask; |
| 2891 | char *cmd; | 2961 | char *cmd; |
| 2892 | 2962 | ||
| @@ -2896,17 +2966,16 @@ static int hotkey_write(char *buf) | |||
| 2896 | if (mutex_lock_killable(&hotkey_mutex)) | 2966 | if (mutex_lock_killable(&hotkey_mutex)) |
| 2897 | return -ERESTARTSYS; | 2967 | return -ERESTARTSYS; |
| 2898 | 2968 | ||
| 2899 | status = -1; | ||
| 2900 | mask = hotkey_mask; | 2969 | mask = hotkey_mask; |
| 2901 | 2970 | ||
| 2902 | res = 0; | 2971 | res = 0; |
| 2903 | while ((cmd = next_cmd(&buf))) { | 2972 | while ((cmd = next_cmd(&buf))) { |
| 2904 | if (strlencmp(cmd, "enable") == 0) { | 2973 | if (strlencmp(cmd, "enable") == 0) { |
| 2905 | status = 1; | 2974 | hotkey_enabledisable_warn(); |
| 2906 | } else if (strlencmp(cmd, "disable") == 0) { | 2975 | } else if (strlencmp(cmd, "disable") == 0) { |
| 2907 | status = 0; | 2976 | hotkey_enabledisable_warn(); |
| 2977 | res = -EPERM; | ||
| 2908 | } else if (strlencmp(cmd, "reset") == 0) { | 2978 | } else if (strlencmp(cmd, "reset") == 0) { |
| 2909 | status = hotkey_orig_status; | ||
| 2910 | mask = hotkey_orig_mask; | 2979 | mask = hotkey_orig_mask; |
| 2911 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { | 2980 | } else if (sscanf(cmd, "0x%x", &mask) == 1) { |
| 2912 | /* mask set */ | 2981 | /* mask set */ |
| @@ -2917,8 +2986,10 @@ static int hotkey_write(char *buf) | |||
| 2917 | goto errexit; | 2986 | goto errexit; |
| 2918 | } | 2987 | } |
| 2919 | } | 2988 | } |
| 2920 | if (status != -1) | 2989 | |
| 2921 | res = hotkey_status_set(status); | 2990 | if (!res) |
| 2991 | tpacpi_disclose_usertask("procfs hotkey", | ||
| 2992 | "set mask to 0x%08x\n", mask); | ||
| 2922 | 2993 | ||
| 2923 | if (!res && mask != hotkey_mask) | 2994 | if (!res && mask != hotkey_mask) |
| 2924 | res = hotkey_mask_set(mask); | 2995 | res = hotkey_mask_set(mask); |
| @@ -2971,13 +3042,17 @@ enum { | |||
| 2971 | TP_ACPI_BLTH_SAVE_STATE = 0x05, /* Save state for S4/S5 */ | 3042 | TP_ACPI_BLTH_SAVE_STATE = 0x05, /* Save state for S4/S5 */ |
| 2972 | }; | 3043 | }; |
| 2973 | 3044 | ||
| 3045 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" | ||
| 3046 | |||
| 2974 | static struct rfkill *tpacpi_bluetooth_rfkill; | 3047 | static struct rfkill *tpacpi_bluetooth_rfkill; |
| 2975 | 3048 | ||
| 2976 | static void bluetooth_suspend(pm_message_t state) | 3049 | static void bluetooth_suspend(pm_message_t state) |
| 2977 | { | 3050 | { |
| 2978 | /* Try to make sure radio will resume powered off */ | 3051 | /* Try to make sure radio will resume powered off */ |
| 2979 | acpi_evalf(NULL, NULL, "\\BLTH", "vd", | 3052 | if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd", |
| 2980 | TP_ACPI_BLTH_PWR_OFF_ON_RESUME); | 3053 | TP_ACPI_BLTH_PWR_OFF_ON_RESUME)) |
| 3054 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3055 | "bluetooth power down on resume request failed\n"); | ||
| 2981 | } | 3056 | } |
| 2982 | 3057 | ||
| 2983 | static int bluetooth_get_radiosw(void) | 3058 | static int bluetooth_get_radiosw(void) |
| @@ -3015,6 +3090,10 @@ static void bluetooth_update_rfk(void) | |||
| 3015 | if (status < 0) | 3090 | if (status < 0) |
| 3016 | return; | 3091 | return; |
| 3017 | rfkill_force_state(tpacpi_bluetooth_rfkill, status); | 3092 | rfkill_force_state(tpacpi_bluetooth_rfkill, status); |
| 3093 | |||
| 3094 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3095 | "forced rfkill state to %d\n", | ||
| 3096 | status); | ||
| 3018 | } | 3097 | } |
| 3019 | 3098 | ||
| 3020 | static int bluetooth_set_radiosw(int radio_on, int update_rfk) | 3099 | static int bluetooth_set_radiosw(int radio_on, int update_rfk) |
| @@ -3030,6 +3109,9 @@ static int bluetooth_set_radiosw(int radio_on, int update_rfk) | |||
| 3030 | && radio_on) | 3109 | && radio_on) |
| 3031 | return -EPERM; | 3110 | return -EPERM; |
| 3032 | 3111 | ||
| 3112 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3113 | "will %s bluetooth\n", radio_on ? "enable" : "disable"); | ||
| 3114 | |||
| 3033 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3115 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
| 3034 | if (dbg_bluetoothemul) { | 3116 | if (dbg_bluetoothemul) { |
| 3035 | tpacpi_bluetooth_emulstate = !!radio_on; | 3117 | tpacpi_bluetooth_emulstate = !!radio_on; |
| @@ -3060,6 +3142,8 @@ static ssize_t bluetooth_enable_show(struct device *dev, | |||
| 3060 | { | 3142 | { |
| 3061 | int status; | 3143 | int status; |
| 3062 | 3144 | ||
| 3145 | printk_deprecated_rfkill_attribute("bluetooth_enable"); | ||
| 3146 | |||
| 3063 | status = bluetooth_get_radiosw(); | 3147 | status = bluetooth_get_radiosw(); |
| 3064 | if (status < 0) | 3148 | if (status < 0) |
| 3065 | return status; | 3149 | return status; |
| @@ -3075,9 +3159,13 @@ static ssize_t bluetooth_enable_store(struct device *dev, | |||
| 3075 | unsigned long t; | 3159 | unsigned long t; |
| 3076 | int res; | 3160 | int res; |
| 3077 | 3161 | ||
| 3162 | printk_deprecated_rfkill_attribute("bluetooth_enable"); | ||
| 3163 | |||
| 3078 | if (parse_strtoul(buf, 1, &t)) | 3164 | if (parse_strtoul(buf, 1, &t)) |
| 3079 | return -EINVAL; | 3165 | return -EINVAL; |
| 3080 | 3166 | ||
| 3167 | tpacpi_disclose_usertask("bluetooth_enable", "set to %ld\n", t); | ||
| 3168 | |||
| 3081 | res = bluetooth_set_radiosw(t, 1); | 3169 | res = bluetooth_set_radiosw(t, 1); |
| 3082 | 3170 | ||
| 3083 | return (res) ? res : count; | 3171 | return (res) ? res : count; |
| @@ -3111,6 +3199,8 @@ static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state) | |||
| 3111 | 3199 | ||
| 3112 | static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) | 3200 | static int tpacpi_bluetooth_rfk_set(void *data, enum rfkill_state state) |
| 3113 | { | 3201 | { |
| 3202 | dbg_printk(TPACPI_DBG_RFKILL, | ||
| 3203 | "request to change radio state to %d\n", state); | ||
| 3114 | return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | 3204 | return bluetooth_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); |
| 3115 | } | 3205 | } |
| 3116 | 3206 | ||
| @@ -3121,6 +3211,9 @@ static void bluetooth_shutdown(void) | |||
| 3121 | TP_ACPI_BLTH_SAVE_STATE)) | 3211 | TP_ACPI_BLTH_SAVE_STATE)) |
| 3122 | printk(TPACPI_NOTICE | 3212 | printk(TPACPI_NOTICE |
| 3123 | "failed to save bluetooth state to NVRAM\n"); | 3213 | "failed to save bluetooth state to NVRAM\n"); |
| 3214 | else | ||
| 3215 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3216 | "bluestooth state saved to NVRAM\n"); | ||
| 3124 | } | 3217 | } |
| 3125 | 3218 | ||
| 3126 | static void bluetooth_exit(void) | 3219 | static void bluetooth_exit(void) |
| @@ -3139,7 +3232,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
| 3139 | int res; | 3232 | int res; |
| 3140 | int status = 0; | 3233 | int status = 0; |
| 3141 | 3234 | ||
| 3142 | vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); | 3235 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3236 | "initializing bluetooth subdriver\n"); | ||
| 3143 | 3237 | ||
| 3144 | TPACPI_ACPIHANDLE_INIT(hkey); | 3238 | TPACPI_ACPIHANDLE_INIT(hkey); |
| 3145 | 3239 | ||
| @@ -3148,7 +3242,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
| 3148 | tp_features.bluetooth = hkey_handle && | 3242 | tp_features.bluetooth = hkey_handle && |
| 3149 | acpi_evalf(hkey_handle, &status, "GBDC", "qd"); | 3243 | acpi_evalf(hkey_handle, &status, "GBDC", "qd"); |
| 3150 | 3244 | ||
| 3151 | vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", | 3245 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3246 | "bluetooth is %s, status 0x%02x\n", | ||
| 3152 | str_supported(tp_features.bluetooth), | 3247 | str_supported(tp_features.bluetooth), |
| 3153 | status); | 3248 | status); |
| 3154 | 3249 | ||
| @@ -3163,7 +3258,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
| 3163 | !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { | 3258 | !(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { |
| 3164 | /* no bluetooth hardware present in system */ | 3259 | /* no bluetooth hardware present in system */ |
| 3165 | tp_features.bluetooth = 0; | 3260 | tp_features.bluetooth = 0; |
| 3166 | dbg_printk(TPACPI_DBG_INIT, | 3261 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3167 | "bluetooth hardware not installed\n"); | 3262 | "bluetooth hardware not installed\n"); |
| 3168 | } | 3263 | } |
| 3169 | 3264 | ||
| @@ -3178,7 +3273,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
| 3178 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, | 3273 | res = tpacpi_new_rfkill(TPACPI_RFK_BLUETOOTH_SW_ID, |
| 3179 | &tpacpi_bluetooth_rfkill, | 3274 | &tpacpi_bluetooth_rfkill, |
| 3180 | RFKILL_TYPE_BLUETOOTH, | 3275 | RFKILL_TYPE_BLUETOOTH, |
| 3181 | "tpacpi_bluetooth_sw", | 3276 | TPACPI_RFK_BLUETOOTH_SW_NAME, |
| 3182 | true, | 3277 | true, |
| 3183 | tpacpi_bluetooth_rfk_set, | 3278 | tpacpi_bluetooth_rfk_set, |
| 3184 | tpacpi_bluetooth_rfk_get); | 3279 | tpacpi_bluetooth_rfk_get); |
| @@ -3211,19 +3306,27 @@ static int bluetooth_read(char *p) | |||
| 3211 | static int bluetooth_write(char *buf) | 3306 | static int bluetooth_write(char *buf) |
| 3212 | { | 3307 | { |
| 3213 | char *cmd; | 3308 | char *cmd; |
| 3309 | int state = -1; | ||
| 3214 | 3310 | ||
| 3215 | if (!tp_features.bluetooth) | 3311 | if (!tp_features.bluetooth) |
| 3216 | return -ENODEV; | 3312 | return -ENODEV; |
| 3217 | 3313 | ||
| 3218 | while ((cmd = next_cmd(&buf))) { | 3314 | while ((cmd = next_cmd(&buf))) { |
| 3219 | if (strlencmp(cmd, "enable") == 0) { | 3315 | if (strlencmp(cmd, "enable") == 0) { |
| 3220 | bluetooth_set_radiosw(1, 1); | 3316 | state = 1; |
| 3221 | } else if (strlencmp(cmd, "disable") == 0) { | 3317 | } else if (strlencmp(cmd, "disable") == 0) { |
| 3222 | bluetooth_set_radiosw(0, 1); | 3318 | state = 0; |
| 3223 | } else | 3319 | } else |
| 3224 | return -EINVAL; | 3320 | return -EINVAL; |
| 3225 | } | 3321 | } |
| 3226 | 3322 | ||
| 3323 | if (state != -1) { | ||
| 3324 | tpacpi_disclose_usertask("procfs bluetooth", | ||
| 3325 | "attempt to %s\n", | ||
| 3326 | state ? "enable" : "disable"); | ||
| 3327 | bluetooth_set_radiosw(state, 1); | ||
| 3328 | } | ||
| 3329 | |||
| 3227 | return 0; | 3330 | return 0; |
| 3228 | } | 3331 | } |
| 3229 | 3332 | ||
| @@ -3248,13 +3351,17 @@ enum { | |||
| 3248 | off / last state */ | 3351 | off / last state */ |
| 3249 | }; | 3352 | }; |
| 3250 | 3353 | ||
| 3354 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" | ||
| 3355 | |||
| 3251 | static struct rfkill *tpacpi_wan_rfkill; | 3356 | static struct rfkill *tpacpi_wan_rfkill; |
| 3252 | 3357 | ||
| 3253 | static void wan_suspend(pm_message_t state) | 3358 | static void wan_suspend(pm_message_t state) |
| 3254 | { | 3359 | { |
| 3255 | /* Try to make sure radio will resume powered off */ | 3360 | /* Try to make sure radio will resume powered off */ |
| 3256 | acpi_evalf(NULL, NULL, "\\WGSV", "qvd", | 3361 | if (!acpi_evalf(NULL, NULL, "\\WGSV", "qvd", |
| 3257 | TP_ACPI_WGSV_PWR_OFF_ON_RESUME); | 3362 | TP_ACPI_WGSV_PWR_OFF_ON_RESUME)) |
| 3363 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3364 | "WWAN power down on resume request failed\n"); | ||
| 3258 | } | 3365 | } |
| 3259 | 3366 | ||
| 3260 | static int wan_get_radiosw(void) | 3367 | static int wan_get_radiosw(void) |
| @@ -3292,6 +3399,10 @@ static void wan_update_rfk(void) | |||
| 3292 | if (status < 0) | 3399 | if (status < 0) |
| 3293 | return; | 3400 | return; |
| 3294 | rfkill_force_state(tpacpi_wan_rfkill, status); | 3401 | rfkill_force_state(tpacpi_wan_rfkill, status); |
| 3402 | |||
| 3403 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3404 | "forced rfkill state to %d\n", | ||
| 3405 | status); | ||
| 3295 | } | 3406 | } |
| 3296 | 3407 | ||
| 3297 | static int wan_set_radiosw(int radio_on, int update_rfk) | 3408 | static int wan_set_radiosw(int radio_on, int update_rfk) |
| @@ -3307,6 +3418,9 @@ static int wan_set_radiosw(int radio_on, int update_rfk) | |||
| 3307 | && radio_on) | 3418 | && radio_on) |
| 3308 | return -EPERM; | 3419 | return -EPERM; |
| 3309 | 3420 | ||
| 3421 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3422 | "will %s WWAN\n", radio_on ? "enable" : "disable"); | ||
| 3423 | |||
| 3310 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3424 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
| 3311 | if (dbg_wwanemul) { | 3425 | if (dbg_wwanemul) { |
| 3312 | tpacpi_wwan_emulstate = !!radio_on; | 3426 | tpacpi_wwan_emulstate = !!radio_on; |
| @@ -3337,6 +3451,8 @@ static ssize_t wan_enable_show(struct device *dev, | |||
| 3337 | { | 3451 | { |
| 3338 | int status; | 3452 | int status; |
| 3339 | 3453 | ||
| 3454 | printk_deprecated_rfkill_attribute("wwan_enable"); | ||
| 3455 | |||
| 3340 | status = wan_get_radiosw(); | 3456 | status = wan_get_radiosw(); |
| 3341 | if (status < 0) | 3457 | if (status < 0) |
| 3342 | return status; | 3458 | return status; |
| @@ -3352,9 +3468,13 @@ static ssize_t wan_enable_store(struct device *dev, | |||
| 3352 | unsigned long t; | 3468 | unsigned long t; |
| 3353 | int res; | 3469 | int res; |
| 3354 | 3470 | ||
| 3471 | printk_deprecated_rfkill_attribute("wwan_enable"); | ||
| 3472 | |||
| 3355 | if (parse_strtoul(buf, 1, &t)) | 3473 | if (parse_strtoul(buf, 1, &t)) |
| 3356 | return -EINVAL; | 3474 | return -EINVAL; |
| 3357 | 3475 | ||
| 3476 | tpacpi_disclose_usertask("wwan_enable", "set to %ld\n", t); | ||
| 3477 | |||
| 3358 | res = wan_set_radiosw(t, 1); | 3478 | res = wan_set_radiosw(t, 1); |
| 3359 | 3479 | ||
| 3360 | return (res) ? res : count; | 3480 | return (res) ? res : count; |
| @@ -3388,6 +3508,8 @@ static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state) | |||
| 3388 | 3508 | ||
| 3389 | static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) | 3509 | static int tpacpi_wan_rfk_set(void *data, enum rfkill_state state) |
| 3390 | { | 3510 | { |
| 3511 | dbg_printk(TPACPI_DBG_RFKILL, | ||
| 3512 | "request to change radio state to %d\n", state); | ||
| 3391 | return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | 3513 | return wan_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); |
| 3392 | } | 3514 | } |
| 3393 | 3515 | ||
| @@ -3398,6 +3520,9 @@ static void wan_shutdown(void) | |||
| 3398 | TP_ACPI_WGSV_SAVE_STATE)) | 3520 | TP_ACPI_WGSV_SAVE_STATE)) |
| 3399 | printk(TPACPI_NOTICE | 3521 | printk(TPACPI_NOTICE |
| 3400 | "failed to save WWAN state to NVRAM\n"); | 3522 | "failed to save WWAN state to NVRAM\n"); |
| 3523 | else | ||
| 3524 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3525 | "WWAN state saved to NVRAM\n"); | ||
| 3401 | } | 3526 | } |
| 3402 | 3527 | ||
| 3403 | static void wan_exit(void) | 3528 | static void wan_exit(void) |
| @@ -3416,14 +3541,16 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
| 3416 | int res; | 3541 | int res; |
| 3417 | int status = 0; | 3542 | int status = 0; |
| 3418 | 3543 | ||
| 3419 | vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n"); | 3544 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3545 | "initializing wan subdriver\n"); | ||
| 3420 | 3546 | ||
| 3421 | TPACPI_ACPIHANDLE_INIT(hkey); | 3547 | TPACPI_ACPIHANDLE_INIT(hkey); |
| 3422 | 3548 | ||
| 3423 | tp_features.wan = hkey_handle && | 3549 | tp_features.wan = hkey_handle && |
| 3424 | acpi_evalf(hkey_handle, &status, "GWAN", "qd"); | 3550 | acpi_evalf(hkey_handle, &status, "GWAN", "qd"); |
| 3425 | 3551 | ||
| 3426 | vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n", | 3552 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3553 | "wan is %s, status 0x%02x\n", | ||
| 3427 | str_supported(tp_features.wan), | 3554 | str_supported(tp_features.wan), |
| 3428 | status); | 3555 | status); |
| 3429 | 3556 | ||
| @@ -3438,7 +3565,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
| 3438 | !(status & TP_ACPI_WANCARD_HWPRESENT)) { | 3565 | !(status & TP_ACPI_WANCARD_HWPRESENT)) { |
| 3439 | /* no wan hardware present in system */ | 3566 | /* no wan hardware present in system */ |
| 3440 | tp_features.wan = 0; | 3567 | tp_features.wan = 0; |
| 3441 | dbg_printk(TPACPI_DBG_INIT, | 3568 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3442 | "wan hardware not installed\n"); | 3569 | "wan hardware not installed\n"); |
| 3443 | } | 3570 | } |
| 3444 | 3571 | ||
| @@ -3453,7 +3580,7 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
| 3453 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, | 3580 | res = tpacpi_new_rfkill(TPACPI_RFK_WWAN_SW_ID, |
| 3454 | &tpacpi_wan_rfkill, | 3581 | &tpacpi_wan_rfkill, |
| 3455 | RFKILL_TYPE_WWAN, | 3582 | RFKILL_TYPE_WWAN, |
| 3456 | "tpacpi_wwan_sw", | 3583 | TPACPI_RFK_WWAN_SW_NAME, |
| 3457 | true, | 3584 | true, |
| 3458 | tpacpi_wan_rfk_set, | 3585 | tpacpi_wan_rfk_set, |
| 3459 | tpacpi_wan_rfk_get); | 3586 | tpacpi_wan_rfk_get); |
| @@ -3471,6 +3598,8 @@ static int wan_read(char *p) | |||
| 3471 | int len = 0; | 3598 | int len = 0; |
| 3472 | int status = wan_get_radiosw(); | 3599 | int status = wan_get_radiosw(); |
| 3473 | 3600 | ||
| 3601 | tpacpi_disclose_usertask("procfs wan", "read"); | ||
| 3602 | |||
| 3474 | if (!tp_features.wan) | 3603 | if (!tp_features.wan) |
| 3475 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3604 | len += sprintf(p + len, "status:\t\tnot supported\n"); |
| 3476 | else { | 3605 | else { |
| @@ -3486,19 +3615,27 @@ static int wan_read(char *p) | |||
| 3486 | static int wan_write(char *buf) | 3615 | static int wan_write(char *buf) |
| 3487 | { | 3616 | { |
| 3488 | char *cmd; | 3617 | char *cmd; |
| 3618 | int state = -1; | ||
| 3489 | 3619 | ||
| 3490 | if (!tp_features.wan) | 3620 | if (!tp_features.wan) |
| 3491 | return -ENODEV; | 3621 | return -ENODEV; |
| 3492 | 3622 | ||
| 3493 | while ((cmd = next_cmd(&buf))) { | 3623 | while ((cmd = next_cmd(&buf))) { |
| 3494 | if (strlencmp(cmd, "enable") == 0) { | 3624 | if (strlencmp(cmd, "enable") == 0) { |
| 3495 | wan_set_radiosw(1, 1); | 3625 | state = 1; |
| 3496 | } else if (strlencmp(cmd, "disable") == 0) { | 3626 | } else if (strlencmp(cmd, "disable") == 0) { |
| 3497 | wan_set_radiosw(0, 1); | 3627 | state = 0; |
| 3498 | } else | 3628 | } else |
| 3499 | return -EINVAL; | 3629 | return -EINVAL; |
| 3500 | } | 3630 | } |
| 3501 | 3631 | ||
| 3632 | if (state != -1) { | ||
| 3633 | tpacpi_disclose_usertask("procfs wan", | ||
| 3634 | "attempt to %s\n", | ||
| 3635 | state ? "enable" : "disable"); | ||
| 3636 | wan_set_radiosw(state, 1); | ||
| 3637 | } | ||
| 3638 | |||
| 3502 | return 0; | 3639 | return 0; |
| 3503 | } | 3640 | } |
| 3504 | 3641 | ||
| @@ -3521,6 +3658,8 @@ enum { | |||
| 3521 | TP_ACPI_UWB_RADIOSSW = 0x02, /* UWB radio enabled */ | 3658 | TP_ACPI_UWB_RADIOSSW = 0x02, /* UWB radio enabled */ |
| 3522 | }; | 3659 | }; |
| 3523 | 3660 | ||
| 3661 | #define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw" | ||
| 3662 | |||
| 3524 | static struct rfkill *tpacpi_uwb_rfkill; | 3663 | static struct rfkill *tpacpi_uwb_rfkill; |
| 3525 | 3664 | ||
| 3526 | static int uwb_get_radiosw(void) | 3665 | static int uwb_get_radiosw(void) |
| @@ -3558,6 +3697,10 @@ static void uwb_update_rfk(void) | |||
| 3558 | if (status < 0) | 3697 | if (status < 0) |
| 3559 | return; | 3698 | return; |
| 3560 | rfkill_force_state(tpacpi_uwb_rfkill, status); | 3699 | rfkill_force_state(tpacpi_uwb_rfkill, status); |
| 3700 | |||
| 3701 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3702 | "forced rfkill state to %d\n", | ||
| 3703 | status); | ||
| 3561 | } | 3704 | } |
| 3562 | 3705 | ||
| 3563 | static int uwb_set_radiosw(int radio_on, int update_rfk) | 3706 | static int uwb_set_radiosw(int radio_on, int update_rfk) |
| @@ -3573,6 +3716,9 @@ static int uwb_set_radiosw(int radio_on, int update_rfk) | |||
| 3573 | && radio_on) | 3716 | && radio_on) |
| 3574 | return -EPERM; | 3717 | return -EPERM; |
| 3575 | 3718 | ||
| 3719 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3720 | "will %s UWB\n", radio_on ? "enable" : "disable"); | ||
| 3721 | |||
| 3576 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3722 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
| 3577 | if (dbg_uwbemul) { | 3723 | if (dbg_uwbemul) { |
| 3578 | tpacpi_uwb_emulstate = !!radio_on; | 3724 | tpacpi_uwb_emulstate = !!radio_on; |
| @@ -3607,6 +3753,8 @@ static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state) | |||
| 3607 | 3753 | ||
| 3608 | static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) | 3754 | static int tpacpi_uwb_rfk_set(void *data, enum rfkill_state state) |
| 3609 | { | 3755 | { |
| 3756 | dbg_printk(TPACPI_DBG_RFKILL, | ||
| 3757 | "request to change radio state to %d\n", state); | ||
| 3610 | return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); | 3758 | return uwb_set_radiosw((state == RFKILL_STATE_UNBLOCKED), 0); |
| 3611 | } | 3759 | } |
| 3612 | 3760 | ||
| @@ -3621,14 +3769,16 @@ static int __init uwb_init(struct ibm_init_struct *iibm) | |||
| 3621 | int res; | 3769 | int res; |
| 3622 | int status = 0; | 3770 | int status = 0; |
| 3623 | 3771 | ||
| 3624 | vdbg_printk(TPACPI_DBG_INIT, "initializing uwb subdriver\n"); | 3772 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3773 | "initializing uwb subdriver\n"); | ||
| 3625 | 3774 | ||
| 3626 | TPACPI_ACPIHANDLE_INIT(hkey); | 3775 | TPACPI_ACPIHANDLE_INIT(hkey); |
| 3627 | 3776 | ||
| 3628 | tp_features.uwb = hkey_handle && | 3777 | tp_features.uwb = hkey_handle && |
| 3629 | acpi_evalf(hkey_handle, &status, "GUWB", "qd"); | 3778 | acpi_evalf(hkey_handle, &status, "GUWB", "qd"); |
| 3630 | 3779 | ||
| 3631 | vdbg_printk(TPACPI_DBG_INIT, "uwb is %s, status 0x%02x\n", | 3780 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_RFKILL, |
| 3781 | "uwb is %s, status 0x%02x\n", | ||
| 3632 | str_supported(tp_features.uwb), | 3782 | str_supported(tp_features.uwb), |
| 3633 | status); | 3783 | status); |
| 3634 | 3784 | ||
| @@ -3653,7 +3803,7 @@ static int __init uwb_init(struct ibm_init_struct *iibm) | |||
| 3653 | res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, | 3803 | res = tpacpi_new_rfkill(TPACPI_RFK_UWB_SW_ID, |
| 3654 | &tpacpi_uwb_rfkill, | 3804 | &tpacpi_uwb_rfkill, |
| 3655 | RFKILL_TYPE_UWB, | 3805 | RFKILL_TYPE_UWB, |
| 3656 | "tpacpi_uwb_sw", | 3806 | TPACPI_RFK_UWB_SW_NAME, |
| 3657 | false, | 3807 | false, |
| 3658 | tpacpi_uwb_rfk_set, | 3808 | tpacpi_uwb_rfk_set, |
| 3659 | tpacpi_uwb_rfk_get); | 3809 | tpacpi_uwb_rfk_get); |
| @@ -4602,6 +4752,16 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = { | |||
| 4602 | "tpacpi::unknown_led", | 4752 | "tpacpi::unknown_led", |
| 4603 | "tpacpi::standby", | 4753 | "tpacpi::standby", |
| 4604 | }; | 4754 | }; |
| 4755 | #define TPACPI_SAFE_LEDS 0x0081U | ||
| 4756 | |||
| 4757 | static inline bool tpacpi_is_led_restricted(const unsigned int led) | ||
| 4758 | { | ||
| 4759 | #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS | ||
| 4760 | return false; | ||
| 4761 | #else | ||
| 4762 | return (TPACPI_SAFE_LEDS & (1 << led)) == 0; | ||
| 4763 | #endif | ||
| 4764 | } | ||
| 4605 | 4765 | ||
| 4606 | static int led_get_status(const unsigned int led) | 4766 | static int led_get_status(const unsigned int led) |
| 4607 | { | 4767 | { |
| @@ -4639,16 +4799,20 @@ static int led_set_status(const unsigned int led, | |||
| 4639 | switch (led_supported) { | 4799 | switch (led_supported) { |
| 4640 | case TPACPI_LED_570: | 4800 | case TPACPI_LED_570: |
| 4641 | /* 570 */ | 4801 | /* 570 */ |
| 4642 | if (led > 7) | 4802 | if (unlikely(led > 7)) |
| 4643 | return -EINVAL; | 4803 | return -EINVAL; |
| 4804 | if (unlikely(tpacpi_is_led_restricted(led))) | ||
| 4805 | return -EPERM; | ||
| 4644 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | 4806 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", |
| 4645 | (1 << led), led_sled_arg1[ledstatus])) | 4807 | (1 << led), led_sled_arg1[ledstatus])) |
| 4646 | rc = -EIO; | 4808 | rc = -EIO; |
| 4647 | break; | 4809 | break; |
| 4648 | case TPACPI_LED_OLD: | 4810 | case TPACPI_LED_OLD: |
| 4649 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ | 4811 | /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */ |
| 4650 | if (led > 7) | 4812 | if (unlikely(led > 7)) |
| 4651 | return -EINVAL; | 4813 | return -EINVAL; |
| 4814 | if (unlikely(tpacpi_is_led_restricted(led))) | ||
| 4815 | return -EPERM; | ||
| 4652 | rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); | 4816 | rc = ec_write(TPACPI_LED_EC_HLMS, (1 << led)); |
| 4653 | if (rc >= 0) | 4817 | if (rc >= 0) |
| 4654 | rc = ec_write(TPACPI_LED_EC_HLBL, | 4818 | rc = ec_write(TPACPI_LED_EC_HLBL, |
| @@ -4659,6 +4823,10 @@ static int led_set_status(const unsigned int led, | |||
| 4659 | break; | 4823 | break; |
| 4660 | case TPACPI_LED_NEW: | 4824 | case TPACPI_LED_NEW: |
| 4661 | /* all others */ | 4825 | /* all others */ |
| 4826 | if (unlikely(led >= TPACPI_LED_NUMLEDS)) | ||
| 4827 | return -EINVAL; | ||
| 4828 | if (unlikely(tpacpi_is_led_restricted(led))) | ||
| 4829 | return -EPERM; | ||
| 4662 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", | 4830 | if (!acpi_evalf(led_handle, NULL, NULL, "vdd", |
| 4663 | led, led_led_arg1[ledstatus])) | 4831 | led, led_led_arg1[ledstatus])) |
| 4664 | rc = -EIO; | 4832 | rc = -EIO; |
| @@ -4751,6 +4919,30 @@ static void led_exit(void) | |||
| 4751 | kfree(tpacpi_leds); | 4919 | kfree(tpacpi_leds); |
| 4752 | } | 4920 | } |
| 4753 | 4921 | ||
| 4922 | static int __init tpacpi_init_led(unsigned int led) | ||
| 4923 | { | ||
| 4924 | int rc; | ||
| 4925 | |||
| 4926 | tpacpi_leds[led].led = led; | ||
| 4927 | |||
| 4928 | tpacpi_leds[led].led_classdev.brightness_set = &led_sysfs_set; | ||
| 4929 | tpacpi_leds[led].led_classdev.blink_set = &led_sysfs_blink_set; | ||
| 4930 | if (led_supported == TPACPI_LED_570) | ||
| 4931 | tpacpi_leds[led].led_classdev.brightness_get = | ||
| 4932 | &led_sysfs_get; | ||
| 4933 | |||
| 4934 | tpacpi_leds[led].led_classdev.name = tpacpi_led_names[led]; | ||
| 4935 | |||
| 4936 | INIT_WORK(&tpacpi_leds[led].work, led_set_status_worker); | ||
| 4937 | |||
| 4938 | rc = led_classdev_register(&tpacpi_pdev->dev, | ||
| 4939 | &tpacpi_leds[led].led_classdev); | ||
| 4940 | if (rc < 0) | ||
| 4941 | tpacpi_leds[led].led_classdev.name = NULL; | ||
| 4942 | |||
| 4943 | return rc; | ||
| 4944 | } | ||
| 4945 | |||
| 4754 | static int __init led_init(struct ibm_init_struct *iibm) | 4946 | static int __init led_init(struct ibm_init_struct *iibm) |
| 4755 | { | 4947 | { |
| 4756 | unsigned int i; | 4948 | unsigned int i; |
| @@ -4784,27 +4976,21 @@ static int __init led_init(struct ibm_init_struct *iibm) | |||
| 4784 | } | 4976 | } |
| 4785 | 4977 | ||
| 4786 | for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { | 4978 | for (i = 0; i < TPACPI_LED_NUMLEDS; i++) { |
| 4787 | tpacpi_leds[i].led = i; | 4979 | if (!tpacpi_is_led_restricted(i)) { |
| 4788 | 4980 | rc = tpacpi_init_led(i); | |
| 4789 | tpacpi_leds[i].led_classdev.brightness_set = &led_sysfs_set; | 4981 | if (rc < 0) { |
| 4790 | tpacpi_leds[i].led_classdev.blink_set = &led_sysfs_blink_set; | 4982 | led_exit(); |
| 4791 | if (led_supported == TPACPI_LED_570) | 4983 | return rc; |
| 4792 | tpacpi_leds[i].led_classdev.brightness_get = | 4984 | } |
| 4793 | &led_sysfs_get; | ||
| 4794 | |||
| 4795 | tpacpi_leds[i].led_classdev.name = tpacpi_led_names[i]; | ||
| 4796 | |||
| 4797 | INIT_WORK(&tpacpi_leds[i].work, led_set_status_worker); | ||
| 4798 | |||
| 4799 | rc = led_classdev_register(&tpacpi_pdev->dev, | ||
| 4800 | &tpacpi_leds[i].led_classdev); | ||
| 4801 | if (rc < 0) { | ||
| 4802 | tpacpi_leds[i].led_classdev.name = NULL; | ||
| 4803 | led_exit(); | ||
| 4804 | return rc; | ||
| 4805 | } | 4985 | } |
| 4806 | } | 4986 | } |
| 4807 | 4987 | ||
| 4988 | #ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS | ||
| 4989 | if (led_supported != TPACPI_LED_NONE) | ||
| 4990 | printk(TPACPI_NOTICE | ||
| 4991 | "warning: userspace override of important " | ||
| 4992 | "firmware LEDs is enabled\n"); | ||
| 4993 | #endif | ||
| 4808 | return (led_supported != TPACPI_LED_NONE)? 0 : 1; | 4994 | return (led_supported != TPACPI_LED_NONE)? 0 : 1; |
| 4809 | } | 4995 | } |
| 4810 | 4996 | ||
| @@ -5340,6 +5526,20 @@ static struct ibm_struct ecdump_driver_data = { | |||
| 5340 | 5526 | ||
| 5341 | #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" | 5527 | #define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen" |
| 5342 | 5528 | ||
| 5529 | /* | ||
| 5530 | * ThinkPads can read brightness from two places: EC HBRV (0x31), or | ||
| 5531 | * CMOS NVRAM byte 0x5E, bits 0-3. | ||
| 5532 | * | ||
| 5533 | * EC HBRV (0x31) has the following layout | ||
| 5534 | * Bit 7: unknown function | ||
| 5535 | * Bit 6: unknown function | ||
| 5536 | * Bit 5: Z: honour scale changes, NZ: ignore scale changes | ||
| 5537 | * Bit 4: must be set to zero to avoid problems | ||
| 5538 | * Bit 3-0: backlight brightness level | ||
| 5539 | * | ||
| 5540 | * brightness_get_raw returns status data in the HBRV layout | ||
| 5541 | */ | ||
| 5542 | |||
| 5343 | enum { | 5543 | enum { |
| 5344 | TP_EC_BACKLIGHT = 0x31, | 5544 | TP_EC_BACKLIGHT = 0x31, |
| 5345 | 5545 | ||
| @@ -5349,108 +5549,164 @@ enum { | |||
| 5349 | TP_EC_BACKLIGHT_MAPSW = 0x20, | 5549 | TP_EC_BACKLIGHT_MAPSW = 0x20, |
| 5350 | }; | 5550 | }; |
| 5351 | 5551 | ||
| 5552 | enum tpacpi_brightness_access_mode { | ||
| 5553 | TPACPI_BRGHT_MODE_AUTO = 0, /* Not implemented yet */ | ||
| 5554 | TPACPI_BRGHT_MODE_EC, /* EC control */ | ||
| 5555 | TPACPI_BRGHT_MODE_UCMS_STEP, /* UCMS step-based control */ | ||
| 5556 | TPACPI_BRGHT_MODE_ECNVRAM, /* EC control w/ NVRAM store */ | ||
| 5557 | TPACPI_BRGHT_MODE_MAX | ||
| 5558 | }; | ||
| 5559 | |||
| 5352 | static struct backlight_device *ibm_backlight_device; | 5560 | static struct backlight_device *ibm_backlight_device; |
| 5353 | static int brightness_mode; | 5561 | |
| 5562 | static enum tpacpi_brightness_access_mode brightness_mode = | ||
| 5563 | TPACPI_BRGHT_MODE_MAX; | ||
| 5564 | |||
| 5354 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ | 5565 | static unsigned int brightness_enable = 2; /* 2 = auto, 0 = no, 1 = yes */ |
| 5355 | 5566 | ||
| 5356 | static struct mutex brightness_mutex; | 5567 | static struct mutex brightness_mutex; |
| 5357 | 5568 | ||
| 5358 | /* | 5569 | /* NVRAM brightness access, |
| 5359 | * ThinkPads can read brightness from two places: EC 0x31, or | 5570 | * call with brightness_mutex held! */ |
| 5360 | * CMOS NVRAM byte 0x5E, bits 0-3. | 5571 | static unsigned int tpacpi_brightness_nvram_get(void) |
| 5361 | * | ||
| 5362 | * EC 0x31 has the following layout | ||
| 5363 | * Bit 7: unknown function | ||
| 5364 | * Bit 6: unknown function | ||
| 5365 | * Bit 5: Z: honour scale changes, NZ: ignore scale changes | ||
| 5366 | * Bit 4: must be set to zero to avoid problems | ||
| 5367 | * Bit 3-0: backlight brightness level | ||
| 5368 | * | ||
| 5369 | * brightness_get_raw returns status data in the EC 0x31 layout | ||
| 5370 | */ | ||
| 5371 | static int brightness_get_raw(int *status) | ||
| 5372 | { | 5572 | { |
| 5373 | u8 lec = 0, lcmos = 0, level = 0; | 5573 | u8 lnvram; |
| 5374 | 5574 | ||
| 5375 | if (brightness_mode & 1) { | 5575 | lnvram = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) |
| 5376 | if (!acpi_ec_read(TP_EC_BACKLIGHT, &lec)) | 5576 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) |
| 5377 | return -EIO; | 5577 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; |
| 5378 | level = lec & TP_EC_BACKLIGHT_LVLMSK; | 5578 | lnvram &= (tp_features.bright_16levels) ? 0x0f : 0x07; |
| 5379 | }; | 5579 | |
| 5380 | if (brightness_mode & 2) { | 5580 | return lnvram; |
| 5381 | lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS) | 5581 | } |
| 5382 | & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | 5582 | |
| 5383 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS; | 5583 | static void tpacpi_brightness_checkpoint_nvram(void) |
| 5384 | lcmos &= (tp_features.bright_16levels)? 0x0f : 0x07; | 5584 | { |
| 5385 | level = lcmos; | 5585 | u8 lec = 0; |
| 5386 | } | 5586 | u8 b_nvram; |
| 5387 | 5587 | ||
| 5388 | if (brightness_mode == 3) { | 5588 | if (brightness_mode != TPACPI_BRGHT_MODE_ECNVRAM) |
| 5389 | *status = lec; /* Prefer EC, CMOS is just a backing store */ | 5589 | return; |
| 5390 | lec &= TP_EC_BACKLIGHT_LVLMSK; | 5590 | |
| 5391 | if (lec == lcmos) | 5591 | vdbg_printk(TPACPI_DBG_BRGHT, |
| 5392 | tp_warned.bright_cmos_ec_unsync = 0; | 5592 | "trying to checkpoint backlight level to NVRAM...\n"); |
| 5393 | else { | 5593 | |
| 5394 | if (!tp_warned.bright_cmos_ec_unsync) { | 5594 | if (mutex_lock_killable(&brightness_mutex) < 0) |
| 5395 | printk(TPACPI_ERR | 5595 | return; |
| 5396 | "CMOS NVRAM (%u) and EC (%u) do not " | 5596 | |
| 5397 | "agree on display brightness level\n", | 5597 | if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) |
| 5398 | (unsigned int) lcmos, | 5598 | goto unlock; |
| 5399 | (unsigned int) lec); | 5599 | lec &= TP_EC_BACKLIGHT_LVLMSK; |
| 5400 | tp_warned.bright_cmos_ec_unsync = 1; | 5600 | b_nvram = nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS); |
| 5401 | } | 5601 | |
| 5602 | if (lec != ((b_nvram & TP_NVRAM_MASK_LEVEL_BRIGHTNESS) | ||
| 5603 | >> TP_NVRAM_POS_LEVEL_BRIGHTNESS)) { | ||
| 5604 | /* NVRAM needs update */ | ||
| 5605 | b_nvram &= ~(TP_NVRAM_MASK_LEVEL_BRIGHTNESS << | ||
| 5606 | TP_NVRAM_POS_LEVEL_BRIGHTNESS); | ||
| 5607 | b_nvram |= lec; | ||
| 5608 | nvram_write_byte(b_nvram, TP_NVRAM_ADDR_BRIGHTNESS); | ||
| 5609 | dbg_printk(TPACPI_DBG_BRGHT, | ||
| 5610 | "updated NVRAM backlight level to %u (0x%02x)\n", | ||
| 5611 | (unsigned int) lec, (unsigned int) b_nvram); | ||
| 5612 | } else | ||
| 5613 | vdbg_printk(TPACPI_DBG_BRGHT, | ||
| 5614 | "NVRAM backlight level already is %u (0x%02x)\n", | ||
| 5615 | (unsigned int) lec, (unsigned int) b_nvram); | ||
| 5616 | |||
| 5617 | unlock: | ||
| 5618 | mutex_unlock(&brightness_mutex); | ||
| 5619 | } | ||
| 5620 | |||
| 5621 | |||
| 5622 | /* call with brightness_mutex held! */ | ||
| 5623 | static int tpacpi_brightness_get_raw(int *status) | ||
| 5624 | { | ||
| 5625 | u8 lec = 0; | ||
| 5626 | |||
| 5627 | switch (brightness_mode) { | ||
| 5628 | case TPACPI_BRGHT_MODE_UCMS_STEP: | ||
| 5629 | *status = tpacpi_brightness_nvram_get(); | ||
| 5630 | return 0; | ||
| 5631 | case TPACPI_BRGHT_MODE_EC: | ||
| 5632 | case TPACPI_BRGHT_MODE_ECNVRAM: | ||
| 5633 | if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) | ||
| 5402 | return -EIO; | 5634 | return -EIO; |
| 5403 | } | 5635 | *status = lec; |
| 5404 | } else { | 5636 | return 0; |
| 5405 | *status = level; | 5637 | default: |
| 5638 | return -ENXIO; | ||
| 5406 | } | 5639 | } |
| 5640 | } | ||
| 5641 | |||
| 5642 | /* call with brightness_mutex held! */ | ||
| 5643 | /* do NOT call with illegal backlight level value */ | ||
| 5644 | static int tpacpi_brightness_set_ec(unsigned int value) | ||
| 5645 | { | ||
| 5646 | u8 lec = 0; | ||
| 5647 | |||
| 5648 | if (unlikely(!acpi_ec_read(TP_EC_BACKLIGHT, &lec))) | ||
| 5649 | return -EIO; | ||
| 5650 | |||
| 5651 | if (unlikely(!acpi_ec_write(TP_EC_BACKLIGHT, | ||
| 5652 | (lec & TP_EC_BACKLIGHT_CMDMSK) | | ||
| 5653 | (value & TP_EC_BACKLIGHT_LVLMSK)))) | ||
| 5654 | return -EIO; | ||
| 5655 | |||
| 5656 | return 0; | ||
| 5657 | } | ||
| 5658 | |||
| 5659 | /* call with brightness_mutex held! */ | ||
| 5660 | static int tpacpi_brightness_set_ucmsstep(unsigned int value) | ||
| 5661 | { | ||
| 5662 | int cmos_cmd, inc; | ||
| 5663 | unsigned int current_value, i; | ||
| 5664 | |||
| 5665 | current_value = tpacpi_brightness_nvram_get(); | ||
| 5666 | |||
| 5667 | if (value == current_value) | ||
| 5668 | return 0; | ||
| 5669 | |||
| 5670 | cmos_cmd = (value > current_value) ? | ||
| 5671 | TP_CMOS_BRIGHTNESS_UP : | ||
| 5672 | TP_CMOS_BRIGHTNESS_DOWN; | ||
| 5673 | inc = (value > current_value) ? 1 : -1; | ||
| 5674 | |||
| 5675 | for (i = current_value; i != value; i += inc) | ||
| 5676 | if (issue_thinkpad_cmos_command(cmos_cmd)) | ||
| 5677 | return -EIO; | ||
| 5407 | 5678 | ||
| 5408 | return 0; | 5679 | return 0; |
| 5409 | } | 5680 | } |
| 5410 | 5681 | ||
| 5411 | /* May return EINTR which can always be mapped to ERESTARTSYS */ | 5682 | /* May return EINTR which can always be mapped to ERESTARTSYS */ |
| 5412 | static int brightness_set(int value) | 5683 | static int brightness_set(unsigned int value) |
| 5413 | { | 5684 | { |
| 5414 | int cmos_cmd, inc, i, res; | 5685 | int res; |
| 5415 | int current_value; | ||
| 5416 | int command_bits; | ||
| 5417 | 5686 | ||
| 5418 | if (value > ((tp_features.bright_16levels)? 15 : 7) || | 5687 | if (value > ((tp_features.bright_16levels)? 15 : 7) || |
| 5419 | value < 0) | 5688 | value < 0) |
| 5420 | return -EINVAL; | 5689 | return -EINVAL; |
| 5421 | 5690 | ||
| 5691 | vdbg_printk(TPACPI_DBG_BRGHT, | ||
| 5692 | "set backlight level to %d\n", value); | ||
| 5693 | |||
| 5422 | res = mutex_lock_killable(&brightness_mutex); | 5694 | res = mutex_lock_killable(&brightness_mutex); |
| 5423 | if (res < 0) | 5695 | if (res < 0) |
| 5424 | return res; | 5696 | return res; |
| 5425 | 5697 | ||
| 5426 | res = brightness_get_raw(¤t_value); | 5698 | switch (brightness_mode) { |
| 5427 | if (res < 0) | 5699 | case TPACPI_BRGHT_MODE_EC: |
| 5428 | goto errout; | 5700 | case TPACPI_BRGHT_MODE_ECNVRAM: |
| 5429 | 5701 | res = tpacpi_brightness_set_ec(value); | |
| 5430 | command_bits = current_value & TP_EC_BACKLIGHT_CMDMSK; | 5702 | break; |
| 5431 | current_value &= TP_EC_BACKLIGHT_LVLMSK; | 5703 | case TPACPI_BRGHT_MODE_UCMS_STEP: |
| 5432 | 5704 | res = tpacpi_brightness_set_ucmsstep(value); | |
| 5433 | cmos_cmd = value > current_value ? | 5705 | break; |
| 5434 | TP_CMOS_BRIGHTNESS_UP : | 5706 | default: |
| 5435 | TP_CMOS_BRIGHTNESS_DOWN; | 5707 | res = -ENXIO; |
| 5436 | inc = (value > current_value)? 1 : -1; | ||
| 5437 | |||
| 5438 | res = 0; | ||
| 5439 | for (i = current_value; i != value; i += inc) { | ||
| 5440 | if ((brightness_mode & 2) && | ||
| 5441 | issue_thinkpad_cmos_command(cmos_cmd)) { | ||
| 5442 | res = -EIO; | ||
| 5443 | goto errout; | ||
| 5444 | } | ||
| 5445 | if ((brightness_mode & 1) && | ||
| 5446 | !acpi_ec_write(TP_EC_BACKLIGHT, | ||
| 5447 | (i + inc) | command_bits)) { | ||
| 5448 | res = -EIO; | ||
| 5449 | goto errout;; | ||
| 5450 | } | ||
| 5451 | } | 5708 | } |
| 5452 | 5709 | ||
| 5453 | errout: | ||
| 5454 | mutex_unlock(&brightness_mutex); | 5710 | mutex_unlock(&brightness_mutex); |
| 5455 | return res; | 5711 | return res; |
| 5456 | } | 5712 | } |
| @@ -5459,21 +5715,34 @@ errout: | |||
| 5459 | 5715 | ||
| 5460 | static int brightness_update_status(struct backlight_device *bd) | 5716 | static int brightness_update_status(struct backlight_device *bd) |
| 5461 | { | 5717 | { |
| 5462 | /* it is the backlight class's job (caller) to handle | 5718 | unsigned int level = |
| 5463 | * EINTR and other errors properly */ | ||
| 5464 | return brightness_set( | ||
| 5465 | (bd->props.fb_blank == FB_BLANK_UNBLANK && | 5719 | (bd->props.fb_blank == FB_BLANK_UNBLANK && |
| 5466 | bd->props.power == FB_BLANK_UNBLANK) ? | 5720 | bd->props.power == FB_BLANK_UNBLANK) ? |
| 5467 | bd->props.brightness : 0); | 5721 | bd->props.brightness : 0; |
| 5722 | |||
| 5723 | dbg_printk(TPACPI_DBG_BRGHT, | ||
| 5724 | "backlight: attempt to set level to %d\n", | ||
| 5725 | level); | ||
| 5726 | |||
| 5727 | /* it is the backlight class's job (caller) to handle | ||
| 5728 | * EINTR and other errors properly */ | ||
| 5729 | return brightness_set(level); | ||
| 5468 | } | 5730 | } |
| 5469 | 5731 | ||
| 5470 | static int brightness_get(struct backlight_device *bd) | 5732 | static int brightness_get(struct backlight_device *bd) |
| 5471 | { | 5733 | { |
| 5472 | int status, res; | 5734 | int status, res; |
| 5473 | 5735 | ||
| 5474 | res = brightness_get_raw(&status); | 5736 | res = mutex_lock_killable(&brightness_mutex); |
| 5475 | if (res < 0) | 5737 | if (res < 0) |
| 5476 | return 0; /* FIXME: teach backlight about error handling */ | 5738 | return 0; |
| 5739 | |||
| 5740 | res = tpacpi_brightness_get_raw(&status); | ||
| 5741 | |||
| 5742 | mutex_unlock(&brightness_mutex); | ||
| 5743 | |||
| 5744 | if (res < 0) | ||
| 5745 | return 0; | ||
| 5477 | 5746 | ||
| 5478 | return status & TP_EC_BACKLIGHT_LVLMSK; | 5747 | return status & TP_EC_BACKLIGHT_LVLMSK; |
| 5479 | } | 5748 | } |
| @@ -5523,7 +5792,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
| 5523 | } | 5792 | } |
| 5524 | 5793 | ||
| 5525 | if (!brightness_enable) { | 5794 | if (!brightness_enable) { |
| 5526 | dbg_printk(TPACPI_DBG_INIT, | 5795 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, |
| 5527 | "brightness support disabled by " | 5796 | "brightness support disabled by " |
| 5528 | "module parameter\n"); | 5797 | "module parameter\n"); |
| 5529 | return 1; | 5798 | return 1; |
| @@ -5538,20 +5807,38 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
| 5538 | if (b == 16) | 5807 | if (b == 16) |
| 5539 | tp_features.bright_16levels = 1; | 5808 | tp_features.bright_16levels = 1; |
| 5540 | 5809 | ||
| 5541 | if (!brightness_mode) { | 5810 | /* |
| 5542 | if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) | 5811 | * Check for module parameter bogosity, note that we |
| 5543 | brightness_mode = 2; | 5812 | * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be |
| 5544 | else | 5813 | * able to detect "unspecified" |
| 5545 | brightness_mode = 3; | 5814 | */ |
| 5815 | if (brightness_mode > TPACPI_BRGHT_MODE_MAX) | ||
| 5816 | return -EINVAL; | ||
| 5546 | 5817 | ||
| 5547 | dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n", | 5818 | /* TPACPI_BRGHT_MODE_AUTO not implemented yet, just use default */ |
| 5548 | brightness_mode); | 5819 | if (brightness_mode == TPACPI_BRGHT_MODE_AUTO || |
| 5549 | } | 5820 | brightness_mode == TPACPI_BRGHT_MODE_MAX) { |
| 5821 | if (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) { | ||
| 5822 | /* | ||
| 5823 | * IBM models that define HBRV probably have | ||
| 5824 | * EC-based backlight level control | ||
| 5825 | */ | ||
| 5826 | if (acpi_evalf(ec_handle, NULL, "HBRV", "qd")) | ||
| 5827 | /* T40-T43, R50-R52, R50e, R51e, X31-X41 */ | ||
| 5828 | brightness_mode = TPACPI_BRGHT_MODE_ECNVRAM; | ||
| 5829 | else | ||
| 5830 | /* all other IBM ThinkPads */ | ||
| 5831 | brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP; | ||
| 5832 | } else | ||
| 5833 | /* All Lenovo ThinkPads */ | ||
| 5834 | brightness_mode = TPACPI_BRGHT_MODE_UCMS_STEP; | ||
| 5550 | 5835 | ||
| 5551 | if (brightness_mode > 3) | 5836 | dbg_printk(TPACPI_DBG_BRGHT, |
| 5552 | return -EINVAL; | 5837 | "selected brightness_mode=%d\n", |
| 5838 | brightness_mode); | ||
| 5839 | } | ||
| 5553 | 5840 | ||
| 5554 | if (brightness_get_raw(&b) < 0) | 5841 | if (tpacpi_brightness_get_raw(&b) < 0) |
| 5555 | return 1; | 5842 | return 1; |
| 5556 | 5843 | ||
| 5557 | if (tp_features.bright_16levels) | 5844 | if (tp_features.bright_16levels) |
| @@ -5565,7 +5852,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
| 5565 | printk(TPACPI_ERR "Could not register backlight device\n"); | 5852 | printk(TPACPI_ERR "Could not register backlight device\n"); |
| 5566 | return PTR_ERR(ibm_backlight_device); | 5853 | return PTR_ERR(ibm_backlight_device); |
| 5567 | } | 5854 | } |
| 5568 | vdbg_printk(TPACPI_DBG_INIT, "brightness is supported\n"); | 5855 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, |
| 5856 | "brightness is supported\n"); | ||
| 5569 | 5857 | ||
| 5570 | ibm_backlight_device->props.max_brightness = | 5858 | ibm_backlight_device->props.max_brightness = |
| 5571 | (tp_features.bright_16levels)? 15 : 7; | 5859 | (tp_features.bright_16levels)? 15 : 7; |
| @@ -5575,13 +5863,25 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
| 5575 | return 0; | 5863 | return 0; |
| 5576 | } | 5864 | } |
| 5577 | 5865 | ||
| 5866 | static void brightness_suspend(pm_message_t state) | ||
| 5867 | { | ||
| 5868 | tpacpi_brightness_checkpoint_nvram(); | ||
| 5869 | } | ||
| 5870 | |||
| 5871 | static void brightness_shutdown(void) | ||
| 5872 | { | ||
| 5873 | tpacpi_brightness_checkpoint_nvram(); | ||
| 5874 | } | ||
| 5875 | |||
| 5578 | static void brightness_exit(void) | 5876 | static void brightness_exit(void) |
| 5579 | { | 5877 | { |
| 5580 | if (ibm_backlight_device) { | 5878 | if (ibm_backlight_device) { |
| 5581 | vdbg_printk(TPACPI_DBG_EXIT, | 5879 | vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_BRGHT, |
| 5582 | "calling backlight_device_unregister()\n"); | 5880 | "calling backlight_device_unregister()\n"); |
| 5583 | backlight_device_unregister(ibm_backlight_device); | 5881 | backlight_device_unregister(ibm_backlight_device); |
| 5584 | } | 5882 | } |
| 5883 | |||
| 5884 | tpacpi_brightness_checkpoint_nvram(); | ||
| 5585 | } | 5885 | } |
| 5586 | 5886 | ||
| 5587 | static int brightness_read(char *p) | 5887 | static int brightness_read(char *p) |
| @@ -5628,6 +5928,9 @@ static int brightness_write(char *buf) | |||
| 5628 | return -EINVAL; | 5928 | return -EINVAL; |
| 5629 | } | 5929 | } |
| 5630 | 5930 | ||
| 5931 | tpacpi_disclose_usertask("procfs brightness", | ||
| 5932 | "set level to %d\n", level); | ||
| 5933 | |||
| 5631 | /* | 5934 | /* |
| 5632 | * Now we know what the final level should be, so we try to set it. | 5935 | * Now we know what the final level should be, so we try to set it. |
| 5633 | * Doing it this way makes the syscall restartable in case of EINTR | 5936 | * Doing it this way makes the syscall restartable in case of EINTR |
| @@ -5641,6 +5944,8 @@ static struct ibm_struct brightness_driver_data = { | |||
| 5641 | .read = brightness_read, | 5944 | .read = brightness_read, |
| 5642 | .write = brightness_write, | 5945 | .write = brightness_write, |
| 5643 | .exit = brightness_exit, | 5946 | .exit = brightness_exit, |
| 5947 | .suspend = brightness_suspend, | ||
| 5948 | .shutdown = brightness_shutdown, | ||
| 5644 | }; | 5949 | }; |
| 5645 | 5950 | ||
| 5646 | /************************************************************************* | 5951 | /************************************************************************* |
| @@ -6086,6 +6391,9 @@ static int fan_set_level(int level) | |||
| 6086 | default: | 6391 | default: |
| 6087 | return -ENXIO; | 6392 | return -ENXIO; |
| 6088 | } | 6393 | } |
| 6394 | |||
| 6395 | vdbg_printk(TPACPI_DBG_FAN, | ||
| 6396 | "fan control: set fan control register to 0x%02x\n", level); | ||
| 6089 | return 0; | 6397 | return 0; |
| 6090 | } | 6398 | } |
| 6091 | 6399 | ||
| @@ -6163,6 +6471,11 @@ static int fan_set_enable(void) | |||
| 6163 | } | 6471 | } |
| 6164 | 6472 | ||
| 6165 | mutex_unlock(&fan_mutex); | 6473 | mutex_unlock(&fan_mutex); |
| 6474 | |||
| 6475 | if (!rc) | ||
| 6476 | vdbg_printk(TPACPI_DBG_FAN, | ||
| 6477 | "fan control: set fan control register to 0x%02x\n", | ||
| 6478 | s); | ||
| 6166 | return rc; | 6479 | return rc; |
| 6167 | } | 6480 | } |
| 6168 | 6481 | ||
| @@ -6199,6 +6512,9 @@ static int fan_set_disable(void) | |||
| 6199 | rc = -ENXIO; | 6512 | rc = -ENXIO; |
| 6200 | } | 6513 | } |
| 6201 | 6514 | ||
| 6515 | if (!rc) | ||
| 6516 | vdbg_printk(TPACPI_DBG_FAN, | ||
| 6517 | "fan control: set fan control register to 0\n"); | ||
| 6202 | 6518 | ||
| 6203 | mutex_unlock(&fan_mutex); | 6519 | mutex_unlock(&fan_mutex); |
| 6204 | return rc; | 6520 | return rc; |
| @@ -6327,6 +6643,9 @@ static ssize_t fan_pwm1_enable_store(struct device *dev, | |||
| 6327 | if (parse_strtoul(buf, 2, &t)) | 6643 | if (parse_strtoul(buf, 2, &t)) |
| 6328 | return -EINVAL; | 6644 | return -EINVAL; |
| 6329 | 6645 | ||
| 6646 | tpacpi_disclose_usertask("hwmon pwm1_enable", | ||
| 6647 | "set fan mode to %lu\n", t); | ||
| 6648 | |||
| 6330 | switch (t) { | 6649 | switch (t) { |
| 6331 | case 0: | 6650 | case 0: |
| 6332 | level = TP_EC_FAN_FULLSPEED; | 6651 | level = TP_EC_FAN_FULLSPEED; |
| @@ -6392,6 +6711,9 @@ static ssize_t fan_pwm1_store(struct device *dev, | |||
| 6392 | if (parse_strtoul(buf, 255, &s)) | 6711 | if (parse_strtoul(buf, 255, &s)) |
| 6393 | return -EINVAL; | 6712 | return -EINVAL; |
| 6394 | 6713 | ||
| 6714 | tpacpi_disclose_usertask("hwmon pwm1", | ||
| 6715 | "set fan speed to %lu\n", s); | ||
| 6716 | |||
| 6395 | /* scale down from 0-255 to 0-7 */ | 6717 | /* scale down from 0-255 to 0-7 */ |
| 6396 | newlevel = (s >> 5) & 0x07; | 6718 | newlevel = (s >> 5) & 0x07; |
| 6397 | 6719 | ||
| @@ -6458,6 +6780,8 @@ static ssize_t fan_fan_watchdog_store(struct device_driver *drv, | |||
| 6458 | fan_watchdog_maxinterval = t; | 6780 | fan_watchdog_maxinterval = t; |
| 6459 | fan_watchdog_reset(); | 6781 | fan_watchdog_reset(); |
| 6460 | 6782 | ||
| 6783 | tpacpi_disclose_usertask("fan_watchdog", "set to %lu\n", t); | ||
| 6784 | |||
| 6461 | return count; | 6785 | return count; |
| 6462 | } | 6786 | } |
| 6463 | 6787 | ||
| @@ -6479,7 +6803,8 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 6479 | { | 6803 | { |
| 6480 | int rc; | 6804 | int rc; |
| 6481 | 6805 | ||
| 6482 | vdbg_printk(TPACPI_DBG_INIT, "initializing fan subdriver\n"); | 6806 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, |
| 6807 | "initializing fan subdriver\n"); | ||
| 6483 | 6808 | ||
| 6484 | mutex_init(&fan_mutex); | 6809 | mutex_init(&fan_mutex); |
| 6485 | fan_status_access_mode = TPACPI_FAN_NONE; | 6810 | fan_status_access_mode = TPACPI_FAN_NONE; |
| @@ -6538,7 +6863,8 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 6538 | } | 6863 | } |
| 6539 | } | 6864 | } |
| 6540 | 6865 | ||
| 6541 | vdbg_printk(TPACPI_DBG_INIT, "fan is %s, modes %d, %d\n", | 6866 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, |
| 6867 | "fan is %s, modes %d, %d\n", | ||
| 6542 | str_supported(fan_status_access_mode != TPACPI_FAN_NONE || | 6868 | str_supported(fan_status_access_mode != TPACPI_FAN_NONE || |
| 6543 | fan_control_access_mode != TPACPI_FAN_WR_NONE), | 6869 | fan_control_access_mode != TPACPI_FAN_WR_NONE), |
| 6544 | fan_status_access_mode, fan_control_access_mode); | 6870 | fan_status_access_mode, fan_control_access_mode); |
| @@ -6547,7 +6873,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 6547 | if (!fan_control_allowed) { | 6873 | if (!fan_control_allowed) { |
| 6548 | fan_control_access_mode = TPACPI_FAN_WR_NONE; | 6874 | fan_control_access_mode = TPACPI_FAN_WR_NONE; |
| 6549 | fan_control_commands = 0; | 6875 | fan_control_commands = 0; |
| 6550 | dbg_printk(TPACPI_DBG_INIT, | 6876 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_FAN, |
| 6551 | "fan control features disabled by parameter\n"); | 6877 | "fan control features disabled by parameter\n"); |
| 6552 | } | 6878 | } |
| 6553 | 6879 | ||
| @@ -6576,7 +6902,7 @@ static int __init fan_init(struct ibm_init_struct *iibm) | |||
| 6576 | 6902 | ||
| 6577 | static void fan_exit(void) | 6903 | static void fan_exit(void) |
| 6578 | { | 6904 | { |
| 6579 | vdbg_printk(TPACPI_DBG_EXIT, | 6905 | vdbg_printk(TPACPI_DBG_EXIT | TPACPI_DBG_FAN, |
| 6580 | "cancelling any pending fan watchdog tasks\n"); | 6906 | "cancelling any pending fan watchdog tasks\n"); |
| 6581 | 6907 | ||
| 6582 | /* FIXME: can we really do this unconditionally? */ | 6908 | /* FIXME: can we really do this unconditionally? */ |
| @@ -6757,6 +7083,9 @@ static int fan_write_cmd_level(const char *cmd, int *rc) | |||
| 6757 | if (*rc == -ENXIO) | 7083 | if (*rc == -ENXIO) |
| 6758 | printk(TPACPI_ERR "level command accepted for unsupported " | 7084 | printk(TPACPI_ERR "level command accepted for unsupported " |
| 6759 | "access mode %d", fan_control_access_mode); | 7085 | "access mode %d", fan_control_access_mode); |
| 7086 | else if (!*rc) | ||
| 7087 | tpacpi_disclose_usertask("procfs fan", | ||
| 7088 | "set level to %d\n", level); | ||
| 6760 | 7089 | ||
| 6761 | return 1; | 7090 | return 1; |
| 6762 | } | 7091 | } |
| @@ -6770,6 +7099,8 @@ static int fan_write_cmd_enable(const char *cmd, int *rc) | |||
| 6770 | if (*rc == -ENXIO) | 7099 | if (*rc == -ENXIO) |
| 6771 | printk(TPACPI_ERR "enable command accepted for unsupported " | 7100 | printk(TPACPI_ERR "enable command accepted for unsupported " |
| 6772 | "access mode %d", fan_control_access_mode); | 7101 | "access mode %d", fan_control_access_mode); |
| 7102 | else if (!*rc) | ||
| 7103 | tpacpi_disclose_usertask("procfs fan", "enable\n"); | ||
| 6773 | 7104 | ||
| 6774 | return 1; | 7105 | return 1; |
| 6775 | } | 7106 | } |
| @@ -6783,6 +7114,8 @@ static int fan_write_cmd_disable(const char *cmd, int *rc) | |||
| 6783 | if (*rc == -ENXIO) | 7114 | if (*rc == -ENXIO) |
| 6784 | printk(TPACPI_ERR "disable command accepted for unsupported " | 7115 | printk(TPACPI_ERR "disable command accepted for unsupported " |
| 6785 | "access mode %d", fan_control_access_mode); | 7116 | "access mode %d", fan_control_access_mode); |
| 7117 | else if (!*rc) | ||
| 7118 | tpacpi_disclose_usertask("procfs fan", "disable\n"); | ||
| 6786 | 7119 | ||
| 6787 | return 1; | 7120 | return 1; |
| 6788 | } | 7121 | } |
| @@ -6801,6 +7134,9 @@ static int fan_write_cmd_speed(const char *cmd, int *rc) | |||
| 6801 | if (*rc == -ENXIO) | 7134 | if (*rc == -ENXIO) |
| 6802 | printk(TPACPI_ERR "speed command accepted for unsupported " | 7135 | printk(TPACPI_ERR "speed command accepted for unsupported " |
| 6803 | "access mode %d", fan_control_access_mode); | 7136 | "access mode %d", fan_control_access_mode); |
| 7137 | else if (!*rc) | ||
| 7138 | tpacpi_disclose_usertask("procfs fan", | ||
| 7139 | "set speed to %d\n", speed); | ||
| 6804 | 7140 | ||
| 6805 | return 1; | 7141 | return 1; |
| 6806 | } | 7142 | } |
| @@ -6814,8 +7150,12 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc) | |||
| 6814 | 7150 | ||
| 6815 | if (interval < 0 || interval > 120) | 7151 | if (interval < 0 || interval > 120) |
| 6816 | *rc = -EINVAL; | 7152 | *rc = -EINVAL; |
| 6817 | else | 7153 | else { |
| 6818 | fan_watchdog_maxinterval = interval; | 7154 | fan_watchdog_maxinterval = interval; |
| 7155 | tpacpi_disclose_usertask("procfs fan", | ||
| 7156 | "set watchdog timer to %d\n", | ||
| 7157 | interval); | ||
| 7158 | } | ||
| 6819 | 7159 | ||
| 6820 | return 1; | 7160 | return 1; |
| 6821 | } | 7161 | } |
| @@ -7244,10 +7584,10 @@ module_param_named(fan_control, fan_control_allowed, bool, 0); | |||
| 7244 | MODULE_PARM_DESC(fan_control, | 7584 | MODULE_PARM_DESC(fan_control, |
| 7245 | "Enables setting fan parameters features when true"); | 7585 | "Enables setting fan parameters features when true"); |
| 7246 | 7586 | ||
| 7247 | module_param_named(brightness_mode, brightness_mode, int, 0); | 7587 | module_param_named(brightness_mode, brightness_mode, uint, 0); |
| 7248 | MODULE_PARM_DESC(brightness_mode, | 7588 | MODULE_PARM_DESC(brightness_mode, |
| 7249 | "Selects brightness control strategy: " | 7589 | "Selects brightness control strategy: " |
| 7250 | "0=auto, 1=EC, 2=CMOS, 3=both"); | 7590 | "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); |
| 7251 | 7591 | ||
| 7252 | module_param(brightness_enable, uint, 0); | 7592 | module_param(brightness_enable, uint, 0); |
| 7253 | MODULE_PARM_DESC(brightness_enable, | 7593 | MODULE_PARM_DESC(brightness_enable, |
| @@ -7517,9 +7857,6 @@ static int __init thinkpad_acpi_module_init(void) | |||
| 7517 | return 0; | 7857 | return 0; |
| 7518 | } | 7858 | } |
| 7519 | 7859 | ||
| 7520 | /* Please remove this in year 2009 */ | ||
| 7521 | MODULE_ALIAS("ibm_acpi"); | ||
| 7522 | |||
| 7523 | MODULE_ALIAS(TPACPI_DRVR_SHORTNAME); | 7860 | MODULE_ALIAS(TPACPI_DRVR_SHORTNAME); |
| 7524 | 7861 | ||
| 7525 | /* | 7862 | /* |
