Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
L
linux-davinci
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Redmine
Redmine
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Metrics
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
linux
linux-davinci
Commits
336d63b8
Commit
336d63b8
authored
Apr 05, 2009
by
Len Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'thinkpad-acpi' into release
parents
07290bed
0e501834
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
657 additions
and
246 deletions
+657
-246
Documentation/laptops/thinkpad-acpi.txt
Documentation/laptops/thinkpad-acpi.txt
+97
-47
drivers/platform/x86/Kconfig
drivers/platform/x86/Kconfig
+24
-0
drivers/platform/x86/thinkpad_acpi.c
drivers/platform/x86/thinkpad_acpi.c
+536
-199
No files found.
Documentation/laptops/thinkpad-acpi.txt
View file @
336d63b8
...
@@ -20,7 +20,8 @@ moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
...
@@ -20,7 +20,8 @@ moved to the drivers/misc tree and renamed to thinkpad-acpi for kernel
kernel 2.6.29 and release 0.22.
kernel 2.6.29 and release 0.22.
The driver is named "thinkpad-acpi". In some places, like module
The driver is named "thinkpad-acpi". In some places, like module
names, "thinkpad_acpi" is used because of userspace issues.
names and log messages, "thinkpad_acpi" is used because of userspace
issues.
"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too
"tpacpi" is used as a shorthand where "thinkpad-acpi" would be too
long due to length limitations on some Linux kernel versions.
long due to length limitations on some Linux kernel versions.
...
@@ -37,7 +38,7 @@ detailed description):
...
@@ -37,7 +38,7 @@ detailed description):
- ThinkLight on and off
- ThinkLight on and off
- limited docking and undocking
- limited docking and undocking
- UltraBay eject
- UltraBay eject
- CMOS control
- CMOS
/UCMS
control
- LED control
- LED control
- ACPI sounds
- ACPI sounds
- temperature sensors
- temperature sensors
...
@@ -46,6 +47,7 @@ detailed description):
...
@@ -46,6 +47,7 @@ detailed description):
- Volume control
- Volume control
- Fan control and monitoring: fan speed, fan enable/disable
- Fan control and monitoring: fan speed, fan enable/disable
- WAN enable and disable
- WAN enable and disable
- UWB enable and disable
A compatibility table by model and feature is maintained on the web
A compatibility table by model and feature is maintained on the web
site, http://ibm-acpi.sf.net/. I appreciate any success or failure
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,7 +55,7 @@ reports, especially if they add to or correct the compatibility table.
Please include the following information in your report:
Please include the following information in your report:
- ThinkPad model name
- ThinkPad model name
- a copy of your
DSDT, from /proc/acpi/dsdt
- a copy of your
ACPI tables, using the "acpidump" utility
- a copy of the output of dmidecode, with serial numbers
- a copy of the output of dmidecode, with serial numbers
and UUIDs masked off
and UUIDs masked off
- which driver features work and which don't
- which driver features work and which don't
...
@@ -66,17 +68,18 @@ Installation
...
@@ -66,17 +68,18 @@ Installation
------------
------------
If you are compiling this driver as included in the Linux kernel
If you are compiling this driver as included in the Linux kernel
sources, simply enable the CONFIG_THINKPAD_ACPI option, and optionally
sources, look for the CONFIG_THINKPAD_ACPI Kconfig option.
enable the CONFIG_THINKPAD_ACPI_BAY option if you want the
It is located on the menu path: "Device Drivers" -> "X86 Platform
thinkpad-specific bay functionality.
Specific Device Drivers" -> "ThinkPad ACPI Laptop Extras".
Features
Features
--------
--------
The driver exports two different interfaces to userspace, which can be
The driver exports two different interfaces to userspace, which can be
used to access the features it provides. One is a legacy procfs-based
used to access the features it provides. One is a legacy procfs-based
interface, which will be removed at some time in the
distant future.
interface, which will be removed at some time in the
future. The other
The other
is a new sysfs-based interface which is not complete yet.
is a new sysfs-based interface which is not complete yet.
The procfs interface creates the /proc/acpi/ibm directory. There is a
The procfs interface creates the /proc/acpi/ibm directory. There is a
file under that directory for each feature it supports. The procfs
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,15 +114,17 @@ The version of thinkpad-acpi's sysfs interface is exported by the driver
as a driver attribute (see below).
as a driver attribute (see below).
Sysfs driver attributes are on the driver's sysfs attribute space,
Sysfs driver attributes are on the driver's sysfs attribute space,
for 2.6.23 this is /sys/bus/platform/drivers/thinkpad_acpi/ and
for 2.6.23
+
this is /sys/bus/platform/drivers/thinkpad_acpi/ and
/sys/bus/platform/drivers/thinkpad_hwmon/
/sys/bus/platform/drivers/thinkpad_hwmon/
Sysfs device attributes are on the thinkpad_acpi device sysfs attribute
Sysfs device attributes are on the thinkpad_acpi device sysfs attribute
space, for 2.6.23 this is /sys/devices/platform/thinkpad_acpi/.
space, for 2.6.23
+
this is /sys/devices/platform/thinkpad_acpi/.
Sysfs device attributes for the sensors and fan are on the
Sysfs device attributes for the sensors and fan are on the
thinkpad_hwmon device's sysfs attribute space, but you should locate it
thinkpad_hwmon device's sysfs attribute space, but you should locate it
looking for a hwmon device with the name attribute of "thinkpad".
looking for a hwmon device with the name attribute of "thinkpad", or
better yet, through libsensors.
Driver version
Driver version
--------------
--------------
...
@@ -129,6 +134,7 @@ sysfs driver attribute: version
...
@@ -129,6 +134,7 @@ sysfs driver attribute: version
The driver name and version. No commands can be written to this file.
The driver name and version. No commands can be written to this file.
Sysfs interface version
Sysfs interface version
-----------------------
-----------------------
...
@@ -160,6 +166,7 @@ expect that an attribute might not be there, and deal with it properly
...
@@ -160,6 +166,7 @@ expect that an attribute might not be there, and deal with it properly
(an attribute not being there *is* a valid way to make it clear that a
(an attribute not being there *is* a valid way to make it clear that a
feature is not available in sysfs).
feature is not available in sysfs).
Hot keys
Hot keys
--------
--------
...
@@ -172,17 +179,14 @@ system. Enabling the hotkey functionality of thinkpad-acpi signals the
...
@@ -172,17 +179,14 @@ system. Enabling the hotkey functionality of thinkpad-acpi signals the
firmware that such a driver is present, and modifies how the ThinkPad
firmware that such a driver is present, and modifies how the ThinkPad
firmware will behave in many situations.
firmware will behave in many situations.
The driver enables the hot key feature automatically when loaded. The
The driver enables the HKEY ("hot key") event reporting automatically
feature can later be disabled and enabled back at runtime. The driver
when loaded, and disables it when it is removed.
will also restore the hot key feature to its previous state and mask
when it is unloaded.
When the hotkey feature is enabled and the hot key mask is set (see
The driver will report HKEY events in the following format:
below), the driver will report HKEY events in the following format:
ibm/hotkey HKEY 00000080 0000xxxx
ibm/hotkey HKEY 00000080 0000xxxx
Some of these events refer to hot key presses, but not all.
Some of these events refer to hot key presses, but not all
of them
.
The driver will generate events over the input layer for hot keys and
The driver will generate events over the input layer for hot keys and
radio switches, and over the ACPI netlink layer for other events. The
radio switches, and over the ACPI netlink layer for other events. The
...
@@ -214,13 +218,17 @@ procfs notes:
...
@@ -214,13 +218,17 @@ procfs notes:
The following commands can be written to the /proc/acpi/ibm/hotkey file:
The following commands can be written to the /proc/acpi/ibm/hotkey file:
echo enable > /proc/acpi/ibm/hotkey -- enable the hot keys feature
echo disable > /proc/acpi/ibm/hotkey -- disable the hot keys feature
echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
... any other 8-hex-digit mask ...
... any other 8-hex-digit mask ...
echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
The following commands have been deprecated and will cause the kernel
to log a warning:
echo enable > /proc/acpi/ibm/hotkey -- does nothing
echo disable > /proc/acpi/ibm/hotkey -- returns an error
The procfs interface does not support NVRAM polling control. So as to
The procfs interface does not support NVRAM polling control. So as to
maintain maximum bug-to-bug compatibility, it does not report any masks,
maintain maximum bug-to-bug compatibility, it does not report any masks,
nor does it allow one to manipulate the hot key mask when the firmware
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,12 +237,9 @@ does not support masks at all, even if NVRAM polling is in use.
sysfs notes:
sysfs notes:
hotkey_bios_enabled:
hotkey_bios_enabled:
Returns the status of the hot keys feature when
DEPRECATED, WILL BE REMOVED SOON.
thinkpad-acpi was loaded. Upon module unload, the hot
key feature status will be restored to this value.
0: hot keys were disabled
Returns 0.
1: hot keys were enabled (unusual)
hotkey_bios_mask:
hotkey_bios_mask:
Returns the hot keys mask when thinkpad-acpi was loaded.
Returns the hot keys mask when thinkpad-acpi was loaded.
...
@@ -242,13 +247,10 @@ sysfs notes:
...
@@ -242,13 +247,10 @@ sysfs notes:
to this value.
to this value.
hotkey_enable:
hotkey_enable:
Enables/disables the hot keys feature in the ACPI
DEPRECATED, WILL BE REMOVED SOON.
firmware, and reports current status of the hot keys
feature. Has no effect on the NVRAM hot key polling
functionality.
0:
disables the hot keys feature / feature disabled
0:
returns -EPERM
1:
enables the hot keys feature / feature enabled
1:
does nothing
hotkey_mask:
hotkey_mask:
bit mask to enable driver-handling (and depending on
bit mask to enable driver-handling (and depending on
...
@@ -618,6 +620,7 @@ For Lenovo models *with* ACPI backlight control:
...
@@ -618,6 +620,7 @@ For Lenovo models *with* ACPI backlight control:
and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process
and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process
these keys on userspace somehow (e.g. by calling xbacklight).
these keys on userspace somehow (e.g. by calling xbacklight).
Bluetooth
Bluetooth
---------
---------
...
@@ -628,6 +631,9 @@ sysfs rfkill class: switch "tpacpi_bluetooth_sw"
...
@@ -628,6 +631,9 @@ sysfs rfkill class: switch "tpacpi_bluetooth_sw"
This feature shows the presence and current state of a ThinkPad
This feature shows the presence and current state of a ThinkPad
Bluetooth device in the internal ThinkPad CDC slot.
Bluetooth device in the internal ThinkPad CDC slot.
If the ThinkPad supports it, the Bluetooth state is stored in NVRAM,
so it is kept across reboots and power-off.
Procfs notes:
Procfs notes:
If Bluetooth is installed, the following commands can be used:
If Bluetooth is installed, the following commands can be used:
...
@@ -652,6 +658,7 @@ Sysfs notes:
...
@@ -652,6 +658,7 @@ Sysfs notes:
rfkill controller switch "tpacpi_bluetooth_sw": refer to
rfkill controller switch "tpacpi_bluetooth_sw": refer to
Documentation/rfkill.txt for details.
Documentation/rfkill.txt for details.
Video output control -- /proc/acpi/ibm/video
Video output control -- /proc/acpi/ibm/video
--------------------------------------------
--------------------------------------------
...
@@ -693,11 +700,8 @@ Fn-F7 from working. This also disables the video output switching
...
@@ -693,11 +700,8 @@ Fn-F7 from working. This also disables the video output switching
features of this driver, as it uses the same ACPI methods as
features of this driver, as it uses the same ACPI methods as
Fn-F7. Video switching on the console should still work.
Fn-F7. Video switching on the console should still work.
UPDATE: There's now a patch for the X.org Radeon driver which
UPDATE: refer to https://bugs.freedesktop.org/show_bug.cgi?id=2000
addresses this issue. Some people are reporting success with the patch
while others are still having problems. For more information:
https://bugs.freedesktop.org/show_bug.cgi?id=2000
ThinkLight control
ThinkLight control
------------------
------------------
...
@@ -720,10 +724,11 @@ The ThinkLight sysfs interface is documented by the LED class
...
@@ -720,10 +724,11 @@ The ThinkLight sysfs interface is documented by the LED class
documentation, in Documentation/leds-class.txt. The ThinkLight LED name
documentation, in Documentation/leds-class.txt. The ThinkLight LED name
is "tpacpi::thinklight".
is "tpacpi::thinklight".
Due to limitations in the sysfs LED class, if the status of the
thinkl
ight
Due to limitations in the sysfs LED class, if the status of the
ThinkL
ight
cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
cannot be read or if it is unknown, thinkpad-acpi will report it as "off".
It is impossible to know if the status returned through sysfs is valid.
It is impossible to know if the status returned through sysfs is valid.
Docking / undocking -- /proc/acpi/ibm/dock
Docking / undocking -- /proc/acpi/ibm/dock
------------------------------------------
------------------------------------------
...
@@ -784,6 +789,7 @@ the only docking stations currently supported are the X-series
...
@@ -784,6 +789,7 @@ the only docking stations currently supported are the X-series
UltraBase docks and "dumb" port replicators like the Mini Dock (the
UltraBase docks and "dumb" port replicators like the Mini Dock (the
latter don't need any ACPI support, actually).
latter don't need any ACPI support, actually).
UltraBay eject -- /proc/acpi/ibm/bay
UltraBay eject -- /proc/acpi/ibm/bay
------------------------------------
------------------------------------
...
@@ -847,8 +853,9 @@ supported. Use "eject2" instead of "eject" for the second bay.
...
@@ -847,8 +853,9 @@ supported. Use "eject2" instead of "eject" for the second bay.
Note: the UltraBay eject support on the 600e/x, A22p and A3x is
Note: the UltraBay eject support on the 600e/x, A22p and A3x is
EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
EXPERIMENTAL and may not work as expected. USE WITH CAUTION!
CMOS control
------------
CMOS/UCMS control
-----------------
procfs: /proc/acpi/ibm/cmos
procfs: /proc/acpi/ibm/cmos
sysfs device attribute: cmos_command
sysfs device attribute: cmos_command
...
@@ -882,6 +889,7 @@ The cmos command interface is prone to firmware split-brain problems, as
...
@@ -882,6 +889,7 @@ The cmos command interface is prone to firmware split-brain problems, as
in newer ThinkPads it is just a compatibility layer. Do not use it, it is
in newer ThinkPads it is just a compatibility layer. Do not use it, it is
exported just as a debug tool.
exported just as a debug tool.
LED control
LED control
-----------
-----------
...
@@ -893,6 +901,17 @@ some older ThinkPad models, it is possible to query the status of the
...
@@ -893,6 +901,17 @@ some older ThinkPad models, it is possible to query the status of the
LED indicators as well. Newer ThinkPads cannot query the real status
LED indicators as well. Newer ThinkPads cannot query the real status
of the LED indicators.
of the LED indicators.
Because misuse of the LEDs could induce an unaware user to perform
dangerous actions (like undocking or ejecting a bay device while the
buses are still active), or mask an important alarm (such as a nearly
empty battery, or a broken battery), access to most LEDs is
restricted.
Unrestricted access to all LEDs requires that thinkpad-acpi be
compiled with the CONFIG_THINKPAD_ACPI_UNSAFE_LEDS option enabled.
Distributions must never enable this option. Individual users that
are aware of the consequences are welcome to enabling it.
procfs notes:
procfs notes:
The available commands are:
The available commands are:
...
@@ -939,6 +958,7 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the
...
@@ -939,6 +958,7 @@ ThinkPad indicator LED should blink in hardware accelerated mode, use the
"timer" trigger, and leave the delay_on and delay_off parameters set to
"timer" trigger, and leave the delay_on and delay_off parameters set to
zero (to request hardware acceleration autodetection).
zero (to request hardware acceleration autodetection).
ACPI sounds -- /proc/acpi/ibm/beep
ACPI sounds -- /proc/acpi/ibm/beep
----------------------------------
----------------------------------
...
@@ -968,6 +988,7 @@ X40:
...
@@ -968,6 +988,7 @@ X40:
16 - one medium-pitched beep repeating constantly, stop with 17
16 - one medium-pitched beep repeating constantly, stop with 17
17 - stop 16
17 - stop 16
Temperature sensors
Temperature sensors
-------------------
-------------------
...
@@ -1115,6 +1136,7 @@ registers contain the current battery capacity, etc. If you experiment
...
@@ -1115,6 +1136,7 @@ registers contain the current battery capacity, etc. If you experiment
with this, do send me your results (including some complete dumps with
with this, do send me your results (including some complete dumps with
a description of the conditions when they were taken.)
a description of the conditions when they were taken.)
LCD brightness control
LCD brightness control
----------------------
----------------------
...
@@ -1124,10 +1146,9 @@ sysfs backlight device "thinkpad_screen"
...
@@ -1124,10 +1146,9 @@ sysfs backlight device "thinkpad_screen"
This feature allows software control of the LCD brightness on ThinkPad
This feature allows software control of the LCD brightness on ThinkPad
models which don't have a hardware brightness slider.
models which don't have a hardware brightness slider.
It has some limitations: the LCD backlight cannot be actually turned on or
It has some limitations: the LCD backlight cannot be actually turned
off by this interface, and in many ThinkPad models, the "dim while on
on or off by this interface, it just controls the backlight brightness
battery" functionality will be enabled by the BIOS when this interface is
level.
used, and cannot be controlled.
On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
On IBM (and some of the earlier Lenovo) ThinkPads, the backlight control
has eight brightness levels, ranging from 0 to 7. Some of the levels
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,10 +1157,15 @@ display backlight brightness control methods have 16 levels, ranging
from 0 to 15.
from 0 to 15.
There are two interfaces to the firmware for direct brightness control,
There are two interfaces to the firmware for direct brightness control,
EC and
CMOS
. To select which one should be used, use the
EC and
UCMS (or CMOS)
. To select which one should be used, use the
brightness_mode module parameter: brightness_mode=1 selects EC mode,
brightness_mode module parameter: brightness_mode=1 selects EC mode,
brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
brightness_mode=2 selects UCMS mode, brightness_mode=3 selects EC
and CMOS. The driver tries to auto-detect which interface to use.
mode with NVRAM backing (so that brightness changes are remembered
across shutdown/reboot).
The driver tries to select which interface to use from a table of
defaults for each ThinkPad model. If it makes a wrong choice, please
report this as a bug, so that we can fix it.
When display backlight brightness controls are available through the
When display backlight brightness controls are available through the
standard ACPI interface, it is best to use it instead of this direct
standard ACPI interface, it is best to use it instead of this direct
...
@@ -1201,6 +1227,7 @@ WARNING:
...
@@ -1201,6 +1227,7 @@ WARNING:
and maybe reduce the life of the backlight lamps by needlessly kicking
and maybe reduce the life of the backlight lamps by needlessly kicking
its level up and down at every change.
its level up and down at every change.
Volume control -- /proc/acpi/ibm/volume
Volume control -- /proc/acpi/ibm/volume
---------------------------------------
---------------------------------------
...
@@ -1217,6 +1244,11 @@ distinct. The unmute the volume after the mute command, use either the
...
@@ -1217,6 +1244,11 @@ distinct. The unmute the volume after the mute command, use either the
up or down command (the level command will not unmute the volume).
up or down command (the level command will not unmute the volume).
The current volume level and mute state is shown in the file.
The current volume level and mute state is shown in the file.
The ALSA mixer interface to this feature is still missing, but patches
to add it exist. That problem should be addressed in the not so
distant future.
Fan control and monitoring: fan speed, fan enable/disable
Fan control and monitoring: fan speed, fan enable/disable
---------------------------------------------------------
---------------------------------------------------------
...
@@ -1383,8 +1415,11 @@ procfs: /proc/acpi/ibm/wan
...
@@ -1383,8 +1415,11 @@ procfs: /proc/acpi/ibm/wan
sysfs device attribute: wwan_enable (deprecated)
sysfs device attribute: wwan_enable (deprecated)
sysfs rfkill class: switch "tpacpi_wwan_sw"
sysfs rfkill class: switch "tpacpi_wwan_sw"
This feature shows the presence and current state of a W-WAN (Sierra
This feature shows the presence and current state of the built-in
Wireless EV-DO) device.
Wireless WAN device.
If the ThinkPad supports it, the WWAN state is stored in NVRAM,
so it is kept across reboots and power-off.
It was tested on a Lenovo ThinkPad X60. It should probably work on other
It was tested on a Lenovo ThinkPad X60. It should probably work on other
ThinkPad models which come with this module installed.
ThinkPad models which come with this module installed.
...
@@ -1413,6 +1448,7 @@ Sysfs notes:
...
@@ -1413,6 +1448,7 @@ Sysfs notes:
rfkill controller switch "tpacpi_wwan_sw": refer to
rfkill controller switch "tpacpi_wwan_sw": refer to
Documentation/rfkill.txt for details.
Documentation/rfkill.txt for details.
EXPERIMENTAL: UWB
EXPERIMENTAL: UWB
-----------------
-----------------
...
@@ -1431,6 +1467,7 @@ Sysfs notes:
...
@@ -1431,6 +1467,7 @@ Sysfs notes:
rfkill controller switch "tpacpi_uwb_sw": refer to
rfkill controller switch "tpacpi_uwb_sw": refer to
Documentation/rfkill.txt for details.
Documentation/rfkill.txt for details.
Multiple Commands, Module Parameters
Multiple Commands, Module Parameters
------------------------------------
------------------------------------
...
@@ -1445,6 +1482,7 @@ for example:
...
@@ -1445,6 +1482,7 @@ for example:
modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
modprobe thinkpad_acpi hotkey=enable,0xffff video=auto_disable
Enabling debugging output
Enabling debugging output
-------------------------
-------------------------
...
@@ -1457,8 +1495,15 @@ will enable all debugging output classes. It takes a bitmask, so
...
@@ -1457,8 +1495,15 @@ will enable all debugging output classes. It takes a bitmask, so
to enable more than one output class, just add their values.
to enable more than one output class, just add their values.
Debug bitmask Description
Debug bitmask Description
0x8000 Disclose PID of userspace programs
accessing some functions of the driver
0x0001 Initialization and probing
0x0001 Initialization and probing
0x0002 Removal
0x0002 Removal
0x0004 RF Transmitter control (RFKILL)
(bluetooth, WWAN, UWB...)
0x0008 HKEY event interface, hotkeys
0x0010 Fan control
0x0020 Backlight brightness
There is also a kernel build option to enable more debugging
There is also a kernel build option to enable more debugging
information, which may be necessary to debug driver problems.
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,6 +1512,7 @@ The level of debugging information output by the driver can be changed
at runtime through sysfs, using the driver attribute debug_level. The
at runtime through sysfs, using the driver attribute debug_level. The
attribute takes the same bitmask as the debug module parameter above.
attribute takes the same bitmask as the debug module parameter above.
Force loading of module
Force loading of module
-----------------------
-----------------------
...
@@ -1505,3 +1551,7 @@ Sysfs interface changelog:
...
@@ -1505,3 +1551,7 @@ Sysfs interface changelog:
0x020200: Add poll()/select() support to the following attributes:
0x020200: Add poll()/select() support to the following attributes:
hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason
hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason
0x020300: hotkey enable/disable support removed, attributes
hotkey_bios_enabled and hotkey_enable deprecated and
marked for removal.
drivers/platform/x86/Kconfig
View file @
336d63b8
...
@@ -226,6 +226,30 @@ config THINKPAD_ACPI_DEBUG
...
@@ -226,6 +226,30 @@ config THINKPAD_ACPI_DEBUG
If you are not sure, say N here.
If you are not sure, say N here.
config THINKPAD_ACPI_UNSAFE_LEDS
bool "Allow control of important LEDs (unsafe)"
depends on THINKPAD_ACPI
default n
---help---
Overriding LED state on ThinkPads can mask important
firmware alerts (like critical battery condition), or misled
the user into damaging the hardware (undocking or ejecting
the bay while buses are still active), etc.
LED control on the ThinkPad is write-only (with very few
exceptions on very ancient models), which makes it
impossible to know beforehand if important information will
be lost when one changes LED state.
Users that know what they are doing can enable this option
and the driver will allow control of every LED, including
the ones on the dock stations.
Never enable this option on a distribution kernel.
Say N here, unless you are building a kernel for your own
use, and need to control the important firmware LEDs.
config THINKPAD_ACPI_DOCK
config THINKPAD_ACPI_DOCK
bool "Legacy Docking Station Support"
bool "Legacy Docking Station Support"
depends on THINKPAD_ACPI
depends on THINKPAD_ACPI
...
...
drivers/platform/x86/thinkpad_acpi.c
View file @
336d63b8
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
*
*
*
*
* Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
* Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
* Copyright (C) 2006-200
8
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
* Copyright (C) 2006-200
9
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
*
*
* This program is free software; you can redistribute it and/or modify
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* it under the terms of the GNU General Public License as published by
...
@@ -22,7 +22,7 @@
...
@@ -22,7 +22,7 @@
*/
*/
#define TPACPI_VERSION "0.22"
#define TPACPI_VERSION "0.22"
#define TPACPI_SYSFS_VERSION 0x020
2
00
#define TPACPI_SYSFS_VERSION 0x020
3
00
/*
/*
* Changelog:
* Changelog:
...
@@ -54,6 +54,7 @@
...
@@ -54,6 +54,7 @@
#include <linux/string.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/kthread.h>
#include <linux/kthread.h>
#include <linux/freezer.h>
#include <linux/freezer.h>
#include <linux/delay.h>
#include <linux/delay.h>
...
@@ -172,29 +173,26 @@ enum {
...
@@ -172,29 +173,26 @@ enum {
TPACPI_RFK_UWB_SW_ID
,
TPACPI_RFK_UWB_SW_ID
,
};
};
/*
Debugging
*/
/*
printk headers
*/
#define TPACPI_LOG TPACPI_FILE ": "
#define TPACPI_LOG TPACPI_FILE ": "
#define TPACPI_ALERT KERN_ALERT TPACPI_LOG
#define TPACPI_EMERG KERN_EMERG TPACPI_LOG
#define TPACPI_CRIT KERN_CRIT TPACPI_LOG
#define TPACPI_ALERT KERN_ALERT TPACPI_LOG
#define TPACPI_ERR KERN_ERR TPACPI_LOG
#define TPACPI_CRIT KERN_CRIT TPACPI_LOG
#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
#define TPACPI_ERR KERN_ERR TPACPI_LOG
#define TPACPI_INFO KERN_INFO TPACPI_LOG
#define TPACPI_WARN KERN_WARNING TPACPI_LOG
#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
#define TPACPI_NOTICE KERN_NOTICE TPACPI_LOG
#define TPACPI_INFO KERN_INFO TPACPI_LOG
#define TPACPI_DEBUG KERN_DEBUG TPACPI_LOG
/* Debugging printk groups */
#define TPACPI_DBG_ALL 0xffff
#define TPACPI_DBG_ALL 0xffff
#define TPACPI_DBG_DISCLOSETASK 0x8000
#define TPACPI_DBG_INIT 0x0001
#define TPACPI_DBG_INIT 0x0001
#define TPACPI_DBG_EXIT 0x0002
#define TPACPI_DBG_EXIT 0x0002
#define dbg_printk(a_dbg_level, format, arg...) \
#define TPACPI_DBG_RFKILL 0x0004
do { if (dbg_level & a_dbg_level) \
#define TPACPI_DBG_HKEY 0x0008
printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \
#define TPACPI_DBG_FAN 0x0010
} while (0)
#define TPACPI_DBG_BRGHT 0x0020
#ifdef CONFIG_THINKPAD_ACPI_DEBUG
#define vdbg_printk(a_dbg_level, format, arg...) \
dbg_printk(a_dbg_level, format, ## arg)
static
const
char
*
str_supported
(
int
is_supported
);
#else
#define vdbg_printk(a_dbg_level, format, arg...)
#endif
#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
#define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off")
#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
#define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
...
@@ -277,7 +275,6 @@ static struct {
...
@@ -277,7 +275,6 @@ static struct {
static
struct
{
static
struct
{
u16
hotkey_mask_ff
:
1
;
u16
hotkey_mask_ff
:
1
;
u16
bright_cmos_ec_unsync
:
1
;
}
tp_warned
;
}
tp_warned
;
struct
thinkpad_id_data
{
struct
thinkpad_id_data
{
...
@@ -326,6 +323,39 @@ static int tpacpi_uwb_emulstate;
...
@@ -326,6 +323,39 @@ static int tpacpi_uwb_emulstate;
#endif
#endif
/*************************************************************************
* Debugging helpers
*/
#define dbg_printk(a_dbg_level, format, arg...) \
do { if (dbg_level & (a_dbg_level)) \
printk(TPACPI_DEBUG "%s: " format, __func__ , ## arg); \
} while (0)
#ifdef CONFIG_THINKPAD_ACPI_DEBUG
#define vdbg_printk dbg_printk
static
const
char
*
str_supported
(
int
is_supported
);
#else
#define vdbg_printk(a_dbg_level, format, arg...) \
do { } while (0)
#endif
static
void
tpacpi_log_usertask
(
const
char
*
const
what
)
{
printk
(
TPACPI_DEBUG
"%s: access by process with PID %d
\n
"
,
what
,
task_tgid_vnr
(
current
));
}
#define tpacpi_disclose_usertask(what, format, arg...) \
do { \
if (unlikely( \
(dbg_level & TPACPI_DBG_DISCLOSETASK) && \
(tpacpi_lifecycle == TPACPI_LIFE_RUNNING))) { \
printk(TPACPI_DEBUG "%s: PID %d: " format, \
what, task_tgid_vnr(current), ## arg); \
} \
} while (0)
/****************************************************************************
/****************************************************************************
****************************************************************************
****************************************************************************
*
*
...
@@ -989,10 +1019,13 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
...
@@ -989,10 +1019,13 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
/* try to set the initial state as the default for the rfkill
/* try to set the initial state as the default for the rfkill
* type, since we ask the firmware to preserve it across S5 in
* type, since we ask the firmware to preserve it across S5 in
* NVRAM */
* NVRAM */
rfkill_set_default
(
rfktype
,
if
(
rfkill_set_default
(
rfktype
,
(
initial_state
==
RFKILL_STATE_UNBLOCKED
)
?
(
initial_state
==
RFKILL_STATE_UNBLOCKED
)
?
RFKILL_STATE_UNBLOCKED
:
RFKILL_STATE_UNBLOCKED
:
RFKILL_STATE_SOFT_BLOCKED
);
RFKILL_STATE_SOFT_BLOCKED
)
==
-
EPERM
)
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"Default state for %s cannot be changed
\n
"
,
name
);
}
}
*
rfk
=
rfkill_allocate
(
&
tpacpi_pdev
->
dev
,
rfktype
);
*
rfk
=
rfkill_allocate
(
&
tpacpi_pdev
->
dev
,
rfktype
);
...
@@ -1020,6 +1053,21 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
...
@@ -1020,6 +1053,21 @@ static int __init tpacpi_new_rfkill(const unsigned int id,
return
0
;
return
0
;
}
}
static
void
printk_deprecated_attribute
(
const
char
*
const
what
,
const
char
*
const
details
)
{
tpacpi_log_usertask
(
"deprecated sysfs attribute"
);
printk
(
TPACPI_WARN
"WARNING: sysfs attribute %s is deprecated and "
"will be removed. %s
\n
"
,
what
,
details
);
}
static
void
printk_deprecated_rfkill_attribute
(
const
char
*
const
what
)
{
printk_deprecated_attribute
(
what
,
"Please switch to generic rfkill before year 2010"
);
}
/*************************************************************************
/*************************************************************************
* thinkpad-acpi driver attributes
* thinkpad-acpi driver attributes
*/
*/
...
@@ -1382,7 +1430,6 @@ static enum { /* Reasons for waking up */
...
@@ -1382,7 +1430,6 @@ static enum { /* Reasons for waking up */
static
int
hotkey_autosleep_ack
;
static
int
hotkey_autosleep_ack
;
static
int
hotkey_orig_status
;
static
u32
hotkey_orig_mask
;
static
u32
hotkey_orig_mask
;
static
u32
hotkey_all_mask
;
static
u32
hotkey_all_mask
;
static
u32
hotkey_reserved_mask
;
static
u32
hotkey_reserved_mask
;
...
@@ -1529,9 +1576,9 @@ static int hotkey_status_get(int *status)
...
@@ -1529,9 +1576,9 @@ static int hotkey_status_get(int *status)
return
0
;
return
0
;
}
}
static
int
hotkey_status_set
(
int
status
)
static
int
hotkey_status_set
(
bool
enable
)
{
{
if
(
!
acpi_evalf
(
hkey_handle
,
NULL
,
"MHKC"
,
"vd"
,
status
))
if
(
!
acpi_evalf
(
hkey_handle
,
NULL
,
"MHKC"
,
"vd"
,
enable
?
1
:
0
))
return
-
EIO
;
return
-
EIO
;
return
0
;
return
0
;
...
@@ -1847,6 +1894,9 @@ static ssize_t hotkey_enable_show(struct device *dev,
...
@@ -1847,6 +1894,9 @@ static ssize_t hotkey_enable_show(struct device *dev,
{
{
int
res
,
status
;
int
res
,
status
;
printk_deprecated_attribute
(
"hotkey_enable"
,
"Hotkey reporting is always enabled"
);
res
=
hotkey_status_get
(
&
status
);
res
=
hotkey_status_get
(
&
status
);
if
(
res
)
if
(
res
)
return
res
;
return
res
;
...
@@ -1859,14 +1909,17 @@ static ssize_t hotkey_enable_store(struct device *dev,
...
@@ -1859,14 +1909,17 @@ static ssize_t hotkey_enable_store(struct device *dev,
const
char
*
buf
,
size_t
count
)
const
char
*
buf
,
size_t
count
)
{
{
unsigned
long
t
;
unsigned
long
t
;
int
res
;
printk_deprecated_attribute
(
"hotkey_enable"
,
"Hotkeys can be disabled through hotkey_mask"
);
if
(
parse_strtoul
(
buf
,
1
,
&
t
))
if
(
parse_strtoul
(
buf
,
1
,
&
t
))
return
-
EINVAL
;
return
-
EINVAL
;
res
=
hotkey_status_set
(
t
);
if
(
t
==
0
)
return
-
EPERM
;
return
(
res
)
?
res
:
count
;
return
count
;
}
}
static
struct
device_attribute
dev_attr_hotkey_enable
=
static
struct
device_attribute
dev_attr_hotkey_enable
=
...
@@ -1910,6 +1963,8 @@ static ssize_t hotkey_mask_store(struct device *dev,
...
@@ -1910,6 +1963,8 @@ static ssize_t hotkey_mask_store(struct device *dev,
mutex_unlock
(
&
hotkey_mutex
);
mutex_unlock
(
&
hotkey_mutex
);
tpacpi_disclose_usertask
(
"hotkey_mask"
,
"set to 0x%08lx
\n
"
,
t
);
return
(
res
)
?
res
:
count
;
return
(
res
)
?
res
:
count
;
}
}
...
@@ -1922,7 +1977,7 @@ static ssize_t hotkey_bios_enabled_show(struct device *dev,
...
@@ -1922,7 +1977,7 @@ static ssize_t hotkey_bios_enabled_show(struct device *dev,
struct
device_attribute
*
attr
,
struct
device_attribute
*
attr
,
char
*
buf
)
char
*
buf
)
{
{
return
s
nprintf
(
buf
,
PAGE_SIZE
,
"%d
\n
"
,
hotkey_orig_status
);
return
s
printf
(
buf
,
"0
\n
"
);
}
}
static
struct
device_attribute
dev_attr_hotkey_bios_enabled
=
static
struct
device_attribute
dev_attr_hotkey_bios_enabled
=
...
@@ -1996,6 +2051,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
...
@@ -1996,6 +2051,8 @@ static ssize_t hotkey_source_mask_store(struct device *dev,
mutex_unlock
(
&
hotkey_mutex
);
mutex_unlock
(
&
hotkey_mutex
);
tpacpi_disclose_usertask
(
"hotkey_source_mask"
,
"set to 0x%08lx
\n
"
,
t
);
return
count
;
return
count
;
}
}
...
@@ -2028,6 +2085,8 @@ static ssize_t hotkey_poll_freq_store(struct device *dev,
...
@@ -2028,6 +2085,8 @@ static ssize_t hotkey_poll_freq_store(struct device *dev,
hotkey_poll_setup
(
1
);
hotkey_poll_setup
(
1
);
mutex_unlock
(
&
hotkey_mutex
);
mutex_unlock
(
&
hotkey_mutex
);
tpacpi_disclose_usertask
(
"hotkey_poll_freq"
,
"set to %lu
\n
"
,
t
);
return
count
;
return
count
;
}
}
...
@@ -2197,11 +2256,11 @@ static void hotkey_exit(void)
...
@@ -2197,11 +2256,11 @@ static void hotkey_exit(void)
kfree
(
hotkey_keycode_map
);
kfree
(
hotkey_keycode_map
);
if
(
tp_features
.
hotkey
)
{
if
(
tp_features
.
hotkey
)
{
dbg_printk
(
TPACPI_DBG_EXIT
,
dbg_printk
(
TPACPI_DBG_EXIT
|
TPACPI_DBG_HKEY
,
"restoring original hot key mask
\n
"
);
"restoring original hot key mask
\n
"
);
/* no short-circuit boolean operator below! */
/* no short-circuit boolean operator below! */
if
((
hotkey_mask_set
(
hotkey_orig_mask
)
|
if
((
hotkey_mask_set
(
hotkey_orig_mask
)
|
hotkey_status_set
(
hotkey_orig_status
))
!=
0
)
hotkey_status_set
(
false
))
!=
0
)
printk
(
TPACPI_ERR
printk
(
TPACPI_ERR
"failed to restore hot key mask "
"failed to restore hot key mask "
"to BIOS defaults
\n
"
);
"to BIOS defaults
\n
"
);
...
@@ -2327,7 +2386,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2327,7 +2386,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
int
status
;
int
status
;
int
hkeyv
;
int
hkeyv
;
vdbg_printk
(
TPACPI_DBG_INIT
,
"initializing hotkey subdriver
\n
"
);
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"initializing hotkey subdriver
\n
"
);
BUG_ON
(
!
tpacpi_inputdev
);
BUG_ON
(
!
tpacpi_inputdev
);
BUG_ON
(
tpacpi_inputdev
->
open
!=
NULL
||
BUG_ON
(
tpacpi_inputdev
->
open
!=
NULL
||
...
@@ -2344,7 +2404,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2344,7 +2404,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
/* hotkey not supported on 570 */
/* hotkey not supported on 570 */
tp_features
.
hotkey
=
hkey_handle
!=
NULL
;
tp_features
.
hotkey
=
hkey_handle
!=
NULL
;
vdbg_printk
(
TPACPI_DBG_INIT
,
"hotkeys are %s
\n
"
,
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"hotkeys are %s
\n
"
,
str_supported
(
tp_features
.
hotkey
));
str_supported
(
tp_features
.
hotkey
));
if
(
!
tp_features
.
hotkey
)
if
(
!
tp_features
.
hotkey
)
...
@@ -2376,10 +2437,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2376,10 +2437,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
* T4x, X31, and later
* T4x, X31, and later
*/
*/
tp_features
.
hotkey_mask
=
1
;
tp_features
.
hotkey_mask
=
1
;
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"firmware HKEY interface version: 0x%x
\n
"
,
hkeyv
);
}
}
}
}
vdbg_printk
(
TPACPI_DBG_INIT
,
"hotkey masks are %s
\n
"
,
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"hotkey masks are %s
\n
"
,
str_supported
(
tp_features
.
hotkey_mask
));
str_supported
(
tp_features
.
hotkey_mask
));
if
(
tp_features
.
hotkey_mask
)
{
if
(
tp_features
.
hotkey_mask
)
{
...
@@ -2396,10 +2461,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2396,10 +2461,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
/* hotkey_source_mask *must* be zero for
/* hotkey_source_mask *must* be zero for
* the first hotkey_mask_get */
* the first hotkey_mask_get */
res
=
hotkey_status_get
(
&
hotkey_orig_status
);
if
(
res
)
goto
err_exit
;
if
(
tp_features
.
hotkey_mask
)
{
if
(
tp_features
.
hotkey_mask
)
{
res
=
hotkey_mask_get
();
res
=
hotkey_mask_get
();
if
(
res
)
if
(
res
)
...
@@ -2422,7 +2483,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2422,7 +2483,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
hotkey_source_mask
=
TPACPI_HKEY_NVRAM_GOOD_MASK
;
hotkey_source_mask
=
TPACPI_HKEY_NVRAM_GOOD_MASK
;
}
}
vdbg_printk
(
TPACPI_DBG_INIT
,
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"hotkey source mask 0x%08x, polling freq %d
\n
"
,
"hotkey source mask 0x%08x, polling freq %d
\n
"
,
hotkey_source_mask
,
hotkey_poll_freq
);
hotkey_source_mask
,
hotkey_poll_freq
);
#endif
#endif
...
@@ -2476,12 +2537,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2476,12 +2537,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
}
}
if
(
thinkpad_id
.
vendor
==
PCI_VENDOR_ID_LENOVO
)
{
if
(
thinkpad_id
.
vendor
==
PCI_VENDOR_ID_LENOVO
)
{
dbg_printk
(
TPACPI_DBG_INIT
,
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"using Lenovo default hot key map
\n
"
);
"using Lenovo default hot key map
\n
"
);
memcpy
(
hotkey_keycode_map
,
&
lenovo_keycode_map
,
memcpy
(
hotkey_keycode_map
,
&
lenovo_keycode_map
,
TPACPI_HOTKEY_MAP_SIZE
);
TPACPI_HOTKEY_MAP_SIZE
);
}
else
{
}
else
{
dbg_printk
(
TPACPI_DBG_INIT
,
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"using IBM default hot key map
\n
"
);
"using IBM default hot key map
\n
"
);
memcpy
(
hotkey_keycode_map
,
&
ibm_keycode_map
,
memcpy
(
hotkey_keycode_map
,
&
ibm_keycode_map
,
TPACPI_HOTKEY_MAP_SIZE
);
TPACPI_HOTKEY_MAP_SIZE
);
...
@@ -2538,8 +2599,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2538,8 +2599,9 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
(
1
<<
TP_ACPI_HOTKEYSCAN_FNEND
);
|
(
1
<<
TP_ACPI_HOTKEYSCAN_FNEND
);
}
}
dbg_printk
(
TPACPI_DBG_INIT
,
"enabling hot key handling
\n
"
);
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
res
=
hotkey_status_set
(
1
);
"enabling firmware HKEY event interface...
\n
"
);
res
=
hotkey_status_set
(
true
);
if
(
res
)
{
if
(
res
)
{
hotkey_exit
();
hotkey_exit
();
return
res
;
return
res
;
...
@@ -2552,8 +2614,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
...
@@ -2552,8 +2614,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
return
res
;
return
res
;
}
}
dbg_printk
(
TPACPI_DBG_INIT
,
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_HKEY
,
"legacy
hot key
reporting over procfs %s
\n
"
,
"legacy
ibm/hotkey event
reporting over procfs %s
\n
"
,
(
hotkey_report_mode
<
2
)
?
(
hotkey_report_mode
<
2
)
?
"enabled"
:
"disabled"
);
"enabled"
:
"disabled"
);
...
@@ -2884,9 +2946,17 @@ static int hotkey_read(char *p)
...
@@ -2884,9 +2946,17 @@ static int hotkey_read(char *p)
return
len
;
return
len
;
}
}
static
void
hotkey_enabledisable_warn
(
void
)
{
tpacpi_log_usertask
(
"procfs hotkey enable/disable"
);
WARN
(
1
,
TPACPI_WARN
"hotkey enable/disable functionality has been "
"removed from the driver. Hotkeys are always enabled.
\n
"
);
}
static
int
hotkey_write
(
char
*
buf
)
static
int
hotkey_write
(
char
*
buf
)
{
{
int
res
,
status
;
int
res
;
u32
mask
;
u32
mask
;
char
*
cmd
;
char
*
cmd
;
...
@@ -2896,17 +2966,16 @@ static int hotkey_write(char *buf)
...
@@ -2896,17 +2966,16 @@ static int hotkey_write(char *buf)
if
(
mutex_lock_killable
(
&
hotkey_mutex
))
if
(
mutex_lock_killable
(
&
hotkey_mutex
))
return
-
ERESTARTSYS
;
return
-
ERESTARTSYS
;
status
=
-
1
;
mask
=
hotkey_mask
;
mask
=
hotkey_mask
;
res
=
0
;
res
=
0
;
while
((
cmd
=
next_cmd
(
&
buf
)))
{
while
((
cmd
=
next_cmd
(
&
buf
)))
{
if
(
strlencmp
(
cmd
,
"enable"
)
==
0
)
{
if
(
strlencmp
(
cmd
,
"enable"
)
==
0
)
{
status
=
1
;
hotkey_enabledisable_warn
()
;
}
else
if
(
strlencmp
(
cmd
,
"disable"
)
==
0
)
{
}
else
if
(
strlencmp
(
cmd
,
"disable"
)
==
0
)
{
status
=
0
;
hotkey_enabledisable_warn
();
res
=
-
EPERM
;
}
else
if
(
strlencmp
(
cmd
,
"reset"
)
==
0
)
{
}
else
if
(
strlencmp
(
cmd
,
"reset"
)
==
0
)
{
status
=
hotkey_orig_status
;
mask
=
hotkey_orig_mask
;
mask
=
hotkey_orig_mask
;
}
else
if
(
sscanf
(
cmd
,
"0x%x"
,
&
mask
)
==
1
)
{
}
else
if
(
sscanf
(
cmd
,
"0x%x"
,
&
mask
)
==
1
)
{
/* mask set */
/* mask set */
...
@@ -2917,8 +2986,10 @@ static int hotkey_write(char *buf)
...
@@ -2917,8 +2986,10 @@ static int hotkey_write(char *buf)
goto
errexit
;
goto
errexit
;
}
}
}
}
if
(
status
!=
-
1
)
res
=
hotkey_status_set
(
status
);
if
(
!
res
)
tpacpi_disclose_usertask
(
"procfs hotkey"
,
"set mask to 0x%08x
\n
"
,
mask
);
if
(
!
res
&&
mask
!=
hotkey_mask
)
if
(
!
res
&&
mask
!=
hotkey_mask
)
res
=
hotkey_mask_set
(
mask
);
res
=
hotkey_mask_set
(
mask
);
...
@@ -2971,13 +3042,17 @@ enum {
...
@@ -2971,13 +3042,17 @@ enum {
TP_ACPI_BLTH_SAVE_STATE
=
0x05
,
/* Save state for S4/S5 */
TP_ACPI_BLTH_SAVE_STATE
=
0x05
,
/* Save state for S4/S5 */
};
};
#define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw"
static
struct
rfkill
*
tpacpi_bluetooth_rfkill
;
static
struct
rfkill
*
tpacpi_bluetooth_rfkill
;
static
void
bluetooth_suspend
(
pm_message_t
state
)
static
void
bluetooth_suspend
(
pm_message_t
state
)
{
{
/* Try to make sure radio will resume powered off */
/* Try to make sure radio will resume powered off */
acpi_evalf
(
NULL
,
NULL
,
"
\\
BLTH"
,
"vd"
,
if
(
!
acpi_evalf
(
NULL
,
NULL
,
"
\\
BLTH"
,
"vd"
,
TP_ACPI_BLTH_PWR_OFF_ON_RESUME
);
TP_ACPI_BLTH_PWR_OFF_ON_RESUME
))
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"bluetooth power down on resume request failed
\n
"
);
}
}
static
int
bluetooth_get_radiosw
(
void
)
static
int
bluetooth_get_radiosw
(
void
)
...
@@ -3015,6 +3090,10 @@ static void bluetooth_update_rfk(void)
...
@@ -3015,6 +3090,10 @@ static void bluetooth_update_rfk(void)
if
(
status
<
0
)
if
(
status
<
0
)
return
;
return
;
rfkill_force_state
(
tpacpi_bluetooth_rfkill
,
status
);
rfkill_force_state
(
tpacpi_bluetooth_rfkill
,
status
);
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"forced rfkill state to %d
\n
"
,
status
);
}
}
static
int
bluetooth_set_radiosw
(
int
radio_on
,
int
update_rfk
)
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,6 +3109,9 @@ static int bluetooth_set_radiosw(int radio_on, int update_rfk)
&&
radio_on
)
&&
radio_on
)
return
-
EPERM
;
return
-
EPERM
;
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"will %s bluetooth
\n
"
,
radio_on
?
"enable"
:
"disable"
);
#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
if
(
dbg_bluetoothemul
)
{
if
(
dbg_bluetoothemul
)
{
tpacpi_bluetooth_emulstate
=
!!
radio_on
;
tpacpi_bluetooth_emulstate
=
!!
radio_on
;
...
@@ -3060,6 +3142,8 @@ static ssize_t bluetooth_enable_show(struct device *dev,
...
@@ -3060,6 +3142,8 @@ static ssize_t bluetooth_enable_show(struct device *dev,
{
{
int
status
;
int
status
;
printk_deprecated_rfkill_attribute
(
"bluetooth_enable"
);
status
=
bluetooth_get_radiosw
();
status
=
bluetooth_get_radiosw
();
if
(
status
<
0
)
if
(
status
<
0
)
return
status
;
return
status
;
...
@@ -3075,9 +3159,13 @@ static ssize_t bluetooth_enable_store(struct device *dev,
...
@@ -3075,9 +3159,13 @@ static ssize_t bluetooth_enable_store(struct device *dev,
unsigned
long
t
;
unsigned
long
t
;
int
res
;
int
res
;
printk_deprecated_rfkill_attribute
(
"bluetooth_enable"
);
if
(
parse_strtoul
(
buf
,
1
,
&
t
))
if
(
parse_strtoul
(
buf
,
1
,
&
t
))
return
-
EINVAL
;
return
-
EINVAL
;
tpacpi_disclose_usertask
(
"bluetooth_enable"
,
"set to %ld
\n
"
,
t
);
res
=
bluetooth_set_radiosw
(
t
,
1
);
res
=
bluetooth_set_radiosw
(
t
,
1
);
return
(
res
)
?
res
:
count
;
return
(
res
)
?
res
:
count
;
...
@@ -3111,6 +3199,8 @@ static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state)
...
@@ -3111,6 +3199,8 @@ static int tpacpi_bluetooth_rfk_get(void *data, enum rfkill_state *state)
static
int
tpacpi_bluetooth_rfk_set
(
void
*
data
,
enum
rfkill_state
state
)
static
int
tpacpi_bluetooth_rfk_set
(
void
*
data
,
enum
rfkill_state
state
)
{
{
dbg_printk
(
TPACPI_DBG_RFKILL
,
"request to change radio state to %d
\n
"
,
state
);
return
bluetooth_set_radiosw
((
state
==
RFKILL_STATE_UNBLOCKED
),
0
);
return
bluetooth_set_radiosw
((
state
==
RFKILL_STATE_UNBLOCKED
),
0
);
}
}
...
@@ -3121,6 +3211,9 @@ static void bluetooth_shutdown(void)
...
@@ -3121,6 +3211,9 @@ static void bluetooth_shutdown(void)
TP_ACPI_BLTH_SAVE_STATE
))
TP_ACPI_BLTH_SAVE_STATE
))
printk
(
TPACPI_NOTICE
printk
(
TPACPI_NOTICE
"failed to save bluetooth state to NVRAM
\n
"
);
"failed to save bluetooth state to NVRAM
\n
"
);
else
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"bluestooth state saved to NVRAM
\n
"
);
}
}
static
void
bluetooth_exit
(
void
)
static
void
bluetooth_exit
(
void
)
...
@@ -3139,7 +3232,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
...
@@ -3139,7 +3232,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
int
res
;
int
res
;
int
status
=
0
;
int
status
=
0
;
vdbg_printk
(
TPACPI_DBG_INIT
,
"initializing bluetooth subdriver
\n
"
);
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"initializing bluetooth subdriver
\n
"
);
TPACPI_ACPIHANDLE_INIT
(
hkey
);
TPACPI_ACPIHANDLE_INIT
(
hkey
);
...
@@ -3148,7 +3242,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
...
@@ -3148,7 +3242,8 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
tp_features
.
bluetooth
=
hkey_handle
&&
tp_features
.
bluetooth
=
hkey_handle
&&
acpi_evalf
(
hkey_handle
,
&
status
,
"GBDC"
,
"qd"
);
acpi_evalf
(
hkey_handle
,
&
status
,
"GBDC"
,
"qd"
);
vdbg_printk
(
TPACPI_DBG_INIT
,
"bluetooth is %s, status 0x%02x
\n
"
,
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"bluetooth is %s, status 0x%02x
\n
"
,
str_supported
(
tp_features
.
bluetooth
),
str_supported
(
tp_features
.
bluetooth
),
status
);
status
);
...
@@ -3163,7 +3258,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
...
@@ -3163,7 +3258,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
!
(
status
&
TP_ACPI_BLUETOOTH_HWPRESENT
))
{
!
(
status
&
TP_ACPI_BLUETOOTH_HWPRESENT
))
{
/* no bluetooth hardware present in system */
/* no bluetooth hardware present in system */
tp_features
.
bluetooth
=
0
;
tp_features
.
bluetooth
=
0
;
dbg_printk
(
TPACPI_DBG_INIT
,
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"bluetooth hardware not installed
\n
"
);
"bluetooth hardware not installed
\n
"
);
}
}
...
@@ -3178,7 +3273,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
...
@@ -3178,7 +3273,7 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm)
res
=
tpacpi_new_rfkill
(
TPACPI_RFK_BLUETOOTH_SW_ID
,
res
=
tpacpi_new_rfkill
(
TPACPI_RFK_BLUETOOTH_SW_ID
,
&
tpacpi_bluetooth_rfkill
,
&
tpacpi_bluetooth_rfkill
,
RFKILL_TYPE_BLUETOOTH
,
RFKILL_TYPE_BLUETOOTH
,
"tpacpi_bluetooth_sw"
,
TPACPI_RFK_BLUETOOTH_SW_NAME
,
true
,
true
,
tpacpi_bluetooth_rfk_set
,
tpacpi_bluetooth_rfk_set
,
tpacpi_bluetooth_rfk_get
);
tpacpi_bluetooth_rfk_get
);
...
@@ -3211,19 +3306,27 @@ static int bluetooth_read(char *p)
...
@@ -3211,19 +3306,27 @@ static int bluetooth_read(char *p)
static
int
bluetooth_write
(
char
*
buf
)
static
int
bluetooth_write
(
char
*
buf
)
{
{
char
*
cmd
;
char
*
cmd
;
int
state
=
-
1
;
if
(
!
tp_features
.
bluetooth
)
if
(
!
tp_features
.
bluetooth
)
return
-
ENODEV
;
return
-
ENODEV
;
while
((
cmd
=
next_cmd
(
&
buf
)))
{
while
((
cmd
=
next_cmd
(
&
buf
)))
{
if
(
strlencmp
(
cmd
,
"enable"
)
==
0
)
{
if
(
strlencmp
(
cmd
,
"enable"
)
==
0
)
{
bluetooth_set_radiosw
(
1
,
1
)
;
state
=
1
;
}
else
if
(
strlencmp
(
cmd
,
"disable"
)
==
0
)
{
}
else
if
(
strlencmp
(
cmd
,
"disable"
)
==
0
)
{
bluetooth_set_radiosw
(
0
,
1
)
;
state
=
0
;
}
else
}
else
return
-
EINVAL
;
return
-
EINVAL
;
}
}
if
(
state
!=
-
1
)
{
tpacpi_disclose_usertask
(
"procfs bluetooth"
,
"attempt to %s
\n
"
,
state
?
"enable"
:
"disable"
);
bluetooth_set_radiosw
(
state
,
1
);
}
return
0
;
return
0
;
}
}
...
@@ -3248,13 +3351,17 @@ enum {
...
@@ -3248,13 +3351,17 @@ enum {
off / last state */
off / last state */
};
};
#define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw"
static
struct
rfkill
*
tpacpi_wan_rfkill
;
static
struct
rfkill
*
tpacpi_wan_rfkill
;
static
void
wan_suspend
(
pm_message_t
state
)
static
void
wan_suspend
(
pm_message_t
state
)
{
{
/* Try to make sure radio will resume powered off */
/* Try to make sure radio will resume powered off */
acpi_evalf
(
NULL
,
NULL
,
"
\\
WGSV"
,
"qvd"
,
if
(
!
acpi_evalf
(
NULL
,
NULL
,
"
\\
WGSV"
,
"qvd"
,
TP_ACPI_WGSV_PWR_OFF_ON_RESUME
);
TP_ACPI_WGSV_PWR_OFF_ON_RESUME
))
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"WWAN power down on resume request failed
\n
"
);
}
}
static
int
wan_get_radiosw
(
void
)
static
int
wan_get_radiosw
(
void
)
...
@@ -3292,6 +3399,10 @@ static void wan_update_rfk(void)
...
@@ -3292,6 +3399,10 @@ static void wan_update_rfk(void)
if
(
status
<
0
)
if
(
status
<
0
)
return
;
return
;
rfkill_force_state
(
tpacpi_wan_rfkill
,
status
);
rfkill_force_state
(
tpacpi_wan_rfkill
,
status
);
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"forced rfkill state to %d
\n
"
,
status
);
}
}
static
int
wan_set_radiosw
(
int
radio_on
,
int
update_rfk
)
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,6 +3418,9 @@ static int wan_set_radiosw(int radio_on, int update_rfk)
&&
radio_on
)
&&
radio_on
)
return
-
EPERM
;
return
-
EPERM
;
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"will %s WWAN
\n
"
,
radio_on
?
"enable"
:
"disable"
);
#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
if
(
dbg_wwanemul
)
{
if
(
dbg_wwanemul
)
{
tpacpi_wwan_emulstate
=
!!
radio_on
;
tpacpi_wwan_emulstate
=
!!
radio_on
;
...
@@ -3337,6 +3451,8 @@ static ssize_t wan_enable_show(struct device *dev,
...
@@ -3337,6 +3451,8 @@ static ssize_t wan_enable_show(struct device *dev,
{
{
int
status
;
int
status
;
printk_deprecated_rfkill_attribute
(
"wwan_enable"
);
status
=
wan_get_radiosw
();
status
=
wan_get_radiosw
();
if
(
status
<
0
)
if
(
status
<
0
)
return
status
;
return
status
;
...
@@ -3352,9 +3468,13 @@ static ssize_t wan_enable_store(struct device *dev,
...
@@ -3352,9 +3468,13 @@ static ssize_t wan_enable_store(struct device *dev,
unsigned
long
t
;
unsigned
long
t
;
int
res
;
int
res
;
printk_deprecated_rfkill_attribute
(
"wwan_enable"
);
if
(
parse_strtoul
(
buf
,
1
,
&
t
))
if
(
parse_strtoul
(
buf
,
1
,
&
t
))
return
-
EINVAL
;
return
-
EINVAL
;
tpacpi_disclose_usertask
(
"wwan_enable"
,
"set to %ld
\n
"
,
t
);
res
=
wan_set_radiosw
(
t
,
1
);
res
=
wan_set_radiosw
(
t
,
1
);
return
(
res
)
?
res
:
count
;
return
(
res
)
?
res
:
count
;
...
@@ -3388,6 +3508,8 @@ static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state)
...
@@ -3388,6 +3508,8 @@ static int tpacpi_wan_rfk_get(void *data, enum rfkill_state *state)
static
int
tpacpi_wan_rfk_set
(
void
*
data
,
enum
rfkill_state
state
)
static
int
tpacpi_wan_rfk_set
(
void
*
data
,
enum
rfkill_state
state
)
{
{
dbg_printk
(
TPACPI_DBG_RFKILL
,
"request to change radio state to %d
\n
"
,
state
);
return
wan_set_radiosw
((
state
==
RFKILL_STATE_UNBLOCKED
),
0
);
return
wan_set_radiosw
((
state
==
RFKILL_STATE_UNBLOCKED
),
0
);
}
}
...
@@ -3398,6 +3520,9 @@ static void wan_shutdown(void)
...
@@ -3398,6 +3520,9 @@ static void wan_shutdown(void)
TP_ACPI_WGSV_SAVE_STATE
))
TP_ACPI_WGSV_SAVE_STATE
))
printk
(
TPACPI_NOTICE
printk
(
TPACPI_NOTICE
"failed to save WWAN state to NVRAM
\n
"
);
"failed to save WWAN state to NVRAM
\n
"
);
else
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"WWAN state saved to NVRAM
\n
"
);
}
}
static
void
wan_exit
(
void
)
static
void
wan_exit
(
void
)
...
@@ -3416,14 +3541,16 @@ static int __init wan_init(struct ibm_init_struct *iibm)
...
@@ -3416,14 +3541,16 @@ static int __init wan_init(struct ibm_init_struct *iibm)
int
res
;
int
res
;
int
status
=
0
;
int
status
=
0
;
vdbg_printk
(
TPACPI_DBG_INIT
,
"initializing wan subdriver
\n
"
);
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"initializing wan subdriver
\n
"
);
TPACPI_ACPIHANDLE_INIT
(
hkey
);
TPACPI_ACPIHANDLE_INIT
(
hkey
);
tp_features
.
wan
=
hkey_handle
&&
tp_features
.
wan
=
hkey_handle
&&
acpi_evalf
(
hkey_handle
,
&
status
,
"GWAN"
,
"qd"
);
acpi_evalf
(
hkey_handle
,
&
status
,
"GWAN"
,
"qd"
);
vdbg_printk
(
TPACPI_DBG_INIT
,
"wan is %s, status 0x%02x
\n
"
,
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"wan is %s, status 0x%02x
\n
"
,
str_supported
(
tp_features
.
wan
),
str_supported
(
tp_features
.
wan
),
status
);
status
);
...
@@ -3438,7 +3565,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
...
@@ -3438,7 +3565,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
!
(
status
&
TP_ACPI_WANCARD_HWPRESENT
))
{
!
(
status
&
TP_ACPI_WANCARD_HWPRESENT
))
{
/* no wan hardware present in system */
/* no wan hardware present in system */
tp_features
.
wan
=
0
;
tp_features
.
wan
=
0
;
dbg_printk
(
TPACPI_DBG_INIT
,
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"wan hardware not installed
\n
"
);
"wan hardware not installed
\n
"
);
}
}
...
@@ -3453,7 +3580,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
...
@@ -3453,7 +3580,7 @@ static int __init wan_init(struct ibm_init_struct *iibm)
res
=
tpacpi_new_rfkill
(
TPACPI_RFK_WWAN_SW_ID
,
res
=
tpacpi_new_rfkill
(
TPACPI_RFK_WWAN_SW_ID
,
&
tpacpi_wan_rfkill
,
&
tpacpi_wan_rfkill
,
RFKILL_TYPE_WWAN
,
RFKILL_TYPE_WWAN
,
"tpacpi_wwan_sw"
,
TPACPI_RFK_WWAN_SW_NAME
,
true
,
true
,
tpacpi_wan_rfk_set
,
tpacpi_wan_rfk_set
,
tpacpi_wan_rfk_get
);
tpacpi_wan_rfk_get
);
...
@@ -3471,6 +3598,8 @@ static int wan_read(char *p)
...
@@ -3471,6 +3598,8 @@ static int wan_read(char *p)
int
len
=
0
;
int
len
=
0
;
int
status
=
wan_get_radiosw
();
int
status
=
wan_get_radiosw
();
tpacpi_disclose_usertask
(
"procfs wan"
,
"read"
);
if
(
!
tp_features
.
wan
)
if
(
!
tp_features
.
wan
)
len
+=
sprintf
(
p
+
len
,
"status:
\t\t
not supported
\n
"
);
len
+=
sprintf
(
p
+
len
,
"status:
\t\t
not supported
\n
"
);
else
{
else
{
...
@@ -3486,19 +3615,27 @@ static int wan_read(char *p)
...
@@ -3486,19 +3615,27 @@ static int wan_read(char *p)
static
int
wan_write
(
char
*
buf
)
static
int
wan_write
(
char
*
buf
)
{
{
char
*
cmd
;
char
*
cmd
;
int
state
=
-
1
;
if
(
!
tp_features
.
wan
)
if
(
!
tp_features
.
wan
)
return
-
ENODEV
;
return
-
ENODEV
;
while
((
cmd
=
next_cmd
(
&
buf
)))
{
while
((
cmd
=
next_cmd
(
&
buf
)))
{
if
(
strlencmp
(
cmd
,
"enable"
)
==
0
)
{
if
(
strlencmp
(
cmd
,
"enable"
)
==
0
)
{
wan_set_radiosw
(
1
,
1
)
;
state
=
1
;
}
else
if
(
strlencmp
(
cmd
,
"disable"
)
==
0
)
{
}
else
if
(
strlencmp
(
cmd
,
"disable"
)
==
0
)
{
wan_set_radiosw
(
0
,
1
)
;
state
=
0
;
}
else
}
else
return
-
EINVAL
;
return
-
EINVAL
;
}
}
if
(
state
!=
-
1
)
{
tpacpi_disclose_usertask
(
"procfs wan"
,
"attempt to %s
\n
"
,
state
?
"enable"
:
"disable"
);
wan_set_radiosw
(
state
,
1
);
}
return
0
;
return
0
;
}
}
...
@@ -3521,6 +3658,8 @@ enum {
...
@@ -3521,6 +3658,8 @@ enum {
TP_ACPI_UWB_RADIOSSW
=
0x02
,
/* UWB radio enabled */
TP_ACPI_UWB_RADIOSSW
=
0x02
,
/* UWB radio enabled */
};
};
#define TPACPI_RFK_UWB_SW_NAME "tpacpi_uwb_sw"
static
struct
rfkill
*
tpacpi_uwb_rfkill
;
static
struct
rfkill
*
tpacpi_uwb_rfkill
;
static
int
uwb_get_radiosw
(
void
)
static
int
uwb_get_radiosw
(
void
)
...
@@ -3558,6 +3697,10 @@ static void uwb_update_rfk(void)
...
@@ -3558,6 +3697,10 @@ static void uwb_update_rfk(void)
if
(
status
<
0
)
if
(
status
<
0
)
return
;
return
;
rfkill_force_state
(
tpacpi_uwb_rfkill
,
status
);
rfkill_force_state
(
tpacpi_uwb_rfkill
,
status
);
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"forced rfkill state to %d
\n
"
,
status
);
}
}
static
int
uwb_set_radiosw
(
int
radio_on
,
int
update_rfk
)
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,6 +3716,9 @@ static int uwb_set_radiosw(int radio_on, int update_rfk)
&&
radio_on
)
&&
radio_on
)
return
-
EPERM
;
return
-
EPERM
;
vdbg_printk
(
TPACPI_DBG_RFKILL
,
"will %s UWB
\n
"
,
radio_on
?
"enable"
:
"disable"
);
#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
#ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES
if
(
dbg_uwbemul
)
{
if
(
dbg_uwbemul
)
{
tpacpi_uwb_emulstate
=
!!
radio_on
;
tpacpi_uwb_emulstate
=
!!
radio_on
;
...
@@ -3607,6 +3753,8 @@ static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state)
...
@@ -3607,6 +3753,8 @@ static int tpacpi_uwb_rfk_get(void *data, enum rfkill_state *state)
static
int
tpacpi_uwb_rfk_set
(
void
*
data
,
enum
rfkill_state
state
)
static
int
tpacpi_uwb_rfk_set
(
void
*
data
,
enum
rfkill_state
state
)
{
{
dbg_printk
(
TPACPI_DBG_RFKILL
,
"request to change radio state to %d
\n
"
,
state
);
return
uwb_set_radiosw
((
state
==
RFKILL_STATE_UNBLOCKED
),
0
);
return
uwb_set_radiosw
((
state
==
RFKILL_STATE_UNBLOCKED
),
0
);
}
}
...
@@ -3621,14 +3769,16 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
...
@@ -3621,14 +3769,16 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
int
res
;
int
res
;
int
status
=
0
;
int
status
=
0
;
vdbg_printk
(
TPACPI_DBG_INIT
,
"initializing uwb subdriver
\n
"
);
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"initializing uwb subdriver
\n
"
);
TPACPI_ACPIHANDLE_INIT
(
hkey
);
TPACPI_ACPIHANDLE_INIT
(
hkey
);
tp_features
.
uwb
=
hkey_handle
&&
tp_features
.
uwb
=
hkey_handle
&&
acpi_evalf
(
hkey_handle
,
&
status
,
"GUWB"
,
"qd"
);
acpi_evalf
(
hkey_handle
,
&
status
,
"GUWB"
,
"qd"
);
vdbg_printk
(
TPACPI_DBG_INIT
,
"uwb is %s, status 0x%02x
\n
"
,
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_RFKILL
,
"uwb is %s, status 0x%02x
\n
"
,
str_supported
(
tp_features
.
uwb
),
str_supported
(
tp_features
.
uwb
),
status
);
status
);
...
@@ -3653,7 +3803,7 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
...
@@ -3653,7 +3803,7 @@ static int __init uwb_init(struct ibm_init_struct *iibm)
res
=
tpacpi_new_rfkill
(
TPACPI_RFK_UWB_SW_ID
,
res
=
tpacpi_new_rfkill
(
TPACPI_RFK_UWB_SW_ID
,
&
tpacpi_uwb_rfkill
,
&
tpacpi_uwb_rfkill
,
RFKILL_TYPE_UWB
,
RFKILL_TYPE_UWB
,
"tpacpi_uwb_sw"
,
TPACPI_RFK_UWB_SW_NAME
,
false
,
false
,
tpacpi_uwb_rfk_set
,
tpacpi_uwb_rfk_set
,
tpacpi_uwb_rfk_get
);
tpacpi_uwb_rfk_get
);
...
@@ -4602,6 +4752,16 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
...
@@ -4602,6 +4752,16 @@ static const char * const tpacpi_led_names[TPACPI_LED_NUMLEDS] = {
"tpacpi::unknown_led"
,
"tpacpi::unknown_led"
,
"tpacpi::standby"
,
"tpacpi::standby"
,
};
};
#define TPACPI_SAFE_LEDS 0x0081U
static
inline
bool
tpacpi_is_led_restricted
(
const
unsigned
int
led
)
{
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
return
false
;
#else
return
(
TPACPI_SAFE_LEDS
&
(
1
<<
led
))
==
0
;
#endif
}
static
int
led_get_status
(
const
unsigned
int
led
)
static
int
led_get_status
(
const
unsigned
int
led
)
{
{
...
@@ -4639,16 +4799,20 @@ static int led_set_status(const unsigned int led,
...
@@ -4639,16 +4799,20 @@ static int led_set_status(const unsigned int led,
switch
(
led_supported
)
{
switch
(
led_supported
)
{
case
TPACPI_LED_570
:
case
TPACPI_LED_570
:
/* 570 */
/* 570 */
if
(
led
>
7
)
if
(
unlikely
(
led
>
7
)
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
unlikely
(
tpacpi_is_led_restricted
(
led
)))
return
-
EPERM
;
if
(
!
acpi_evalf
(
led_handle
,
NULL
,
NULL
,
"vdd"
,
if
(
!
acpi_evalf
(
led_handle
,
NULL
,
NULL
,
"vdd"
,
(
1
<<
led
),
led_sled_arg1
[
ledstatus
]))
(
1
<<
led
),
led_sled_arg1
[
ledstatus
]))
rc
=
-
EIO
;
rc
=
-
EIO
;
break
;
break
;
case
TPACPI_LED_OLD
:
case
TPACPI_LED_OLD
:
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
/* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
if
(
led
>
7
)
if
(
unlikely
(
led
>
7
)
)
return
-
EINVAL
;
return
-
EINVAL
;
if
(
unlikely
(
tpacpi_is_led_restricted
(
led
)))
return
-
EPERM
;
rc
=
ec_write
(
TPACPI_LED_EC_HLMS
,
(
1
<<
led
));
rc
=
ec_write
(
TPACPI_LED_EC_HLMS
,
(
1
<<
led
));
if
(
rc
>=
0
)
if
(
rc
>=
0
)
rc
=
ec_write
(
TPACPI_LED_EC_HLBL
,
rc
=
ec_write
(
TPACPI_LED_EC_HLBL
,
...
@@ -4659,6 +4823,10 @@ static int led_set_status(const unsigned int led,
...
@@ -4659,6 +4823,10 @@ static int led_set_status(const unsigned int led,
break
;
break
;
case
TPACPI_LED_NEW
:
case
TPACPI_LED_NEW
:
/* all others */
/* all others */
if
(
unlikely
(
led
>=
TPACPI_LED_NUMLEDS
))
return
-
EINVAL
;
if
(
unlikely
(
tpacpi_is_led_restricted
(
led
)))
return
-
EPERM
;
if
(
!
acpi_evalf
(
led_handle
,
NULL
,
NULL
,
"vdd"
,
if
(
!
acpi_evalf
(
led_handle
,
NULL
,
NULL
,
"vdd"
,
led
,
led_led_arg1
[
ledstatus
]))
led
,
led_led_arg1
[
ledstatus
]))
rc
=
-
EIO
;
rc
=
-
EIO
;
...
@@ -4751,6 +4919,30 @@ static void led_exit(void)
...
@@ -4751,6 +4919,30 @@ static void led_exit(void)
kfree
(
tpacpi_leds
);
kfree
(
tpacpi_leds
);
}
}
static
int
__init
tpacpi_init_led
(
unsigned
int
led
)
{
int
rc
;
tpacpi_leds
[
led
].
led
=
led
;
tpacpi_leds
[
led
].
led_classdev
.
brightness_set
=
&
led_sysfs_set
;
tpacpi_leds
[
led
].
led_classdev
.
blink_set
=
&
led_sysfs_blink_set
;
if
(
led_supported
==
TPACPI_LED_570
)
tpacpi_leds
[
led
].
led_classdev
.
brightness_get
=
&
led_sysfs_get
;
tpacpi_leds
[
led
].
led_classdev
.
name
=
tpacpi_led_names
[
led
];
INIT_WORK
(
&
tpacpi_leds
[
led
].
work
,
led_set_status_worker
);
rc
=
led_classdev_register
(
&
tpacpi_pdev
->
dev
,
&
tpacpi_leds
[
led
].
led_classdev
);
if
(
rc
<
0
)
tpacpi_leds
[
led
].
led_classdev
.
name
=
NULL
;
return
rc
;
}
static
int
__init
led_init
(
struct
ibm_init_struct
*
iibm
)
static
int
__init
led_init
(
struct
ibm_init_struct
*
iibm
)
{
{
unsigned
int
i
;
unsigned
int
i
;
...
@@ -4784,27 +4976,21 @@ static int __init led_init(struct ibm_init_struct *iibm)
...
@@ -4784,27 +4976,21 @@ static int __init led_init(struct ibm_init_struct *iibm)
}
}
for
(
i
=
0
;
i
<
TPACPI_LED_NUMLEDS
;
i
++
)
{
for
(
i
=
0
;
i
<
TPACPI_LED_NUMLEDS
;
i
++
)
{
tpacpi_leds
[
i
].
led
=
i
;
if
(
!
tpacpi_is_led_restricted
(
i
))
{
rc
=
tpacpi_init_led
(
i
);
tpacpi_leds
[
i
].
led_classdev
.
brightness_set
=
&
led_sysfs_set
;
if
(
rc
<
0
)
{
tpacpi_leds
[
i
].
led_classdev
.
blink_set
=
&
led_sysfs_blink_set
;
led_exit
();
if
(
led_supported
==
TPACPI_LED_570
)
return
rc
;
tpacpi_leds
[
i
].
led_classdev
.
brightness_get
=
}
&
led_sysfs_get
;
tpacpi_leds
[
i
].
led_classdev
.
name
=
tpacpi_led_names
[
i
];
INIT_WORK
(
&
tpacpi_leds
[
i
].
work
,
led_set_status_worker
);
rc
=
led_classdev_register
(
&
tpacpi_pdev
->
dev
,
&
tpacpi_leds
[
i
].
led_classdev
);
if
(
rc
<
0
)
{
tpacpi_leds
[
i
].
led_classdev
.
name
=
NULL
;
led_exit
();
return
rc
;
}
}
}
}
#ifdef CONFIG_THINKPAD_ACPI_UNSAFE_LEDS
if
(
led_supported
!=
TPACPI_LED_NONE
)
printk
(
TPACPI_NOTICE
"warning: userspace override of important "
"firmware LEDs is enabled
\n
"
);
#endif
return
(
led_supported
!=
TPACPI_LED_NONE
)
?
0
:
1
;
return
(
led_supported
!=
TPACPI_LED_NONE
)
?
0
:
1
;
}
}
...
@@ -5340,6 +5526,20 @@ static struct ibm_struct ecdump_driver_data = {
...
@@ -5340,6 +5526,20 @@ static struct ibm_struct ecdump_driver_data = {
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
/*
* ThinkPads can read brightness from two places: EC HBRV (0x31), or
* CMOS NVRAM byte 0x5E, bits 0-3.
*
* EC HBRV (0x31) has the following layout
* Bit 7: unknown function
* Bit 6: unknown function
* Bit 5: Z: honour scale changes, NZ: ignore scale changes
* Bit 4: must be set to zero to avoid problems
* Bit 3-0: backlight brightness level
*
* brightness_get_raw returns status data in the HBRV layout
*/
enum
{
enum
{
TP_EC_BACKLIGHT
=
0x31
,
TP_EC_BACKLIGHT
=
0x31
,
...
@@ -5349,108 +5549,164 @@ enum {
...
@@ -5349,108 +5549,164 @@ enum {
TP_EC_BACKLIGHT_MAPSW
=
0x20
,
TP_EC_BACKLIGHT_MAPSW
=
0x20
,
};
};
enum
tpacpi_brightness_access_mode
{
TPACPI_BRGHT_MODE_AUTO
=
0
,
/* Not implemented yet */
TPACPI_BRGHT_MODE_EC
,
/* EC control */
TPACPI_BRGHT_MODE_UCMS_STEP
,
/* UCMS step-based control */
TPACPI_BRGHT_MODE_ECNVRAM
,
/* EC control w/ NVRAM store */
TPACPI_BRGHT_MODE_MAX
};
static
struct
backlight_device
*
ibm_backlight_device
;
static
struct
backlight_device
*
ibm_backlight_device
;
static
int
brightness_mode
;
static
enum
tpacpi_brightness_access_mode
brightness_mode
=
TPACPI_BRGHT_MODE_MAX
;
static
unsigned
int
brightness_enable
=
2
;
/* 2 = auto, 0 = no, 1 = yes */
static
unsigned
int
brightness_enable
=
2
;
/* 2 = auto, 0 = no, 1 = yes */
static
struct
mutex
brightness_mutex
;
static
struct
mutex
brightness_mutex
;
/*
/* NVRAM brightness access,
* ThinkPads can read brightness from two places: EC 0x31, or
* call with brightness_mutex held! */
* CMOS NVRAM byte 0x5E, bits 0-3.
static
unsigned
int
tpacpi_brightness_nvram_get
(
void
)
*
* EC 0x31 has the following layout
* Bit 7: unknown function
* Bit 6: unknown function
* Bit 5: Z: honour scale changes, NZ: ignore scale changes
* Bit 4: must be set to zero to avoid problems
* Bit 3-0: backlight brightness level
*
* brightness_get_raw returns status data in the EC 0x31 layout
*/
static
int
brightness_get_raw
(
int
*
status
)
{
{
u8
l
ec
=
0
,
lcmos
=
0
,
level
=
0
;
u8
l
nvram
;
if
(
brightness_mode
&
1
)
{
lnvram
=
(
nvram_read_byte
(
TP_NVRAM_ADDR_BRIGHTNESS
)
if
(
!
acpi_ec_read
(
TP_EC_BACKLIGHT
,
&
lec
))
&
TP_NVRAM_MASK_LEVEL_BRIGHTNESS
)
return
-
EIO
;
>>
TP_NVRAM_POS_LEVEL_BRIGHTNESS
;
level
=
lec
&
TP_EC_BACKLIGHT_LVLMSK
;
lnvram
&=
(
tp_features
.
bright_16levels
)
?
0x0f
:
0x07
;
};
if
(
brightness_mode
&
2
)
{
return
lnvram
;
lcmos
=
(
nvram_read_byte
(
TP_NVRAM_ADDR_BRIGHTNESS
)
}
&
TP_NVRAM_MASK_LEVEL_BRIGHTNESS
)
>>
TP_NVRAM_POS_LEVEL_BRIGHTNESS
;
static
void
tpacpi_brightness_checkpoint_nvram
(
void
)
lcmos
&=
(
tp_features
.
bright_16levels
)
?
0x0f
:
0x07
;
{
level
=
lcmos
;
u8
lec
=
0
;
}
u8
b_nvram
;
if
(
brightness_mode
==
3
)
{
if
(
brightness_mode
!=
TPACPI_BRGHT_MODE_ECNVRAM
)
*
status
=
lec
;
/* Prefer EC, CMOS is just a backing store */
return
;
lec
&=
TP_EC_BACKLIGHT_LVLMSK
;
if
(
lec
==
lcmos
)
vdbg_printk
(
TPACPI_DBG_BRGHT
,
tp_warned
.
bright_cmos_ec_unsync
=
0
;
"trying to checkpoint backlight level to NVRAM...
\n
"
);
else
{
if
(
!
tp_warned
.
bright_cmos_ec_unsync
)
{
if
(
mutex_lock_killable
(
&
brightness_mutex
)
<
0
)
printk
(
TPACPI_ERR
return
;
"CMOS NVRAM (%u) and EC (%u) do not "
"agree on display brightness level
\n
"
,
if
(
unlikely
(
!
acpi_ec_read
(
TP_EC_BACKLIGHT
,
&
lec
)))
(
unsigned
int
)
lcmos
,
goto
unlock
;
(
unsigned
int
)
lec
);
lec
&=
TP_EC_BACKLIGHT_LVLMSK
;
tp_warned
.
bright_cmos_ec_unsync
=
1
;
b_nvram
=
nvram_read_byte
(
TP_NVRAM_ADDR_BRIGHTNESS
);
}
if
(
lec
!=
((
b_nvram
&
TP_NVRAM_MASK_LEVEL_BRIGHTNESS
)
>>
TP_NVRAM_POS_LEVEL_BRIGHTNESS
))
{
/* NVRAM needs update */
b_nvram
&=
~
(
TP_NVRAM_MASK_LEVEL_BRIGHTNESS
<<
TP_NVRAM_POS_LEVEL_BRIGHTNESS
);
b_nvram
|=
lec
;
nvram_write_byte
(
b_nvram
,
TP_NVRAM_ADDR_BRIGHTNESS
);
dbg_printk
(
TPACPI_DBG_BRGHT
,
"updated NVRAM backlight level to %u (0x%02x)
\n
"
,
(
unsigned
int
)
lec
,
(
unsigned
int
)
b_nvram
);
}
else
vdbg_printk
(
TPACPI_DBG_BRGHT
,
"NVRAM backlight level already is %u (0x%02x)
\n
"
,
(
unsigned
int
)
lec
,
(
unsigned
int
)
b_nvram
);
unlock:
mutex_unlock
(
&
brightness_mutex
);
}
/* call with brightness_mutex held! */
static
int
tpacpi_brightness_get_raw
(
int
*
status
)
{
u8
lec
=
0
;
switch
(
brightness_mode
)
{
case
TPACPI_BRGHT_MODE_UCMS_STEP
:
*
status
=
tpacpi_brightness_nvram_get
();
return
0
;
case
TPACPI_BRGHT_MODE_EC
:
case
TPACPI_BRGHT_MODE_ECNVRAM
:
if
(
unlikely
(
!
acpi_ec_read
(
TP_EC_BACKLIGHT
,
&
lec
)))
return
-
EIO
;
return
-
EIO
;
}
*
status
=
lec
;
}
else
{
return
0
;
*
status
=
level
;
default:
return
-
ENXIO
;
}
}
}
/* call with brightness_mutex held! */
/* do NOT call with illegal backlight level value */
static
int
tpacpi_brightness_set_ec
(
unsigned
int
value
)
{
u8
lec
=
0
;
if
(
unlikely
(
!
acpi_ec_read
(
TP_EC_BACKLIGHT
,
&
lec
)))
return
-
EIO
;
if
(
unlikely
(
!
acpi_ec_write
(
TP_EC_BACKLIGHT
,
(
lec
&
TP_EC_BACKLIGHT_CMDMSK
)
|
(
value
&
TP_EC_BACKLIGHT_LVLMSK
))))
return
-
EIO
;
return
0
;
}
/* call with brightness_mutex held! */
static
int
tpacpi_brightness_set_ucmsstep
(
unsigned
int
value
)
{
int
cmos_cmd
,
inc
;
unsigned
int
current_value
,
i
;
current_value
=
tpacpi_brightness_nvram_get
();
if
(
value
==
current_value
)
return
0
;
cmos_cmd
=
(
value
>
current_value
)
?
TP_CMOS_BRIGHTNESS_UP
:
TP_CMOS_BRIGHTNESS_DOWN
;
inc
=
(
value
>
current_value
)
?
1
:
-
1
;
for
(
i
=
current_value
;
i
!=
value
;
i
+=
inc
)
if
(
issue_thinkpad_cmos_command
(
cmos_cmd
))
return
-
EIO
;
return
0
;
return
0
;
}
}
/* May return EINTR which can always be mapped to ERESTARTSYS */
/* May return EINTR which can always be mapped to ERESTARTSYS */
static
int
brightness_set
(
int
value
)
static
int
brightness_set
(
unsigned
int
value
)
{
{
int
cmos_cmd
,
inc
,
i
,
res
;
int
res
;
int
current_value
;
int
command_bits
;
if
(
value
>
((
tp_features
.
bright_16levels
)
?
15
:
7
)
||
if
(
value
>
((
tp_features
.
bright_16levels
)
?
15
:
7
)
||
value
<
0
)
value
<
0
)
return
-
EINVAL
;
return
-
EINVAL
;
vdbg_printk
(
TPACPI_DBG_BRGHT
,
"set backlight level to %d
\n
"
,
value
);
res
=
mutex_lock_killable
(
&
brightness_mutex
);
res
=
mutex_lock_killable
(
&
brightness_mutex
);
if
(
res
<
0
)
if
(
res
<
0
)
return
res
;
return
res
;
res
=
brightness_get_raw
(
&
current_value
);
switch
(
brightness_mode
)
{
if
(
res
<
0
)
case
TPACPI_BRGHT_MODE_EC
:
goto
errout
;
case
TPACPI_BRGHT_MODE_ECNVRAM
:
res
=
tpacpi_brightness_set_ec
(
value
);
command_bits
=
current_value
&
TP_EC_BACKLIGHT_CMDMSK
;
break
;
current_value
&=
TP_EC_BACKLIGHT_LVLMSK
;
case
TPACPI_BRGHT_MODE_UCMS_STEP
:
res
=
tpacpi_brightness_set_ucmsstep
(
value
);
cmos_cmd
=
value
>
current_value
?
break
;
TP_CMOS_BRIGHTNESS_UP
:
default:
TP_CMOS_BRIGHTNESS_DOWN
;
res
=
-
ENXIO
;
inc
=
(
value
>
current_value
)
?
1
:
-
1
;
res
=
0
;
for
(
i
=
current_value
;
i
!=
value
;
i
+=
inc
)
{
if
((
brightness_mode
&
2
)
&&
issue_thinkpad_cmos_command
(
cmos_cmd
))
{
res
=
-
EIO
;
goto
errout
;
}
if
((
brightness_mode
&
1
)
&&
!
acpi_ec_write
(
TP_EC_BACKLIGHT
,
(
i
+
inc
)
|
command_bits
))
{
res
=
-
EIO
;
goto
errout
;;
}
}
}
errout:
mutex_unlock
(
&
brightness_mutex
);
mutex_unlock
(
&
brightness_mutex
);
return
res
;
return
res
;
}
}
...
@@ -5459,21 +5715,34 @@ errout:
...
@@ -5459,21 +5715,34 @@ errout:
static
int
brightness_update_status
(
struct
backlight_device
*
bd
)
static
int
brightness_update_status
(
struct
backlight_device
*
bd
)
{
{
/* it is the backlight class's job (caller) to handle
unsigned
int
level
=
* EINTR and other errors properly */
return
brightness_set
(
(
bd
->
props
.
fb_blank
==
FB_BLANK_UNBLANK
&&
(
bd
->
props
.
fb_blank
==
FB_BLANK_UNBLANK
&&
bd
->
props
.
power
==
FB_BLANK_UNBLANK
)
?
bd
->
props
.
power
==
FB_BLANK_UNBLANK
)
?
bd
->
props
.
brightness
:
0
);
bd
->
props
.
brightness
:
0
;
dbg_printk
(
TPACPI_DBG_BRGHT
,
"backlight: attempt to set level to %d
\n
"
,
level
);
/* it is the backlight class's job (caller) to handle
* EINTR and other errors properly */
return
brightness_set
(
level
);
}
}
static
int
brightness_get
(
struct
backlight_device
*
bd
)
static
int
brightness_get
(
struct
backlight_device
*
bd
)
{
{
int
status
,
res
;
int
status
,
res
;
res
=
brightness_get_raw
(
&
status
);
res
=
mutex_lock_killable
(
&
brightness_mutex
);
if
(
res
<
0
)
if
(
res
<
0
)
return
0
;
/* FIXME: teach backlight about error handling */
return
0
;
res
=
tpacpi_brightness_get_raw
(
&
status
);
mutex_unlock
(
&
brightness_mutex
);
if
(
res
<
0
)
return
0
;
return
status
&
TP_EC_BACKLIGHT_LVLMSK
;
return
status
&
TP_EC_BACKLIGHT_LVLMSK
;
}
}
...
@@ -5523,7 +5792,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
...
@@ -5523,7 +5792,7 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
}
}
if
(
!
brightness_enable
)
{
if
(
!
brightness_enable
)
{
dbg_printk
(
TPACPI_DBG_INIT
,
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_BRGHT
,
"brightness support disabled by "
"brightness support disabled by "
"module parameter
\n
"
);
"module parameter
\n
"
);
return
1
;
return
1
;
...
@@ -5538,20 +5807,38 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
...
@@ -5538,20 +5807,38 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
if
(
b
==
16
)
if
(
b
==
16
)
tp_features
.
bright_16levels
=
1
;
tp_features
.
bright_16levels
=
1
;
if
(
!
brightness_mode
)
{
/*
if
(
thinkpad_id
.
vendor
==
PCI_VENDOR_ID_LENOVO
)
* Check for module parameter bogosity, note that we
brightness_mode
=
2
;
* init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
else
* able to detect "unspecified"
brightness_mode
=
3
;
*/
if
(
brightness_mode
>
TPACPI_BRGHT_MODE_MAX
)
return
-
EINVAL
;
dbg_printk
(
TPACPI_DBG_INIT
,
"selected brightness_mode=%d
\n
"
,
/* TPACPI_BRGHT_MODE_AUTO not implemented yet, just use default */
brightness_mode
);
if
(
brightness_mode
==
TPACPI_BRGHT_MODE_AUTO
||
}
brightness_mode
==
TPACPI_BRGHT_MODE_MAX
)
{
if
(
thinkpad_id
.
vendor
==
PCI_VENDOR_ID_IBM
)
{
/*
* IBM models that define HBRV probably have
* EC-based backlight level control
*/
if
(
acpi_evalf
(
ec_handle
,
NULL
,
"HBRV"
,
"qd"
))
/* T40-T43, R50-R52, R50e, R51e, X31-X41 */
brightness_mode
=
TPACPI_BRGHT_MODE_ECNVRAM
;
else
/* all other IBM ThinkPads */
brightness_mode
=
TPACPI_BRGHT_MODE_UCMS_STEP
;
}
else
/* All Lenovo ThinkPads */
brightness_mode
=
TPACPI_BRGHT_MODE_UCMS_STEP
;
if
(
brightness_mode
>
3
)
dbg_printk
(
TPACPI_DBG_BRGHT
,
return
-
EINVAL
;
"selected brightness_mode=%d
\n
"
,
brightness_mode
);
}
if
(
brightness_get_raw
(
&
b
)
<
0
)
if
(
tpacpi_
brightness_get_raw
(
&
b
)
<
0
)
return
1
;
return
1
;
if
(
tp_features
.
bright_16levels
)
if
(
tp_features
.
bright_16levels
)
...
@@ -5565,7 +5852,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
...
@@ -5565,7 +5852,8 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
printk
(
TPACPI_ERR
"Could not register backlight device
\n
"
);
printk
(
TPACPI_ERR
"Could not register backlight device
\n
"
);
return
PTR_ERR
(
ibm_backlight_device
);
return
PTR_ERR
(
ibm_backlight_device
);
}
}
vdbg_printk
(
TPACPI_DBG_INIT
,
"brightness is supported
\n
"
);
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_BRGHT
,
"brightness is supported
\n
"
);
ibm_backlight_device
->
props
.
max_brightness
=
ibm_backlight_device
->
props
.
max_brightness
=
(
tp_features
.
bright_16levels
)
?
15
:
7
;
(
tp_features
.
bright_16levels
)
?
15
:
7
;
...
@@ -5575,13 +5863,25 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
...
@@ -5575,13 +5863,25 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
return
0
;
return
0
;
}
}
static
void
brightness_suspend
(
pm_message_t
state
)
{
tpacpi_brightness_checkpoint_nvram
();
}
static
void
brightness_shutdown
(
void
)
{
tpacpi_brightness_checkpoint_nvram
();
}
static
void
brightness_exit
(
void
)
static
void
brightness_exit
(
void
)
{
{
if
(
ibm_backlight_device
)
{
if
(
ibm_backlight_device
)
{
vdbg_printk
(
TPACPI_DBG_EXIT
,
vdbg_printk
(
TPACPI_DBG_EXIT
|
TPACPI_DBG_BRGHT
,
"calling backlight_device_unregister()
\n
"
);
"calling backlight_device_unregister()
\n
"
);
backlight_device_unregister
(
ibm_backlight_device
);
backlight_device_unregister
(
ibm_backlight_device
);
}
}
tpacpi_brightness_checkpoint_nvram
();
}
}
static
int
brightness_read
(
char
*
p
)
static
int
brightness_read
(
char
*
p
)
...
@@ -5628,6 +5928,9 @@ static int brightness_write(char *buf)
...
@@ -5628,6 +5928,9 @@ static int brightness_write(char *buf)
return
-
EINVAL
;
return
-
EINVAL
;
}
}
tpacpi_disclose_usertask
(
"procfs brightness"
,
"set level to %d
\n
"
,
level
);
/*
/*
* Now we know what the final level should be, so we try to set it.
* Now we know what the final level should be, so we try to set it.
* Doing it this way makes the syscall restartable in case of EINTR
* Doing it this way makes the syscall restartable in case of EINTR
...
@@ -5641,6 +5944,8 @@ static struct ibm_struct brightness_driver_data = {
...
@@ -5641,6 +5944,8 @@ static struct ibm_struct brightness_driver_data = {
.
read
=
brightness_read
,
.
read
=
brightness_read
,
.
write
=
brightness_write
,
.
write
=
brightness_write
,
.
exit
=
brightness_exit
,
.
exit
=
brightness_exit
,
.
suspend
=
brightness_suspend
,
.
shutdown
=
brightness_shutdown
,
};
};
/*************************************************************************
/*************************************************************************
...
@@ -6086,6 +6391,9 @@ static int fan_set_level(int level)
...
@@ -6086,6 +6391,9 @@ static int fan_set_level(int level)
default:
default:
return
-
ENXIO
;
return
-
ENXIO
;
}
}
vdbg_printk
(
TPACPI_DBG_FAN
,
"fan control: set fan control register to 0x%02x
\n
"
,
level
);
return
0
;
return
0
;
}
}
...
@@ -6163,6 +6471,11 @@ static int fan_set_enable(void)
...
@@ -6163,6 +6471,11 @@ static int fan_set_enable(void)
}
}
mutex_unlock
(
&
fan_mutex
);
mutex_unlock
(
&
fan_mutex
);
if
(
!
rc
)
vdbg_printk
(
TPACPI_DBG_FAN
,
"fan control: set fan control register to 0x%02x
\n
"
,
s
);
return
rc
;
return
rc
;
}
}
...
@@ -6199,6 +6512,9 @@ static int fan_set_disable(void)
...
@@ -6199,6 +6512,9 @@ static int fan_set_disable(void)
rc
=
-
ENXIO
;
rc
=
-
ENXIO
;
}
}
if
(
!
rc
)
vdbg_printk
(
TPACPI_DBG_FAN
,
"fan control: set fan control register to 0
\n
"
);
mutex_unlock
(
&
fan_mutex
);
mutex_unlock
(
&
fan_mutex
);
return
rc
;
return
rc
;
...
@@ -6327,6 +6643,9 @@ static ssize_t fan_pwm1_enable_store(struct device *dev,
...
@@ -6327,6 +6643,9 @@ static ssize_t fan_pwm1_enable_store(struct device *dev,
if
(
parse_strtoul
(
buf
,
2
,
&
t
))
if
(
parse_strtoul
(
buf
,
2
,
&
t
))
return
-
EINVAL
;
return
-
EINVAL
;
tpacpi_disclose_usertask
(
"hwmon pwm1_enable"
,
"set fan mode to %lu
\n
"
,
t
);
switch
(
t
)
{
switch
(
t
)
{
case
0
:
case
0
:
level
=
TP_EC_FAN_FULLSPEED
;
level
=
TP_EC_FAN_FULLSPEED
;
...
@@ -6392,6 +6711,9 @@ static ssize_t fan_pwm1_store(struct device *dev,
...
@@ -6392,6 +6711,9 @@ static ssize_t fan_pwm1_store(struct device *dev,
if
(
parse_strtoul
(
buf
,
255
,
&
s
))
if
(
parse_strtoul
(
buf
,
255
,
&
s
))
return
-
EINVAL
;
return
-
EINVAL
;
tpacpi_disclose_usertask
(
"hwmon pwm1"
,
"set fan speed to %lu
\n
"
,
s
);
/* scale down from 0-255 to 0-7 */
/* scale down from 0-255 to 0-7 */
newlevel
=
(
s
>>
5
)
&
0x07
;
newlevel
=
(
s
>>
5
)
&
0x07
;
...
@@ -6458,6 +6780,8 @@ static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
...
@@ -6458,6 +6780,8 @@ static ssize_t fan_fan_watchdog_store(struct device_driver *drv,
fan_watchdog_maxinterval
=
t
;
fan_watchdog_maxinterval
=
t
;
fan_watchdog_reset
();
fan_watchdog_reset
();
tpacpi_disclose_usertask
(
"fan_watchdog"
,
"set to %lu
\n
"
,
t
);
return
count
;
return
count
;
}
}
...
@@ -6479,7 +6803,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
...
@@ -6479,7 +6803,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
{
{
int
rc
;
int
rc
;
vdbg_printk
(
TPACPI_DBG_INIT
,
"initializing fan subdriver
\n
"
);
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_FAN
,
"initializing fan subdriver
\n
"
);
mutex_init
(
&
fan_mutex
);
mutex_init
(
&
fan_mutex
);
fan_status_access_mode
=
TPACPI_FAN_NONE
;
fan_status_access_mode
=
TPACPI_FAN_NONE
;
...
@@ -6538,7 +6863,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
...
@@ -6538,7 +6863,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
}
}
}
}
vdbg_printk
(
TPACPI_DBG_INIT
,
"fan is %s, modes %d, %d
\n
"
,
vdbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_FAN
,
"fan is %s, modes %d, %d
\n
"
,
str_supported
(
fan_status_access_mode
!=
TPACPI_FAN_NONE
||
str_supported
(
fan_status_access_mode
!=
TPACPI_FAN_NONE
||
fan_control_access_mode
!=
TPACPI_FAN_WR_NONE
),
fan_control_access_mode
!=
TPACPI_FAN_WR_NONE
),
fan_status_access_mode
,
fan_control_access_mode
);
fan_status_access_mode
,
fan_control_access_mode
);
...
@@ -6547,7 +6873,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
...
@@ -6547,7 +6873,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
if
(
!
fan_control_allowed
)
{
if
(
!
fan_control_allowed
)
{
fan_control_access_mode
=
TPACPI_FAN_WR_NONE
;
fan_control_access_mode
=
TPACPI_FAN_WR_NONE
;
fan_control_commands
=
0
;
fan_control_commands
=
0
;
dbg_printk
(
TPACPI_DBG_INIT
,
dbg_printk
(
TPACPI_DBG_INIT
|
TPACPI_DBG_FAN
,
"fan control features disabled by parameter
\n
"
);
"fan control features disabled by parameter
\n
"
);
}
}
...
@@ -6576,7 +6902,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
...
@@ -6576,7 +6902,7 @@ static int __init fan_init(struct ibm_init_struct *iibm)
static
void
fan_exit
(
void
)
static
void
fan_exit
(
void
)
{
{
vdbg_printk
(
TPACPI_DBG_EXIT
,
vdbg_printk
(
TPACPI_DBG_EXIT
|
TPACPI_DBG_FAN
,
"cancelling any pending fan watchdog tasks
\n
"
);
"cancelling any pending fan watchdog tasks
\n
"
);
/* FIXME: can we really do this unconditionally? */
/* FIXME: can we really do this unconditionally? */
...
@@ -6757,6 +7083,9 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
...
@@ -6757,6 +7083,9 @@ static int fan_write_cmd_level(const char *cmd, int *rc)
if
(
*
rc
==
-
ENXIO
)
if
(
*
rc
==
-
ENXIO
)
printk
(
TPACPI_ERR
"level command accepted for unsupported "
printk
(
TPACPI_ERR
"level command accepted for unsupported "
"access mode %d"
,
fan_control_access_mode
);
"access mode %d"
,
fan_control_access_mode
);
else
if
(
!*
rc
)
tpacpi_disclose_usertask
(
"procfs fan"
,
"set level to %d
\n
"
,
level
);
return
1
;
return
1
;
}
}
...
@@ -6770,6 +7099,8 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
...
@@ -6770,6 +7099,8 @@ static int fan_write_cmd_enable(const char *cmd, int *rc)
if
(
*
rc
==
-
ENXIO
)
if
(
*
rc
==
-
ENXIO
)
printk
(
TPACPI_ERR
"enable command accepted for unsupported "
printk
(
TPACPI_ERR
"enable command accepted for unsupported "
"access mode %d"
,
fan_control_access_mode
);
"access mode %d"
,
fan_control_access_mode
);
else
if
(
!*
rc
)
tpacpi_disclose_usertask
(
"procfs fan"
,
"enable
\n
"
);
return
1
;
return
1
;
}
}
...
@@ -6783,6 +7114,8 @@ static int fan_write_cmd_disable(const char *cmd, int *rc)
...
@@ -6783,6 +7114,8 @@ static int fan_write_cmd_disable(const char *cmd, int *rc)
if
(
*
rc
==
-
ENXIO
)
if
(
*
rc
==
-
ENXIO
)
printk
(
TPACPI_ERR
"disable command accepted for unsupported "
printk
(
TPACPI_ERR
"disable command accepted for unsupported "
"access mode %d"
,
fan_control_access_mode
);
"access mode %d"
,
fan_control_access_mode
);
else
if
(
!*
rc
)
tpacpi_disclose_usertask
(
"procfs fan"
,
"disable
\n
"
);
return
1
;
return
1
;
}
}
...
@@ -6801,6 +7134,9 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
...
@@ -6801,6 +7134,9 @@ static int fan_write_cmd_speed(const char *cmd, int *rc)
if
(
*
rc
==
-
ENXIO
)
if
(
*
rc
==
-
ENXIO
)
printk
(
TPACPI_ERR
"speed command accepted for unsupported "
printk
(
TPACPI_ERR
"speed command accepted for unsupported "
"access mode %d"
,
fan_control_access_mode
);
"access mode %d"
,
fan_control_access_mode
);
else
if
(
!*
rc
)
tpacpi_disclose_usertask
(
"procfs fan"
,
"set speed to %d
\n
"
,
speed
);
return
1
;
return
1
;
}
}
...
@@ -6814,8 +7150,12 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc)
...
@@ -6814,8 +7150,12 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc)
if
(
interval
<
0
||
interval
>
120
)
if
(
interval
<
0
||
interval
>
120
)
*
rc
=
-
EINVAL
;
*
rc
=
-
EINVAL
;
else
else
{
fan_watchdog_maxinterval
=
interval
;
fan_watchdog_maxinterval
=
interval
;
tpacpi_disclose_usertask
(
"procfs fan"
,
"set watchdog timer to %d
\n
"
,
interval
);
}
return
1
;
return
1
;
}
}
...
@@ -7244,10 +7584,10 @@ module_param_named(fan_control, fan_control_allowed, bool, 0);
...
@@ -7244,10 +7584,10 @@ module_param_named(fan_control, fan_control_allowed, bool, 0);
MODULE_PARM_DESC
(
fan_control
,
MODULE_PARM_DESC
(
fan_control
,
"Enables setting fan parameters features when true"
);
"Enables setting fan parameters features when true"
);
module_param_named
(
brightness_mode
,
brightness_mode
,
int
,
0
);
module_param_named
(
brightness_mode
,
brightness_mode
,
u
int
,
0
);
MODULE_PARM_DESC
(
brightness_mode
,
MODULE_PARM_DESC
(
brightness_mode
,
"Selects brightness control strategy: "
"Selects brightness control strategy: "
"0=auto, 1=EC, 2=
CMOS, 3=both
"
);
"0=auto, 1=EC, 2=
UCMS, 3=EC+NVRAM
"
);
module_param
(
brightness_enable
,
uint
,
0
);
module_param
(
brightness_enable
,
uint
,
0
);
MODULE_PARM_DESC
(
brightness_enable
,
MODULE_PARM_DESC
(
brightness_enable
,
...
@@ -7517,9 +7857,6 @@ static int __init thinkpad_acpi_module_init(void)
...
@@ -7517,9 +7857,6 @@ static int __init thinkpad_acpi_module_init(void)
return
0
;
return
0
;
}
}
/* Please remove this in year 2009 */
MODULE_ALIAS
(
"ibm_acpi"
);
MODULE_ALIAS
(
TPACPI_DRVR_SHORTNAME
);
MODULE_ALIAS
(
TPACPI_DRVR_SHORTNAME
);
/*
/*
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment