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 | /* |