Merge branch 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'release' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (77 commits) ACPI: Populate /sys/firmware/acpi/tables/ ACPI: create CONFIG_ACPI_DEBUG_FUNC_TRACE ACPI: update ACPI proc I/F removal schedule ACPI: update feature-removal-schedule.txt, /sys/firmware/acpi/namespace is gone ACPI: export ACPI events via acpi_mc_group multicast group ACPI: fix empty macros found by -Wextra ACPI: drivers/acpi/pci_link.c: lower printk severity sony-laptop: Fix event reading in sony-laptop sony-laptop: Add Vaio FE to the special init sequence sony-laptop: Make the driver use MSC_SCAN and a setkeycode and getkeycode key table. sony-laptop: Invoke _INI for SNC devices that provide it sony-laptop: Add support for recent Vaios Fn keys (C series for now) sony-laptop: map wireless switch events to KEY_WLAN sony-laptop: add new SNC handlers ACPI: thinkpad-acpi: add locking to brightness subdriver ACPI: thinkpad-acpi: bump up version to 0.15 ACPI: thinkpad-acpi: make EC-based thermal readings non-experimental ACPI: thinkpad-acpi: make sure DSDT TMPx readings don't return +128 ACPI: thinkpad-acpi: react to Lenovo ThinkPad differences in hot key ACPI: thinkpad-acpi: allow use of CMOS NVRAM for brightness control ...
This commit is contained in:
commit
39804b20f6
@ -180,24 +180,11 @@ Who: Adrian Bunk <bunk@stusta.de>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: /sys/firmware/acpi/namespace
|
||||
When: 2.6.21
|
||||
Why: The ACPI namespace is effectively the symbol list for
|
||||
the BIOS. The device names are completely arbitrary
|
||||
and have no place being exposed to user-space.
|
||||
|
||||
For those interested in the BIOS ACPI namespace,
|
||||
the BIOS can be extracted and disassembled with acpidump
|
||||
and iasl as documented in the pmtools package here:
|
||||
http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils
|
||||
Who: Len Brown <len.brown@intel.com>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: ACPI procfs interface
|
||||
When: July 2007
|
||||
Why: After ACPI sysfs conversion, ACPI attributes will be duplicated
|
||||
in sysfs and the ACPI procfs interface should be removed.
|
||||
When: July 2008
|
||||
Why: ACPI sysfs conversion should be finished by January 2008.
|
||||
ACPI procfs interface will be removed in July 2008 so that
|
||||
there is enough time for the user space to catch up.
|
||||
Who: Zhang Rui <rui.zhang@intel.com>
|
||||
|
||||
---------------------------
|
||||
|
@ -1,11 +1,11 @@
|
||||
ThinkPad ACPI Extras Driver
|
||||
|
||||
Version 0.14
|
||||
April 21st, 2007
|
||||
Version 0.15
|
||||
July 1st, 2007
|
||||
|
||||
Borislav Deianov <borislav@users.sf.net>
|
||||
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
|
||||
http://ibm-acpi.sf.net/
|
||||
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
|
||||
http://ibm-acpi.sf.net/
|
||||
|
||||
|
||||
This is a Linux driver for the IBM and Lenovo ThinkPad laptops. It
|
||||
@ -134,54 +134,68 @@ end of this document. Changes to the sysfs interface done by the kernel
|
||||
subsystems are not documented here, nor are they tracked by this
|
||||
attribute.
|
||||
|
||||
Changes to the thinkpad-acpi sysfs interface are only considered
|
||||
non-experimental when they are submitted to Linux mainline, at which
|
||||
point the changes in this interface are documented and interface_version
|
||||
may be updated. If you are using any thinkpad-acpi features not yet
|
||||
sent to mainline for merging, you do so on your own risk: these features
|
||||
may disappear, or be implemented in a different and incompatible way by
|
||||
the time they are merged in Linux mainline.
|
||||
|
||||
Changes that are backwards-compatible by nature (e.g. the addition of
|
||||
attributes that do not change the way the other attributes work) do not
|
||||
always warrant an update of interface_version. Therefore, one must
|
||||
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
|
||||
feature is not available in sysfs).
|
||||
|
||||
Hot keys
|
||||
--------
|
||||
|
||||
procfs: /proc/acpi/ibm/hotkey
|
||||
sysfs device attribute: hotkey_*
|
||||
|
||||
Without this driver, only the Fn-F4 key (sleep button) generates an
|
||||
ACPI event. With the driver loaded, the hotkey feature enabled and the
|
||||
mask set (see below), the various hot keys generate ACPI events in the
|
||||
In a ThinkPad, the ACPI HKEY handler is responsible for comunicating
|
||||
some important events and also keyboard hot key presses to the operating
|
||||
system. Enabling the hotkey functionality of thinkpad-acpi signals the
|
||||
firmware that such a driver is present, and modifies how the ThinkPad
|
||||
firmware will behave in many situations.
|
||||
|
||||
When the hotkey feature is enabled and the hot key mask is set (see
|
||||
below), the various hot keys either generate ACPI events in the
|
||||
following format:
|
||||
|
||||
ibm/hotkey HKEY 00000080 0000xxxx
|
||||
|
||||
The last four digits vary depending on the key combination pressed.
|
||||
All labeled Fn-Fx key combinations generate distinct events. In
|
||||
addition, the lid microswitch and some docking station buttons may
|
||||
also generate such events.
|
||||
or events over the input layer. The input layer support accepts the
|
||||
standard IOCTLs to remap the keycodes assigned to each hotkey.
|
||||
|
||||
The bit mask allows some control over which hot keys generate ACPI
|
||||
events. Not all bits in the mask can be modified. Not all bits that
|
||||
can be modified do anything. Not all hot keys can be individually
|
||||
controlled by the mask. Most recent ThinkPad models honor the
|
||||
following bits (assuming the hot keys feature has been enabled):
|
||||
When the input device is open, the driver will suppress any ACPI hot key
|
||||
events that get translated into a meaningful input layer event, in order
|
||||
to avoid sending duplicate events to userspace. Hot keys that are
|
||||
mapped to KEY_RESERVED in the keymap are not translated, and will always
|
||||
generate an ACPI ibm/hotkey HKEY event, and no input layer events.
|
||||
|
||||
key bit behavior when set behavior when unset
|
||||
The hot key bit mask allows some control over which hot keys generate
|
||||
events. If a key is "masked" (bit set to 0 in the mask), the firmware
|
||||
will handle it. If it is "unmasked", it signals the firmware that
|
||||
thinkpad-acpi would prefer to handle it, if the firmware would be so
|
||||
kind to allow it (and it often doesn't!).
|
||||
|
||||
Fn-F3 always generates ACPI event
|
||||
Fn-F4 always generates ACPI event
|
||||
Fn-F5 0010 generate ACPI event enable/disable Bluetooth
|
||||
Fn-F7 0040 generate ACPI event switch LCD and external display
|
||||
Fn-F8 0080 generate ACPI event expand screen or none
|
||||
Fn-F9 0100 generate ACPI event none
|
||||
Fn-F12 always generates ACPI event
|
||||
Not all bits in the mask can be modified. Not all bits that can be
|
||||
modified do anything. Not all hot keys can be individually controlled
|
||||
by the mask. Some models do not support the mask at all, and in those
|
||||
models, hot keys cannot be controlled individually. The behaviour of
|
||||
the mask is, therefore, higly dependent on the ThinkPad model.
|
||||
|
||||
Some models do not support all of the above. For example, the T30 does
|
||||
not support Fn-F5 and Fn-F9. Other models do not support the mask at
|
||||
all. On those models, hot keys cannot be controlled individually.
|
||||
Note that unmasking some keys prevents their default behavior. For
|
||||
example, if Fn+F5 is unmasked, that key will no longer enable/disable
|
||||
Bluetooth by itself.
|
||||
|
||||
Note that enabling ACPI events for some keys prevents their default
|
||||
behavior. For example, if events for Fn-F5 are enabled, that key will
|
||||
no longer enable/disable Bluetooth by itself. This can still be done
|
||||
from an acpid handler for the ibm/hotkey event.
|
||||
|
||||
Note also that not all Fn key combinations are supported through
|
||||
ACPI. For example, on the X40, the brightness, volume and "Access IBM"
|
||||
buttons do not generate ACPI events even with this driver. They *can*
|
||||
be used through the "ThinkPad Buttons" utility, see
|
||||
http://www.nongnu.org/tpb/
|
||||
Note also that not all Fn key combinations are supported through ACPI.
|
||||
For example, on the X40, the brightness, volume and "Access IBM" buttons
|
||||
do not generate ACPI events even with this driver. They *can* be used
|
||||
through the "ThinkPad Buttons" utility, see http://www.nongnu.org/tpb/
|
||||
|
||||
procfs notes:
|
||||
|
||||
@ -189,9 +203,9 @@ 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 0xffff > /proc/acpi/ibm/hotkey -- enable all possible hot keys
|
||||
echo 0x0000 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
|
||||
... any other 4-hex-digit mask ...
|
||||
echo 0xffffffff > /proc/acpi/ibm/hotkey -- enable all hot keys
|
||||
echo 0 > /proc/acpi/ibm/hotkey -- disable all possible hot keys
|
||||
... any other 8-hex-digit mask ...
|
||||
echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
|
||||
|
||||
sysfs notes:
|
||||
@ -202,7 +216,7 @@ sysfs notes:
|
||||
key feature status will be restored to this value.
|
||||
|
||||
0: hot keys were disabled
|
||||
1: hot keys were enabled
|
||||
1: hot keys were enabled (unusual)
|
||||
|
||||
hotkey_bios_mask:
|
||||
Returns the hot keys mask when thinkpad-acpi was loaded.
|
||||
@ -217,9 +231,182 @@ sysfs notes:
|
||||
1: enables the hot keys feature / feature enabled
|
||||
|
||||
hotkey_mask:
|
||||
bit mask to enable ACPI event generation for each hot
|
||||
key (see above). Returns the current status of the hot
|
||||
keys mask, and allows one to modify it.
|
||||
bit mask to enable driver-handling and ACPI event
|
||||
generation for each hot key (see above). Returns the
|
||||
current status of the hot keys mask, and allows one to
|
||||
modify it.
|
||||
|
||||
hotkey_all_mask:
|
||||
bit mask that should enable event reporting for all
|
||||
supported hot keys, when echoed to hotkey_mask above.
|
||||
Unless you know which events need to be handled
|
||||
passively (because the firmware *will* handle them
|
||||
anyway), do *not* use hotkey_all_mask. Use
|
||||
hotkey_recommended_mask, instead. You have been warned.
|
||||
|
||||
hotkey_recommended_mask:
|
||||
bit mask that should enable event reporting for all
|
||||
supported hot keys, except those which are always
|
||||
handled by the firmware anyway. Echo it to
|
||||
hotkey_mask above, to use.
|
||||
|
||||
hotkey_radio_sw:
|
||||
if the ThinkPad has a hardware radio switch, this
|
||||
attribute will read 0 if the switch is in the "radios
|
||||
disabled" postition, and 1 if the switch is in the
|
||||
"radios enabled" position.
|
||||
|
||||
input layer notes:
|
||||
|
||||
A Hot key is mapped to a single input layer EV_KEY event, possibly
|
||||
followed by an EV_MSC MSC_SCAN event that shall contain that key's scan
|
||||
code. An EV_SYN event will always be generated to mark the end of the
|
||||
event block.
|
||||
|
||||
Do not use the EV_MSC MSC_SCAN events to process keys. They are to be
|
||||
used as a helper to remap keys, only. They are particularly useful when
|
||||
remapping KEY_UNKNOWN keys.
|
||||
|
||||
The events are available in an input device, with the following id:
|
||||
|
||||
Bus: BUS_HOST
|
||||
vendor: 0x1014 (PCI_VENDOR_ID_IBM) or
|
||||
0x17aa (PCI_VENDOR_ID_LENOVO)
|
||||
product: 0x5054 ("TP")
|
||||
version: 0x4101
|
||||
|
||||
The version will have its LSB incremented if the keymap changes in a
|
||||
backwards-compatible way. The MSB shall always be 0x41 for this input
|
||||
device. If the MSB is not 0x41, do not use the device as described in
|
||||
this section, as it is either something else (e.g. another input device
|
||||
exported by a thinkpad driver, such as HDAPS) or its functionality has
|
||||
been changed in a non-backwards compatible way.
|
||||
|
||||
Adding other event types for other functionalities shall be considered a
|
||||
backwards-compatible change for this input device.
|
||||
|
||||
Thinkpad-acpi Hot Key event map (version 0x4101):
|
||||
|
||||
ACPI Scan
|
||||
event code Key Notes
|
||||
|
||||
0x1001 0x00 FN+F1 -
|
||||
0x1002 0x01 FN+F2 IBM: battery (rare)
|
||||
Lenovo: Screen lock
|
||||
|
||||
0x1003 0x02 FN+F3 Many IBM models always report
|
||||
this hot key, even with hot keys
|
||||
disabled or with Fn+F3 masked
|
||||
off
|
||||
IBM: screen lock
|
||||
Lenovo: battery
|
||||
|
||||
0x1004 0x03 FN+F4 Sleep button (ACPI sleep button
|
||||
semanthics, i.e. sleep-to-RAM).
|
||||
It is always generate some kind
|
||||
of event, either the hot key
|
||||
event or a ACPI sleep button
|
||||
event. The firmware may
|
||||
refuse to generate further FN+F4
|
||||
key presses until a S3 or S4 ACPI
|
||||
sleep cycle is performed or some
|
||||
time passes.
|
||||
|
||||
0x1005 0x04 FN+F5 Radio. Enables/disables
|
||||
the internal BlueTooth hardware
|
||||
and W-WAN card if left in control
|
||||
of the firmware. Does not affect
|
||||
the WLAN card.
|
||||
Should be used to turn on/off all
|
||||
radios (bluetooth+W-WAN+WLAN),
|
||||
really.
|
||||
|
||||
0x1006 0x05 FN+F6 -
|
||||
|
||||
0x1007 0x06 FN+F7 Video output cycle.
|
||||
Do you feel lucky today?
|
||||
|
||||
0x1008 0x07 FN+F8 IBM: toggle screen expand
|
||||
Lenovo: configure ultranav
|
||||
|
||||
0x1009 0x08 FN+F9 -
|
||||
.. .. ..
|
||||
0x100B 0x0A FN+F11 -
|
||||
|
||||
0x100C 0x0B FN+F12 Sleep to disk. You are always
|
||||
supposed to handle it yourself,
|
||||
either through the ACPI event,
|
||||
or through a hotkey event.
|
||||
The firmware may refuse to
|
||||
generate further FN+F4 key
|
||||
press events until a S3 or S4
|
||||
ACPI sleep cycle is performed,
|
||||
or some time passes.
|
||||
|
||||
0x100D 0x0C FN+BACKSPACE -
|
||||
0x100E 0x0D FN+INSERT -
|
||||
0x100F 0x0E FN+DELETE -
|
||||
|
||||
0x1010 0x0F FN+HOME Brightness up. This key is
|
||||
always handled by the firmware
|
||||
in IBM ThinkPads, even when
|
||||
unmasked. Just leave it alone.
|
||||
For Lenovo ThinkPads with a new
|
||||
BIOS, it has to be handled either
|
||||
by the ACPI OSI, or by userspace.
|
||||
0x1011 0x10 FN+END Brightness down. See brightness
|
||||
up for details.
|
||||
|
||||
0x1012 0x11 FN+PGUP Thinklight toggle. This key is
|
||||
always handled by the firmware,
|
||||
even when unmasked.
|
||||
|
||||
0x1013 0x12 FN+PGDOWN -
|
||||
|
||||
0x1014 0x13 FN+SPACE Zoom key
|
||||
|
||||
0x1015 0x14 VOLUME UP Internal mixer volume up. This
|
||||
key is always handled by the
|
||||
firmware, even when unmasked.
|
||||
NOTE: Lenovo seems to be changing
|
||||
this.
|
||||
0x1016 0x15 VOLUME DOWN Internal mixer volume up. This
|
||||
key is always handled by the
|
||||
firmware, even when unmasked.
|
||||
NOTE: Lenovo seems to be changing
|
||||
this.
|
||||
0x1017 0x16 MUTE Mute internal mixer. This
|
||||
key is always handled by the
|
||||
firmware, even when unmasked.
|
||||
|
||||
0x1018 0x17 THINKPAD Thinkpad/Access IBM/Lenovo key
|
||||
|
||||
0x1019 0x18 unknown
|
||||
.. .. ..
|
||||
0x1020 0x1F unknown
|
||||
|
||||
The ThinkPad firmware does not allow one to differentiate when most hot
|
||||
keys are pressed or released (either that, or we don't know how to, yet).
|
||||
For these keys, the driver generates a set of events for a key press and
|
||||
immediately issues the same set of events for a key release. It is
|
||||
unknown by the driver if the ThinkPad firmware triggered these events on
|
||||
hot key press or release, but the firmware will do it for either one, not
|
||||
both.
|
||||
|
||||
If a key is mapped to KEY_RESERVED, it generates no input events at all,
|
||||
and it may generate a legacy thinkpad-acpi ACPI hotkey event.
|
||||
|
||||
If a key is mapped to KEY_UNKNOWN, it generates an input event that
|
||||
includes an scan code, and it may also generate a legacy thinkpad-acpi
|
||||
ACPI hotkey event.
|
||||
|
||||
If a key is mapped to anything else, it will only generate legacy
|
||||
thinkpad-acpi ACPI hotkey events if nobody has opened the input device.
|
||||
|
||||
Non hot-key ACPI HKEY event map:
|
||||
0x5001 Lid closed
|
||||
0x5002 Lid opened
|
||||
0x7000 Radio Switch may have changed state
|
||||
|
||||
|
||||
Bluetooth
|
||||
@ -437,27 +624,34 @@ CMOS control
|
||||
procfs: /proc/acpi/ibm/cmos
|
||||
sysfs device attribute: cmos_command
|
||||
|
||||
This feature is used internally by the ACPI firmware to control the
|
||||
ThinkLight on most newer ThinkPad models. It may also control LCD
|
||||
brightness, sounds volume and more, but only on some models.
|
||||
This feature is mostly used internally by the ACPI firmware to keep the legacy
|
||||
CMOS NVRAM bits in sync with the current machine state, and to record this
|
||||
state so that the ThinkPad will retain such settings across reboots.
|
||||
|
||||
Some of these commands actually perform actions in some ThinkPad models, but
|
||||
this is expected to disappear more and more in newer models. As an example, in
|
||||
a T43 and in a X40, commands 12 and 13 still control the ThinkLight state for
|
||||
real, but commands 0 to 2 don't control the mixer anymore (they have been
|
||||
phased out) and just update the NVRAM.
|
||||
|
||||
The range of valid cmos command numbers is 0 to 21, but not all have an
|
||||
effect and the behavior varies from model to model. Here is the behavior
|
||||
on the X40 (tpb is the ThinkPad Buttons utility):
|
||||
|
||||
0 - no effect but tpb reports "Volume down"
|
||||
1 - no effect but tpb reports "Volume up"
|
||||
2 - no effect but tpb reports "Mute on"
|
||||
3 - simulate pressing the "Access IBM" button
|
||||
4 - LCD brightness up
|
||||
5 - LCD brightness down
|
||||
11 - toggle screen expansion
|
||||
12 - ThinkLight on
|
||||
13 - ThinkLight off
|
||||
14 - no effect but tpb reports ThinkLight status change
|
||||
0 - Related to "Volume down" key press
|
||||
1 - Related to "Volume up" key press
|
||||
2 - Related to "Mute on" key press
|
||||
3 - Related to "Access IBM" key press
|
||||
4 - Related to "LCD brightness up" key pess
|
||||
5 - Related to "LCD brightness down" key press
|
||||
11 - Related to "toggle screen expansion" key press/function
|
||||
12 - Related to "ThinkLight on"
|
||||
13 - Related to "ThinkLight off"
|
||||
14 - Related to "ThinkLight" key press (toggle thinklight)
|
||||
|
||||
The cmos command interface is prone to firmware split-brain problems, as
|
||||
in newer ThinkPads it is just a compatibility layer.
|
||||
in newer ThinkPads it is just a compatibility layer. Do not use it, it is
|
||||
exported just as a debug tool.
|
||||
|
||||
LED control -- /proc/acpi/ibm/led
|
||||
---------------------------------
|
||||
@ -516,23 +710,15 @@ Temperature sensors
|
||||
procfs: /proc/acpi/ibm/thermal
|
||||
sysfs device attributes: (hwmon) temp*_input
|
||||
|
||||
Most ThinkPads include six or more separate temperature sensors but
|
||||
only expose the CPU temperature through the standard ACPI methods.
|
||||
This feature shows readings from up to eight different sensors on older
|
||||
ThinkPads, and it has experimental support for up to sixteen different
|
||||
sensors on newer ThinkPads.
|
||||
|
||||
EXPERIMENTAL: The 16-sensors feature is marked EXPERIMENTAL because the
|
||||
implementation directly accesses hardware registers and may not work as
|
||||
expected. USE WITH CAUTION! To use this feature, you need to supply the
|
||||
experimental=1 parameter when loading the module. When EXPERIMENTAL
|
||||
mode is enabled, reading the first 8 sensors on newer ThinkPads will
|
||||
also use an new experimental thermal sensor access mode.
|
||||
Most ThinkPads include six or more separate temperature sensors but only
|
||||
expose the CPU temperature through the standard ACPI methods. This
|
||||
feature shows readings from up to eight different sensors on older
|
||||
ThinkPads, and up to sixteen different sensors on newer ThinkPads.
|
||||
|
||||
For example, on the X40, a typical output may be:
|
||||
temperatures: 42 42 45 41 36 -128 33 -128
|
||||
|
||||
EXPERIMENTAL: On the T43/p, a typical output may be:
|
||||
On the T43/p, a typical output may be:
|
||||
temperatures: 48 48 36 52 38 -128 31 -128 48 52 48 -128 -128 -128 -128 -128
|
||||
|
||||
The mapping of thermal sensors to physical locations varies depending on
|
||||
@ -562,7 +748,8 @@ http://thinkwiki.org/wiki/Thermal_Sensors#ThinkPad_T43.2C_T43p
|
||||
2: System board, left side (near PCMCIA slot), reported as HDAPS temp
|
||||
3: PCMCIA slot
|
||||
9: MCH (northbridge) to DRAM Bus
|
||||
10: ICH (southbridge), under Mini-PCI card, under touchpad
|
||||
10: Clock-generator, mini-pci card and ICH (southbridge), under Mini-PCI
|
||||
card, under touchpad
|
||||
11: Power regulator, underside of system board, below F2 key
|
||||
|
||||
The A31 has a very atypical layout for the thermal sensors
|
||||
@ -681,6 +868,12 @@ cannot be controlled.
|
||||
The backlight control has eight levels, ranging from 0 to 7. Some of the
|
||||
levels may not be distinct.
|
||||
|
||||
There are two interfaces to the firmware for brightness control, EC and CMOS.
|
||||
To select which one should be used, use the brightness_mode module parameter:
|
||||
brightness_mode=1 selects EC mode, brightness_mode=2 selects CMOS mode,
|
||||
brightness_mode=3 selects both EC and CMOS. The driver tries to autodetect
|
||||
which interface to use.
|
||||
|
||||
Procfs notes:
|
||||
|
||||
The available commands are:
|
||||
@ -976,3 +1169,9 @@ Sysfs interface changelog:
|
||||
|
||||
0x000100: Initial sysfs support, as a single platform driver and
|
||||
device.
|
||||
0x000200: Hot key support for 32 hot keys, and radio slider switch
|
||||
support.
|
||||
0x010000: Hot keys are now handled by default over the input
|
||||
layer, the radio switch generates input event EV_RADIO,
|
||||
and the driver enables hot key handling by default in
|
||||
the firmware.
|
||||
|
@ -225,15 +225,15 @@ T: git kernel.org:/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6.git
|
||||
S: Supported
|
||||
|
||||
ACPI BATTERY DRIVERS
|
||||
P: Vladimir P. Lebedev
|
||||
M: vladimir.p.lebedev@intel.com
|
||||
P: Alexey Starikovskiy
|
||||
M: astarikovskiy@suse.de
|
||||
L: linux-acpi@vger.kernel.org
|
||||
W: http://acpi.sourceforge.net/
|
||||
S: Supported
|
||||
|
||||
ACPI EC DRIVER
|
||||
P: Alexey Starikovskiy
|
||||
M: alexey.y.starikovskiy@linux.intel.com
|
||||
M: astarikovskiy@suse.de
|
||||
L: linux-acpi@vger.kernel.org
|
||||
W: http://acpi.sourceforge.net/
|
||||
S: Supported
|
||||
|
@ -984,14 +984,6 @@ static struct dmi_system_id __initdata acpi_dmi_table[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = force_acpi_ht,
|
||||
.ident = "DELL GX240",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.callback = force_acpi_ht,
|
||||
.ident = "HP VISUALIZE NT Workstation",
|
||||
|
@ -665,8 +665,8 @@ static int acpi_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
data->max_freq = perf->states[0].core_frequency * 1000;
|
||||
/* table init */
|
||||
for (i=0; i<perf->state_count; i++) {
|
||||
if (i>0 && perf->states[i].core_frequency ==
|
||||
perf->states[i-1].core_frequency)
|
||||
if (i>0 && perf->states[i].core_frequency >=
|
||||
data->freq_table[valid_states-1].frequency / 1000)
|
||||
continue;
|
||||
|
||||
data->freq_table[valid_states].index = i;
|
||||
|
@ -2,16 +2,12 @@
|
||||
# ACPI Configuration
|
||||
#
|
||||
|
||||
menu "ACPI (Advanced Configuration and Power Interface) Support"
|
||||
menuconfig ACPI
|
||||
bool "ACPI Support (Advanced Configuration and Power Interface) Support"
|
||||
depends on !X86_NUMAQ
|
||||
depends on !X86_VISWS
|
||||
depends on !IA64_HP_SIM
|
||||
depends on IA64 || X86
|
||||
depends on PM
|
||||
|
||||
config ACPI
|
||||
bool "ACPI Support"
|
||||
depends on IA64 || X86
|
||||
depends on PCI
|
||||
depends on PM
|
||||
select PNP
|
||||
@ -49,7 +45,6 @@ if ACPI
|
||||
config ACPI_SLEEP
|
||||
bool "Sleep States"
|
||||
depends on X86 && (!SMP || SUSPEND_SMP)
|
||||
depends on PM
|
||||
default y
|
||||
---help---
|
||||
This option adds support for ACPI suspend states.
|
||||
@ -82,7 +77,6 @@ config ACPI_SLEEP_PROC_SLEEP
|
||||
|
||||
config ACPI_PROCFS
|
||||
bool "Procfs interface (deprecated)"
|
||||
depends on ACPI
|
||||
default y
|
||||
---help---
|
||||
The Procfs interface for ACPI is made optional for backward compatibility.
|
||||
@ -124,7 +118,7 @@ config ACPI_BUTTON
|
||||
|
||||
config ACPI_VIDEO
|
||||
tristate "Video"
|
||||
depends on X86 && BACKLIGHT_CLASS_DEVICE
|
||||
depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL
|
||||
help
|
||||
This driver implement the ACPI Extensions For Display Adapters
|
||||
for integrated graphics devices on motherboard, as specified in
|
||||
@ -280,6 +274,14 @@ config ACPI_DEBUG
|
||||
of verbosity. Saying Y enables these statements. This will increase
|
||||
your kernel size by around 50K.
|
||||
|
||||
config ACPI_DEBUG_FUNC_TRACE
|
||||
bool "Additionally enable ACPI function tracing"
|
||||
default n
|
||||
depends on ACPI_DEBUG
|
||||
help
|
||||
ACPI Debug Statements slow down ACPI processing. Function trace
|
||||
is about half of the penalty and is rarely useful.
|
||||
|
||||
config ACPI_EC
|
||||
bool
|
||||
default y
|
||||
@ -330,7 +332,6 @@ config ACPI_CONTAINER
|
||||
|
||||
config ACPI_HOTPLUG_MEMORY
|
||||
tristate "Memory Hotplug"
|
||||
depends on ACPI
|
||||
depends on MEMORY_HOTPLUG
|
||||
default n
|
||||
help
|
||||
@ -359,5 +360,3 @@ config ACPI_SBS
|
||||
to today's ACPI "Control Method" battery.
|
||||
|
||||
endif # ACPI
|
||||
|
||||
endmenu
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -288,6 +288,11 @@ static int bay_add(acpi_handle handle, int id)
|
||||
new_bay->pdev = pdev;
|
||||
platform_set_drvdata(pdev, new_bay);
|
||||
|
||||
/*
|
||||
* we want the bay driver to be able to send uevents
|
||||
*/
|
||||
pdev->dev.uevent_suppress = 0;
|
||||
|
||||
if (acpi_bay_add_fs(new_bay)) {
|
||||
platform_device_unregister(new_bay->pdev);
|
||||
goto bay_add_err;
|
||||
@ -328,18 +333,12 @@ static void bay_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct bay *bay_dev = (struct bay *)data;
|
||||
struct device *dev = &bay_dev->pdev->dev;
|
||||
char event_string[12];
|
||||
char *envp[] = { event_string, NULL };
|
||||
|
||||
bay_dprintk(handle, "Bay event");
|
||||
|
||||
switch(event) {
|
||||
case ACPI_NOTIFY_BUS_CHECK:
|
||||
case ACPI_NOTIFY_DEVICE_CHECK:
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Bay: unknown event %d\n", event);
|
||||
}
|
||||
sprintf(event_string, "BAY_EVENT=%d\n", event);
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
|
@ -292,6 +292,10 @@ int acpi_bus_generate_event(struct acpi_device *device, u8 type, int data)
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
if (acpi_bus_generate_genetlink_event(device, type, data))
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Failed to generate an ACPI event via genetlink!\n");
|
||||
|
||||
/* drop event on the floor if no one's listening */
|
||||
if (!event_is_open)
|
||||
return 0;
|
||||
|
@ -40,8 +40,15 @@ MODULE_AUTHOR("Kristen Carlson Accardi");
|
||||
MODULE_DESCRIPTION(ACPI_DOCK_DRIVER_DESCRIPTION);
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
static int immediate_undock = 1;
|
||||
module_param(immediate_undock, bool, 0644);
|
||||
MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
|
||||
"undock immediately when the undock button is pressed, 0 will cause"
|
||||
" the driver to wait for userspace to write the undock sysfs file "
|
||||
" before undocking");
|
||||
|
||||
static struct atomic_notifier_head dock_notifier_list;
|
||||
static struct platform_device dock_device;
|
||||
static struct platform_device *dock_device;
|
||||
static char dock_device_name[] = "dock";
|
||||
|
||||
struct dock_station {
|
||||
@ -63,6 +70,7 @@ struct dock_dependent_device {
|
||||
};
|
||||
|
||||
#define DOCK_DOCKING 0x00000001
|
||||
#define DOCK_UNDOCKING 0x00000002
|
||||
#define DOCK_EVENT 3
|
||||
#define UNDOCK_EVENT 2
|
||||
|
||||
@ -327,12 +335,20 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
||||
|
||||
static void dock_event(struct dock_station *ds, u32 event, int num)
|
||||
{
|
||||
struct device *dev = &dock_device.dev;
|
||||
struct device *dev = &dock_device->dev;
|
||||
char event_string[7];
|
||||
char *envp[] = { event_string, NULL };
|
||||
|
||||
if (num == UNDOCK_EVENT)
|
||||
sprintf(event_string, "UNDOCK");
|
||||
else
|
||||
sprintf(event_string, "DOCK");
|
||||
|
||||
/*
|
||||
* Indicate that the status of the dock station has
|
||||
* changed.
|
||||
*/
|
||||
kobject_uevent(&dev->kobj, KOBJ_CHANGE);
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -380,12 +396,11 @@ static void handle_dock(struct dock_station *ds, int dock)
|
||||
union acpi_object arg;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer name_buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *obj;
|
||||
|
||||
acpi_get_name(ds->handle, ACPI_FULL_PATHNAME, &name_buffer);
|
||||
obj = name_buffer.pointer;
|
||||
|
||||
printk(KERN_INFO PREFIX "%s\n", dock ? "docking" : "undocking");
|
||||
printk(KERN_INFO PREFIX "%s - %s\n",
|
||||
(char *)name_buffer.pointer, dock ? "docking" : "undocking");
|
||||
|
||||
/* _DCK method has one argument */
|
||||
arg_list.count = 1;
|
||||
@ -394,7 +409,8 @@ static void handle_dock(struct dock_station *ds, int dock)
|
||||
arg.integer.value = dock;
|
||||
status = acpi_evaluate_object(ds->handle, "_DCK", &arg_list, &buffer);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_debug("%s: failed to execute _DCK\n", obj->string.pointer);
|
||||
printk(KERN_ERR PREFIX "%s - failed to execute _DCK\n",
|
||||
(char *)name_buffer.pointer);
|
||||
kfree(buffer.pointer);
|
||||
kfree(name_buffer.pointer);
|
||||
}
|
||||
@ -420,6 +436,16 @@ static inline void complete_dock(struct dock_station *ds)
|
||||
ds->last_dock_time = jiffies;
|
||||
}
|
||||
|
||||
static inline void begin_undock(struct dock_station *ds)
|
||||
{
|
||||
ds->flags |= DOCK_UNDOCKING;
|
||||
}
|
||||
|
||||
static inline void complete_undock(struct dock_station *ds)
|
||||
{
|
||||
ds->flags &= ~(DOCK_UNDOCKING);
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_in_progress - see if we are in the middle of handling a dock event
|
||||
* @ds: the dock station
|
||||
@ -550,7 +576,7 @@ static int handle_eject_request(struct dock_station *ds, u32 event)
|
||||
printk(KERN_ERR PREFIX "Unable to undock!\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
complete_undock(ds);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -594,7 +620,11 @@ static void dock_notify(acpi_handle handle, u32 event, void *data)
|
||||
* to the driver who wish to hotplug.
|
||||
*/
|
||||
case ACPI_NOTIFY_EJECT_REQUEST:
|
||||
handle_eject_request(ds, event);
|
||||
begin_undock(ds);
|
||||
if (immediate_undock)
|
||||
handle_eject_request(ds, event);
|
||||
else
|
||||
dock_event(ds, event, UNDOCK_EVENT);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Unknown dock event %d\n", event);
|
||||
@ -652,6 +682,17 @@ static ssize_t show_docked(struct device *dev,
|
||||
}
|
||||
DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
|
||||
|
||||
/*
|
||||
* show_flags - read method for flags file in sysfs
|
||||
*/
|
||||
static ssize_t show_flags(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
|
||||
|
||||
}
|
||||
DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
|
||||
|
||||
/*
|
||||
* write_undock - write method for "undock" file in sysfs
|
||||
*/
|
||||
@ -675,16 +716,15 @@ static ssize_t show_dock_uid(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned long lbuf;
|
||||
acpi_status status = acpi_evaluate_integer(dock_station->handle, "_UID", NULL, &lbuf);
|
||||
if(ACPI_FAILURE(status)) {
|
||||
acpi_status status = acpi_evaluate_integer(dock_station->handle,
|
||||
"_UID", NULL, &lbuf);
|
||||
if (ACPI_FAILURE(status))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
|
||||
}
|
||||
DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dock_add - add a new dock station
|
||||
* @handle: the dock station handle
|
||||
@ -711,33 +751,53 @@ static int dock_add(acpi_handle handle)
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
||||
|
||||
/* initialize platform device stuff */
|
||||
dock_device.name = dock_device_name;
|
||||
ret = platform_device_register(&dock_device);
|
||||
if (ret) {
|
||||
printk(KERN_ERR PREFIX "Error %d registering dock device\n", ret);
|
||||
dock_device =
|
||||
platform_device_register_simple(dock_device_name, 0, NULL, 0);
|
||||
if (IS_ERR(dock_device)) {
|
||||
kfree(dock_station);
|
||||
return ret;
|
||||
dock_station = NULL;
|
||||
return PTR_ERR(dock_device);
|
||||
}
|
||||
ret = device_create_file(&dock_device.dev, &dev_attr_docked);
|
||||
|
||||
/* we want the dock device to send uevents */
|
||||
dock_device->dev.uevent_suppress = 0;
|
||||
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_docked);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
platform_device_unregister(&dock_device);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device.dev, &dev_attr_undock);
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_undock);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
device_remove_file(&dock_device.dev, &dev_attr_docked);
|
||||
platform_device_unregister(&dock_device);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device.dev, &dev_attr_uid);
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_uid);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
platform_device_unregister(&dock_device);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_flags);
|
||||
if (ret) {
|
||||
printk("Error %d adding sysfs file\n", ret);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -750,6 +810,7 @@ static int dock_add(acpi_handle handle)
|
||||
dd = alloc_dock_dependent_device(handle);
|
||||
if (!dd) {
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto dock_add_err_unregister;
|
||||
}
|
||||
@ -773,10 +834,13 @@ static int dock_add(acpi_handle handle)
|
||||
dock_add_err:
|
||||
kfree(dd);
|
||||
dock_add_err_unregister:
|
||||
device_remove_file(&dock_device.dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device.dev, &dev_attr_undock);
|
||||
platform_device_unregister(&dock_device);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_flags);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -804,12 +868,15 @@ static int dock_remove(void)
|
||||
printk(KERN_ERR "Error removing notify handler\n");
|
||||
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(&dock_device.dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device.dev, &dev_attr_undock);
|
||||
platform_device_unregister(&dock_device);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_flags);
|
||||
platform_device_unregister(dock_device);
|
||||
|
||||
/* free dock station memory */
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -34,25 +34,26 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <asm/io.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/actypes.h>
|
||||
|
||||
#define _COMPONENT ACPI_EC_COMPONENT
|
||||
ACPI_MODULE_NAME("ec");
|
||||
#define ACPI_EC_COMPONENT 0x00100000
|
||||
#define ACPI_EC_CLASS "embedded_controller"
|
||||
#define ACPI_EC_HID "PNP0C09"
|
||||
#define ACPI_EC_DEVICE_NAME "Embedded Controller"
|
||||
#define ACPI_EC_FILE_INFO "info"
|
||||
|
||||
#undef PREFIX
|
||||
#define PREFIX "ACPI: EC: "
|
||||
|
||||
/* EC status register */
|
||||
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
|
||||
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
|
||||
#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
|
||||
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
|
||||
|
||||
/* EC commands */
|
||||
enum ec_command {
|
||||
ACPI_EC_COMMAND_READ = 0x80,
|
||||
@ -61,6 +62,7 @@ enum ec_command {
|
||||
ACPI_EC_BURST_DISABLE = 0x83,
|
||||
ACPI_EC_COMMAND_QUERY = 0x84,
|
||||
};
|
||||
|
||||
/* EC events */
|
||||
enum ec_event {
|
||||
ACPI_EC_EVENT_OBF_1 = 1, /* Output buffer full */
|
||||
@ -94,6 +96,16 @@ static struct acpi_driver acpi_ec_driver = {
|
||||
|
||||
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
|
||||
/* External interfaces use first EC only, so remember */
|
||||
typedef int (*acpi_ec_query_func) (void *data);
|
||||
|
||||
struct acpi_ec_query_handler {
|
||||
struct list_head node;
|
||||
acpi_ec_query_func func;
|
||||
acpi_handle handle;
|
||||
void *data;
|
||||
u8 query_bit;
|
||||
};
|
||||
|
||||
static struct acpi_ec {
|
||||
acpi_handle handle;
|
||||
unsigned long gpe;
|
||||
@ -104,6 +116,7 @@ static struct acpi_ec {
|
||||
atomic_t query_pending;
|
||||
atomic_t event_count;
|
||||
wait_queue_head_t wait;
|
||||
struct list_head list;
|
||||
} *boot_ec, *first_ec;
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
@ -245,7 +258,7 @@ static int acpi_ec_transaction(struct acpi_ec *ec, u8 command,
|
||||
|
||||
status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBF_0, 0, 0);
|
||||
if (status) {
|
||||
printk(KERN_DEBUG PREFIX
|
||||
printk(KERN_ERR PREFIX
|
||||
"input buffer is not empty, aborting transaction\n");
|
||||
goto end;
|
||||
}
|
||||
@ -394,21 +407,67 @@ static int acpi_ec_query(struct acpi_ec *ec, u8 * data)
|
||||
/* --------------------------------------------------------------------------
|
||||
Event Management
|
||||
-------------------------------------------------------------------------- */
|
||||
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
|
||||
acpi_handle handle, acpi_ec_query_func func,
|
||||
void *data)
|
||||
{
|
||||
struct acpi_ec_query_handler *handler =
|
||||
kzalloc(sizeof(struct acpi_ec_query_handler), GFP_KERNEL);
|
||||
if (!handler)
|
||||
return -ENOMEM;
|
||||
|
||||
handler->query_bit = query_bit;
|
||||
handler->handle = handle;
|
||||
handler->func = func;
|
||||
handler->data = data;
|
||||
mutex_lock(&ec->lock);
|
||||
list_add_tail(&handler->node, &ec->list);
|
||||
mutex_unlock(&ec->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
|
||||
|
||||
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
|
||||
{
|
||||
struct acpi_ec_query_handler *handler;
|
||||
mutex_lock(&ec->lock);
|
||||
list_for_each_entry(handler, &ec->list, node) {
|
||||
if (query_bit == handler->query_bit) {
|
||||
list_del(&handler->node);
|
||||
kfree(handler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ec->lock);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
|
||||
|
||||
static void acpi_ec_gpe_query(void *ec_cxt)
|
||||
{
|
||||
struct acpi_ec *ec = ec_cxt;
|
||||
u8 value = 0;
|
||||
char object_name[8];
|
||||
struct acpi_ec_query_handler *handler, copy;
|
||||
|
||||
if (!ec || acpi_ec_query(ec, &value))
|
||||
return;
|
||||
|
||||
snprintf(object_name, 8, "_Q%2.2X", value);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s", object_name));
|
||||
|
||||
acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
|
||||
mutex_lock(&ec->lock);
|
||||
list_for_each_entry(handler, &ec->list, node) {
|
||||
if (value == handler->query_bit) {
|
||||
/* have custom handler for this bit */
|
||||
memcpy(©, handler, sizeof(copy));
|
||||
mutex_unlock(&ec->lock);
|
||||
if (copy.func) {
|
||||
copy.func(copy.data);
|
||||
} else if (copy.handle) {
|
||||
acpi_evaluate_object(copy.handle, NULL, NULL, NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&ec->lock);
|
||||
printk(KERN_ERR PREFIX "Handler for query 0x%x is not found!\n", value);
|
||||
}
|
||||
|
||||
static u32 acpi_ec_gpe_handler(void *data)
|
||||
@ -427,8 +486,7 @@ static u32 acpi_ec_gpe_handler(void *data)
|
||||
if ((value & ACPI_EC_FLAG_SCI) && !atomic_read(&ec->query_pending)) {
|
||||
atomic_set(&ec->query_pending, 1);
|
||||
status =
|
||||
acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query,
|
||||
ec);
|
||||
acpi_os_execute(OSL_EC_BURST_HANDLER, acpi_ec_gpe_query, ec);
|
||||
}
|
||||
|
||||
return status == AE_OK ?
|
||||
@ -454,57 +512,35 @@ acpi_ec_space_setup(acpi_handle region_handle,
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_ec_space_handler(u32 function,
|
||||
acpi_physical_address address,
|
||||
u32 bit_width,
|
||||
acpi_integer * value,
|
||||
acpi_ec_space_handler(u32 function, acpi_physical_address address,
|
||||
u32 bits, acpi_integer *value,
|
||||
void *handler_context, void *region_context)
|
||||
{
|
||||
int result = 0;
|
||||
struct acpi_ec *ec = handler_context;
|
||||
u64 temp = *value;
|
||||
acpi_integer f_v = 0;
|
||||
int i = 0;
|
||||
int result = 0, i = 0;
|
||||
u8 temp = 0;
|
||||
|
||||
if ((address > 0xFF) || !value || !handler_context)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
if (bit_width != 8 && acpi_strict) {
|
||||
if (function != ACPI_READ && function != ACPI_WRITE)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
if (bits != 8 && acpi_strict)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
while (bits - i > 0) {
|
||||
if (function == ACPI_READ) {
|
||||
result = acpi_ec_read(ec, address, &temp);
|
||||
(*value) |= ((acpi_integer)temp) << i;
|
||||
} else {
|
||||
temp = 0xff & ((*value) >> i);
|
||||
result = acpi_ec_write(ec, address, temp);
|
||||
}
|
||||
i += 8;
|
||||
++address;
|
||||
}
|
||||
|
||||
next_byte:
|
||||
switch (function) {
|
||||
case ACPI_READ:
|
||||
temp = 0;
|
||||
result = acpi_ec_read(ec, (u8) address, (u8 *) & temp);
|
||||
break;
|
||||
case ACPI_WRITE:
|
||||
result = acpi_ec_write(ec, (u8) address, (u8) temp);
|
||||
break;
|
||||
default:
|
||||
result = -EINVAL;
|
||||
goto out;
|
||||
break;
|
||||
}
|
||||
|
||||
bit_width -= 8;
|
||||
if (bit_width) {
|
||||
if (function == ACPI_READ)
|
||||
f_v |= temp << 8 * i;
|
||||
if (function == ACPI_WRITE)
|
||||
temp >>= 8;
|
||||
i++;
|
||||
address++;
|
||||
goto next_byte;
|
||||
}
|
||||
|
||||
if (function == ACPI_READ) {
|
||||
f_v |= temp << 8 * i;
|
||||
*value = f_v;
|
||||
}
|
||||
|
||||
out:
|
||||
switch (result) {
|
||||
case -EINVAL:
|
||||
return AE_BAD_PARAMETER;
|
||||
@ -597,9 +633,6 @@ static int acpi_ec_remove_fs(struct acpi_device *device)
|
||||
static acpi_status
|
||||
ec_parse_io_ports(struct acpi_resource *resource, void *context);
|
||||
|
||||
static acpi_status
|
||||
ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval);
|
||||
|
||||
static struct acpi_ec *make_acpi_ec(void)
|
||||
{
|
||||
struct acpi_ec *ec = kzalloc(sizeof(struct acpi_ec), GFP_KERNEL);
|
||||
@ -610,13 +643,52 @@ static struct acpi_ec *make_acpi_ec(void)
|
||||
atomic_set(&ec->event_count, 1);
|
||||
mutex_init(&ec->lock);
|
||||
init_waitqueue_head(&ec->wait);
|
||||
INIT_LIST_HEAD(&ec->list);
|
||||
|
||||
return ec;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
acpi_ec_register_query_methods(acpi_handle handle, u32 level,
|
||||
void *context, void **return_value)
|
||||
{
|
||||
struct acpi_namespace_node *node = handle;
|
||||
struct acpi_ec *ec = context;
|
||||
int value = 0;
|
||||
if (sscanf(node->name.ascii, "_Q%x", &value) == 1) {
|
||||
acpi_ec_add_query_handler(ec, value, handle, NULL, NULL);
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
static int ec_parse_device(struct acpi_ec *ec, acpi_handle handle)
|
||||
{
|
||||
if (ACPI_FAILURE(acpi_walk_resources(handle, METHOD_NAME__CRS,
|
||||
ec_parse_io_ports, ec)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Get GPE bit assignment (EC events). */
|
||||
/* TODO: Add support for _GPE returning a package */
|
||||
if (ACPI_FAILURE(acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe)))
|
||||
return -EINVAL;
|
||||
|
||||
/* Use the global lock for all EC transactions? */
|
||||
acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
|
||||
|
||||
/* Find and register all query methods */
|
||||
acpi_walk_namespace(ACPI_TYPE_METHOD, handle, 1,
|
||||
acpi_ec_register_query_methods, ec, NULL);
|
||||
|
||||
ec->handle = handle;
|
||||
|
||||
printk(KERN_INFO PREFIX "GPE = 0x%lx, I/O: command/status = 0x%lx, data = 0x%lx",
|
||||
ec->gpe, ec->command_addr, ec->data_addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_ec_add(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_ec *ec = NULL;
|
||||
|
||||
if (!device)
|
||||
@ -629,8 +701,7 @@ static int acpi_ec_add(struct acpi_device *device)
|
||||
if (!ec)
|
||||
return -ENOMEM;
|
||||
|
||||
status = ec_parse_device(device->handle, 0, ec, NULL);
|
||||
if (status != AE_CTRL_TERMINATE) {
|
||||
if (ec_parse_device(ec, device->handle)) {
|
||||
kfree(ec);
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -641,6 +712,8 @@ static int acpi_ec_add(struct acpi_device *device)
|
||||
/* We might have incorrect info for GL at boot time */
|
||||
mutex_lock(&boot_ec->lock);
|
||||
boot_ec->global_lock = ec->global_lock;
|
||||
/* Copy handlers from new ec into boot ec */
|
||||
list_splice(&ec->list, &boot_ec->list);
|
||||
mutex_unlock(&boot_ec->lock);
|
||||
kfree(ec);
|
||||
ec = boot_ec;
|
||||
@ -651,22 +724,24 @@ static int acpi_ec_add(struct acpi_device *device)
|
||||
acpi_driver_data(device) = ec;
|
||||
|
||||
acpi_ec_add_fs(device);
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s [%s] (gpe %d) interrupt mode.",
|
||||
acpi_device_name(device), acpi_device_bid(device),
|
||||
(u32) ec->gpe));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_ec_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
struct acpi_ec *ec;
|
||||
struct acpi_ec_query_handler *handler;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
ec = acpi_driver_data(device);
|
||||
mutex_lock(&ec->lock);
|
||||
list_for_each_entry(handler, &ec->list, node) {
|
||||
list_del(&handler->node);
|
||||
kfree(handler);
|
||||
}
|
||||
mutex_unlock(&ec->lock);
|
||||
acpi_ec_remove_fs(device);
|
||||
acpi_driver_data(device) = NULL;
|
||||
if (ec == first_ec)
|
||||
@ -722,15 +797,13 @@ static int ec_install_handlers(struct acpi_ec *ec)
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/* EC is fully operational, allow queries */
|
||||
atomic_set(&ec->query_pending, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_ec_start(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_ec *ec;
|
||||
int ret = 0;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
@ -740,14 +813,14 @@ static int acpi_ec_start(struct acpi_device *device)
|
||||
if (!ec)
|
||||
return -EINVAL;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "gpe=0x%02lx, ports=0x%2lx,0x%2lx",
|
||||
ec->gpe, ec->command_addr, ec->data_addr));
|
||||
|
||||
/* Boot EC is already working */
|
||||
if (ec == boot_ec)
|
||||
return 0;
|
||||
if (ec != boot_ec)
|
||||
ret = ec_install_handlers(ec);
|
||||
|
||||
return ec_install_handlers(ec);
|
||||
/* EC is fully operational, allow queries */
|
||||
atomic_set(&ec->query_pending, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_ec_stop(struct acpi_device *device, int type)
|
||||
@ -779,34 +852,6 @@ static int acpi_ec_stop(struct acpi_device *device, int type)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static acpi_status
|
||||
ec_parse_device(acpi_handle handle, u32 Level, void *context, void **retval)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
struct acpi_ec *ec = context;
|
||||
status = acpi_walk_resources(handle, METHOD_NAME__CRS,
|
||||
ec_parse_io_ports, ec);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
/* Get GPE bit assignment (EC events). */
|
||||
/* TODO: Add support for _GPE returning a package */
|
||||
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec->gpe);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
/* Use the global lock for all EC transactions? */
|
||||
acpi_evaluate_integer(handle, "_GLK", NULL, &ec->global_lock);
|
||||
|
||||
ec->handle = handle;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "GPE=0x%02lx, ports=0x%2lx, 0x%2lx",
|
||||
ec->gpe, ec->command_addr, ec->data_addr));
|
||||
|
||||
return AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
||||
int __init acpi_ec_ecdt_probe(void)
|
||||
{
|
||||
int ret;
|
||||
@ -825,7 +870,7 @@ int __init acpi_ec_ecdt_probe(void)
|
||||
if (ACPI_FAILURE(status))
|
||||
goto error;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found ECDT"));
|
||||
printk(KERN_INFO PREFIX "EC description table is found, configuring boot EC\n");
|
||||
|
||||
boot_ec->command_addr = ecdt_ptr->control.address;
|
||||
boot_ec->data_addr = ecdt_ptr->data.address;
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <net/netlink.h>
|
||||
#include <net/genetlink.h>
|
||||
|
||||
#define _COMPONENT ACPI_SYSTEM_COMPONENT
|
||||
ACPI_MODULE_NAME("event");
|
||||
@ -48,7 +50,6 @@ acpi_system_read_event(struct file *file, char __user * buffer, size_t count,
|
||||
static int chars_remaining = 0;
|
||||
static char *ptr;
|
||||
|
||||
|
||||
if (!chars_remaining) {
|
||||
memset(&event, 0, sizeof(struct acpi_bus_event));
|
||||
|
||||
@ -106,23 +107,161 @@ static const struct file_operations acpi_system_event_ops = {
|
||||
.poll = acpi_system_poll_event,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_NET
|
||||
unsigned int acpi_event_seqnum;
|
||||
struct acpi_genl_event {
|
||||
acpi_device_class device_class;
|
||||
char bus_id[15];
|
||||
u32 type;
|
||||
u32 data;
|
||||
};
|
||||
|
||||
/* attributes of acpi_genl_family */
|
||||
enum {
|
||||
ACPI_GENL_ATTR_UNSPEC,
|
||||
ACPI_GENL_ATTR_EVENT, /* ACPI event info needed by user space */
|
||||
__ACPI_GENL_ATTR_MAX,
|
||||
};
|
||||
#define ACPI_GENL_ATTR_MAX (__ACPI_GENL_ATTR_MAX - 1)
|
||||
|
||||
/* commands supported by the acpi_genl_family */
|
||||
enum {
|
||||
ACPI_GENL_CMD_UNSPEC,
|
||||
ACPI_GENL_CMD_EVENT, /* kernel->user notifications for ACPI events */
|
||||
__ACPI_GENL_CMD_MAX,
|
||||
};
|
||||
#define ACPI_GENL_CMD_MAX (__ACPI_GENL_CMD_MAX - 1)
|
||||
|
||||
#define ACPI_GENL_FAMILY_NAME "acpi_event"
|
||||
#define ACPI_GENL_VERSION 0x01
|
||||
#define ACPI_GENL_MCAST_GROUP_NAME "acpi_mc_group"
|
||||
|
||||
static struct genl_family acpi_event_genl_family = {
|
||||
.id = GENL_ID_GENERATE,
|
||||
.name = ACPI_GENL_FAMILY_NAME,
|
||||
.version = ACPI_GENL_VERSION,
|
||||
.maxattr = ACPI_GENL_ATTR_MAX,
|
||||
};
|
||||
|
||||
static struct genl_multicast_group acpi_event_mcgrp = {
|
||||
.name = ACPI_GENL_MCAST_GROUP_NAME,
|
||||
};
|
||||
|
||||
int acpi_bus_generate_genetlink_event(struct acpi_device *device,
|
||||
u8 type, int data)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct nlattr *attr;
|
||||
struct acpi_genl_event *event;
|
||||
void *msg_header;
|
||||
int size;
|
||||
int result;
|
||||
|
||||
/* allocate memory */
|
||||
size = nla_total_size(sizeof(struct acpi_genl_event)) +
|
||||
nla_total_size(0);
|
||||
|
||||
skb = genlmsg_new(size, GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
/* add the genetlink message header */
|
||||
msg_header = genlmsg_put(skb, 0, acpi_event_seqnum++,
|
||||
&acpi_event_genl_family, 0,
|
||||
ACPI_GENL_CMD_EVENT);
|
||||
if (!msg_header) {
|
||||
nlmsg_free(skb);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* fill the data */
|
||||
attr =
|
||||
nla_reserve(skb, ACPI_GENL_ATTR_EVENT,
|
||||
sizeof(struct acpi_genl_event));
|
||||
if (!attr) {
|
||||
nlmsg_free(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
event = nla_data(attr);
|
||||
if (!event) {
|
||||
nlmsg_free(skb);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memset(event, 0, sizeof(struct acpi_genl_event));
|
||||
|
||||
strcpy(event->device_class, device->pnp.device_class);
|
||||
strcpy(event->bus_id, device->dev.bus_id);
|
||||
event->type = type;
|
||||
event->data = data;
|
||||
|
||||
/* send multicast genetlink message */
|
||||
result = genlmsg_end(skb, msg_header);
|
||||
if (result < 0) {
|
||||
nlmsg_free(skb);
|
||||
return result;
|
||||
}
|
||||
|
||||
result =
|
||||
genlmsg_multicast(skb, 0, acpi_event_mcgrp.id, GFP_ATOMIC);
|
||||
if (result)
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Failed to send a Genetlink message!\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_event_genetlink_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = genl_register_family(&acpi_event_genl_family);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = genl_register_mc_group(&acpi_event_genl_family,
|
||||
&acpi_event_mcgrp);
|
||||
if (result)
|
||||
genl_unregister_family(&acpi_event_genl_family);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
int acpi_bus_generate_genetlink_event(struct acpi_device *device, u8 type,
|
||||
int data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_event_genetlink_init(void)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init acpi_event_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
int error = 0;
|
||||
|
||||
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
/* create genetlink for acpi event */
|
||||
error = acpi_event_genetlink_init();
|
||||
if (error)
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Failed to create genetlink family for ACPI event\n");
|
||||
|
||||
/* 'event' [R] */
|
||||
entry = create_proc_entry("event", S_IRUSR, acpi_root_dir);
|
||||
if (entry)
|
||||
entry->proc_fops = &acpi_system_event_ops;
|
||||
else {
|
||||
error = -ENODEV;
|
||||
}
|
||||
return error;
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(acpi_event_init);
|
||||
fs_initcall(acpi_event_init);
|
||||
|
@ -586,6 +586,10 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
|
||||
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
|
||||
if (gpe_xrupt->previous) {
|
||||
gpe_xrupt->previous->next = gpe_xrupt->next;
|
||||
} else {
|
||||
/* No previous, update list head */
|
||||
|
||||
acpi_gbl_gpe_xrupt_list_head = gpe_xrupt->next;
|
||||
}
|
||||
|
||||
if (gpe_xrupt->next) {
|
||||
|
@ -284,6 +284,7 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
|
||||
}
|
||||
|
||||
if (!pci_device_node) {
|
||||
ACPI_FREE(pci_id);
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#if ACPI_GLUE_DEBUG
|
||||
#define DBG(x...) printk(PREFIX x)
|
||||
#else
|
||||
#define DBG(x...)
|
||||
#define DBG(x...) do { } while(0)
|
||||
#endif
|
||||
static LIST_HEAD(bus_type_list);
|
||||
static DECLARE_RWSEM(bus_type_sem);
|
||||
|
@ -77,13 +77,7 @@ static struct workqueue_struct *kacpi_notify_wq;
|
||||
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
|
||||
static char osi_additional_string[OSI_STRING_LENGTH_MAX];
|
||||
|
||||
#define OSI_LINUX_ENABLED
|
||||
#ifdef OSI_LINUX_ENABLED
|
||||
int osi_linux = 1; /* enable _OSI(Linux) by default */
|
||||
#else
|
||||
int osi_linux; /* disable _OSI(Linux) by default */
|
||||
#endif
|
||||
|
||||
static int osi_linux; /* disable _OSI(Linux) by default */
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
static struct __initdata dmi_system_id acpi_osl_dmi_table[];
|
||||
@ -1183,17 +1177,10 @@ acpi_os_validate_interface (char *interface)
|
||||
if (!strcmp("Linux", interface)) {
|
||||
printk(KERN_WARNING PREFIX
|
||||
"System BIOS is requesting _OSI(Linux)\n");
|
||||
#ifdef OSI_LINUX_ENABLED
|
||||
printk(KERN_WARNING PREFIX
|
||||
"Please test with \"acpi_osi=!Linux\"\n"
|
||||
"Please send dmidecode "
|
||||
"to linux-acpi@vger.kernel.org\n");
|
||||
#else
|
||||
printk(KERN_WARNING PREFIX
|
||||
"If \"acpi_osi=Linux\" works better,\n"
|
||||
"Please send dmidecode "
|
||||
"to linux-acpi@vger.kernel.org\n");
|
||||
#endif
|
||||
if(osi_linux)
|
||||
return AE_OK;
|
||||
}
|
||||
@ -1227,36 +1214,14 @@ acpi_os_validate_address (
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
#ifdef OSI_LINUX_ENABLED
|
||||
static int dmi_osi_not_linux(struct dmi_system_id *d)
|
||||
{
|
||||
printk(KERN_NOTICE "%s detected: requires not _OSI(Linux)\n", d->ident);
|
||||
enable_osi_linux(0);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static int dmi_osi_linux(struct dmi_system_id *d)
|
||||
{
|
||||
printk(KERN_NOTICE "%s detected: requires _OSI(Linux)\n", d->ident);
|
||||
printk(KERN_NOTICE "%s detected: enabling _OSI(Linux)\n", d->ident);
|
||||
enable_osi_linux(1);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
|
||||
#ifdef OSI_LINUX_ENABLED
|
||||
/*
|
||||
* Boxes that need NOT _OSI(Linux)
|
||||
*/
|
||||
{
|
||||
.callback = dmi_osi_not_linux,
|
||||
.ident = "Toshiba Satellite P100",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_BOARD_VENDOR, "TOSHIBA"),
|
||||
DMI_MATCH(DMI_BOARD_NAME, "Satellite P100"),
|
||||
},
|
||||
},
|
||||
#else
|
||||
/*
|
||||
* Boxes that need _OSI(Linux)
|
||||
*/
|
||||
@ -1268,7 +1233,6 @@ static struct dmi_system_id acpi_osl_dmi_table[] __initdata = {
|
||||
DMI_MATCH(DMI_BOARD_NAME, "MPAD-MSAE Customer Reference Boards"),
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{}
|
||||
};
|
||||
#endif /* CONFIG_DMI */
|
||||
|
@ -733,7 +733,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
|
||||
/* query and set link->irq.active */
|
||||
acpi_pci_link_get_current(link);
|
||||
|
||||
printk(PREFIX "%s [%s] (IRQs", acpi_device_name(device),
|
||||
printk(KERN_INFO PREFIX "%s [%s] (IRQs", acpi_device_name(device),
|
||||
acpi_device_bid(device));
|
||||
for (i = 0; i < link->irq.possible_count; i++) {
|
||||
if (link->irq.active == link->irq.possible[i]) {
|
||||
|
@ -66,6 +66,7 @@
|
||||
#define ACPI_PROCESSOR_FILE_LIMIT "limit"
|
||||
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
|
||||
#define ACPI_PROCESSOR_NOTIFY_POWER 0x81
|
||||
#define ACPI_PROCESSOR_NOTIFY_THROTTLING 0x82
|
||||
|
||||
#define ACPI_PROCESSOR_LIMIT_USER 0
|
||||
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
|
||||
@ -84,6 +85,8 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file);
|
||||
static void acpi_processor_notify(acpi_handle handle, u32 event, void *data);
|
||||
static acpi_status acpi_processor_hotadd_init(acpi_handle handle, int *p_cpu);
|
||||
static int acpi_processor_handle_eject(struct acpi_processor *pr);
|
||||
extern int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
|
||||
|
||||
|
||||
static struct acpi_driver acpi_processor_driver = {
|
||||
.name = "processor",
|
||||
@ -696,6 +699,9 @@ static void acpi_processor_notify(acpi_handle handle, u32 event, void *data)
|
||||
acpi_processor_cst_has_changed(pr);
|
||||
acpi_bus_generate_event(device, event, 0);
|
||||
break;
|
||||
case ACPI_PROCESSOR_NOTIFY_THROTTLING:
|
||||
acpi_processor_tstate_has_changed(pr);
|
||||
acpi_bus_generate_event(device, event, 0);
|
||||
default:
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Unsupported event [0x%x]\n", event));
|
||||
|
@ -490,7 +490,17 @@ static void acpi_processor_idle(void)
|
||||
|
||||
case ACPI_STATE_C3:
|
||||
|
||||
if (pr->flags.bm_check) {
|
||||
/*
|
||||
* disable bus master
|
||||
* bm_check implies we need ARB_DIS
|
||||
* !bm_check implies we need cache flush
|
||||
* bm_control implies whether we can do ARB_DIS
|
||||
*
|
||||
* That leaves a case where bm_check is set and bm_control is
|
||||
* not set. In that case we cannot do much, we enter C3
|
||||
* without doing anything.
|
||||
*/
|
||||
if (pr->flags.bm_check && pr->flags.bm_control) {
|
||||
if (atomic_inc_return(&c3_cpu_count) ==
|
||||
num_online_cpus()) {
|
||||
/*
|
||||
@ -499,7 +509,7 @@ static void acpi_processor_idle(void)
|
||||
*/
|
||||
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
|
||||
}
|
||||
} else {
|
||||
} else if (!pr->flags.bm_check) {
|
||||
/* SMP with no shared cache... Invalidate cache */
|
||||
ACPI_FLUSH_CPU_CACHE();
|
||||
}
|
||||
@ -511,7 +521,7 @@ static void acpi_processor_idle(void)
|
||||
acpi_cstate_enter(cx);
|
||||
/* Get end time (ticks) */
|
||||
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
if (pr->flags.bm_check) {
|
||||
if (pr->flags.bm_check && pr->flags.bm_control) {
|
||||
/* Enable bus master arbitration */
|
||||
atomic_dec(&c3_cpu_count);
|
||||
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
|
||||
@ -961,9 +971,9 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
|
||||
if (pr->flags.bm_check) {
|
||||
/* bus mastering control is necessary */
|
||||
if (!pr->flags.bm_control) {
|
||||
/* In this case we enter C3 without bus mastering */
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"C3 support requires bus mastering control\n"));
|
||||
return;
|
||||
"C3 support without bus mastering control\n"));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
@ -44,17 +44,231 @@
|
||||
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
|
||||
ACPI_MODULE_NAME("processor_throttling");
|
||||
|
||||
static int acpi_processor_get_throttling(struct acpi_processor *pr);
|
||||
int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
|
||||
|
||||
static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
unsigned long tpc = 0;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
status = acpi_evaluate_integer(pr->handle, "_TPC", NULL, &tpc);
|
||||
if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TPC"));
|
||||
return -ENODEV;
|
||||
}
|
||||
pr->throttling_platform_limit = (int)tpc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_processor_tstate_has_changed(struct acpi_processor *pr)
|
||||
{
|
||||
return acpi_processor_get_platform_limit(pr);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
_PTC, _TSS, _TSD support
|
||||
-------------------------------------------------------------------------- */
|
||||
static int acpi_processor_get_throttling_control(struct acpi_processor *pr)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = 0;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
union acpi_object *ptc = NULL;
|
||||
union acpi_object obj = { 0 };
|
||||
|
||||
status = acpi_evaluate_object(pr->handle, "_PTC", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PTC"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ptc = (union acpi_object *)buffer.pointer;
|
||||
if (!ptc || (ptc->type != ACPI_TYPE_PACKAGE)
|
||||
|| (ptc->package.count != 2)) {
|
||||
printk(KERN_ERR PREFIX "Invalid _PTC data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* control_register
|
||||
*/
|
||||
|
||||
obj = ptc->package.elements[0];
|
||||
|
||||
if ((obj.type != ACPI_TYPE_BUFFER)
|
||||
|| (obj.buffer.length < sizeof(struct acpi_ptc_register))
|
||||
|| (obj.buffer.pointer == NULL)) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Invalid _PTC data (control_register)\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
memcpy(&pr->throttling.control_register, obj.buffer.pointer,
|
||||
sizeof(struct acpi_ptc_register));
|
||||
|
||||
/*
|
||||
* status_register
|
||||
*/
|
||||
|
||||
obj = ptc->package.elements[1];
|
||||
|
||||
if ((obj.type != ACPI_TYPE_BUFFER)
|
||||
|| (obj.buffer.length < sizeof(struct acpi_ptc_register))
|
||||
|| (obj.buffer.pointer == NULL)) {
|
||||
printk(KERN_ERR PREFIX "Invalid _PTC data (status_register)\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
memcpy(&pr->throttling.status_register, obj.buffer.pointer,
|
||||
sizeof(struct acpi_ptc_register));
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
return result;
|
||||
}
|
||||
static int acpi_processor_get_throttling_states(struct acpi_processor *pr)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
|
||||
struct acpi_buffer state = { 0, NULL };
|
||||
union acpi_object *tss = NULL;
|
||||
int i;
|
||||
|
||||
status = acpi_evaluate_object(pr->handle, "_TSS", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Evaluating _TSS"));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
tss = buffer.pointer;
|
||||
if (!tss || (tss->type != ACPI_TYPE_PACKAGE)) {
|
||||
printk(KERN_ERR PREFIX "Invalid _TSS data\n");
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
|
||||
tss->package.count));
|
||||
|
||||
pr->throttling.state_count = tss->package.count;
|
||||
pr->throttling.states_tss =
|
||||
kmalloc(sizeof(struct acpi_processor_tx_tss) * tss->package.count,
|
||||
GFP_KERNEL);
|
||||
if (!pr->throttling.states_tss) {
|
||||
result = -ENOMEM;
|
||||
goto end;
|
||||
}
|
||||
|
||||
for (i = 0; i < pr->throttling.state_count; i++) {
|
||||
|
||||
struct acpi_processor_tx_tss *tx =
|
||||
(struct acpi_processor_tx_tss *)&(pr->throttling.
|
||||
states_tss[i]);
|
||||
|
||||
state.length = sizeof(struct acpi_processor_tx_tss);
|
||||
state.pointer = tx;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
|
||||
|
||||
status = acpi_extract_package(&(tss->package.elements[i]),
|
||||
&format, &state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, status, "Invalid _TSS data"));
|
||||
result = -EFAULT;
|
||||
kfree(pr->throttling.states_tss);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!tx->freqpercentage) {
|
||||
printk(KERN_ERR PREFIX
|
||||
"Invalid _TSS data: freq is zero\n");
|
||||
result = -EFAULT;
|
||||
kfree(pr->throttling.states_tss);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
|
||||
return result;
|
||||
}
|
||||
static int acpi_processor_get_tsd(struct acpi_processor *pr)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
|
||||
struct acpi_buffer state = { 0, NULL };
|
||||
union acpi_object *tsd = NULL;
|
||||
struct acpi_tsd_package *pdomain;
|
||||
|
||||
status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
tsd = buffer.pointer;
|
||||
if (!tsd || (tsd->type != ACPI_TYPE_PACKAGE)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (tsd->package.count != 1) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
pdomain = &(pr->throttling.domain_info);
|
||||
|
||||
state.length = sizeof(struct acpi_tsd_package);
|
||||
state.pointer = pdomain;
|
||||
|
||||
status = acpi_extract_package(&(tsd->package.elements[0]),
|
||||
&format, &state);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _TSD data\n"));
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pdomain->num_entries != ACPI_TSD_REV0_ENTRIES) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:num_entries\n"));
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (pdomain->revision != ACPI_TSD_REV0_REVISION) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unknown _TSD:revision\n"));
|
||||
result = -EFAULT;
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
kfree(buffer.pointer);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Throttling Control
|
||||
-------------------------------------------------------------------------- */
|
||||
static int acpi_processor_get_throttling(struct acpi_processor *pr)
|
||||
static int acpi_processor_get_throttling_fadt(struct acpi_processor *pr)
|
||||
{
|
||||
int state = 0;
|
||||
u32 value = 0;
|
||||
u32 duty_mask = 0;
|
||||
u32 duty_value = 0;
|
||||
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
@ -94,13 +308,115 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
|
||||
static int acpi_read_throttling_status(struct acpi_processor_throttling
|
||||
*throttling)
|
||||
{
|
||||
int value = -1;
|
||||
switch (throttling->status_register.space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
acpi_os_read_port((acpi_io_address) throttling->status_register.
|
||||
address, &value,
|
||||
(u32) throttling->status_register.bit_width *
|
||||
8);
|
||||
break;
|
||||
case ACPI_ADR_SPACE_FIXED_HARDWARE:
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Unknown addr space %d\n",
|
||||
(u32) (throttling->status_register.space_id));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int acpi_write_throttling_state(struct acpi_processor_throttling
|
||||
*throttling, int value)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
switch (throttling->control_register.space_id) {
|
||||
case ACPI_ADR_SPACE_SYSTEM_IO:
|
||||
acpi_os_write_port((acpi_io_address) throttling->
|
||||
control_register.address, value,
|
||||
(u32) throttling->control_register.
|
||||
bit_width * 8);
|
||||
ret = 0;
|
||||
break;
|
||||
case ACPI_ADR_SPACE_FIXED_HARDWARE:
|
||||
printk(KERN_ERR PREFIX
|
||||
"HARDWARE addr space,NOT supported yet\n");
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PREFIX "Unknown addr space %d\n",
|
||||
(u32) (throttling->control_register.space_id));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int acpi_get_throttling_state(struct acpi_processor *pr, int value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < pr->throttling.state_count; i++) {
|
||||
struct acpi_processor_tx_tss *tx =
|
||||
(struct acpi_processor_tx_tss *)&(pr->throttling.
|
||||
states_tss[i]);
|
||||
if (tx->control == value)
|
||||
break;
|
||||
}
|
||||
if (i > pr->throttling.state_count)
|
||||
i = -1;
|
||||
return i;
|
||||
}
|
||||
|
||||
static int acpi_get_throttling_value(struct acpi_processor *pr, int state)
|
||||
{
|
||||
int value = -1;
|
||||
if (state >= 0 && state <= pr->throttling.state_count) {
|
||||
struct acpi_processor_tx_tss *tx =
|
||||
(struct acpi_processor_tx_tss *)&(pr->throttling.
|
||||
states_tss[state]);
|
||||
value = tx->control;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static int acpi_processor_get_throttling_ptc(struct acpi_processor *pr)
|
||||
{
|
||||
int state = 0;
|
||||
u32 value = 0;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pr->flags.throttling)
|
||||
return -ENODEV;
|
||||
|
||||
pr->throttling.state = 0;
|
||||
local_irq_disable();
|
||||
value = acpi_read_throttling_status(&pr->throttling);
|
||||
if (value >= 0) {
|
||||
state = acpi_get_throttling_state(pr, value);
|
||||
pr->throttling.state = state;
|
||||
}
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_get_throttling(struct acpi_processor *pr)
|
||||
{
|
||||
return pr->throttling.acpi_processor_get_throttling(pr);
|
||||
}
|
||||
|
||||
static int acpi_processor_set_throttling_fadt(struct acpi_processor *pr,
|
||||
int state)
|
||||
{
|
||||
u32 value = 0;
|
||||
u32 duty_mask = 0;
|
||||
u32 duty_value = 0;
|
||||
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
@ -113,6 +429,8 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
|
||||
if (state == pr->throttling.state)
|
||||
return 0;
|
||||
|
||||
if (state < pr->throttling_platform_limit)
|
||||
return -EPERM;
|
||||
/*
|
||||
* Calculate the duty_value and duty_mask.
|
||||
*/
|
||||
@ -165,12 +483,51 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
|
||||
int state)
|
||||
{
|
||||
u32 value = 0;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
|
||||
return -EINVAL;
|
||||
|
||||
if (!pr->flags.throttling)
|
||||
return -ENODEV;
|
||||
|
||||
if (state == pr->throttling.state)
|
||||
return 0;
|
||||
|
||||
if (state < pr->throttling_platform_limit)
|
||||
return -EPERM;
|
||||
|
||||
local_irq_disable();
|
||||
|
||||
value = acpi_get_throttling_value(pr, state);
|
||||
if (value >= 0) {
|
||||
acpi_write_throttling_state(&pr->throttling, value);
|
||||
pr->throttling.state = state;
|
||||
}
|
||||
local_irq_enable();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
|
||||
{
|
||||
return pr->throttling.acpi_processor_set_throttling(pr, state);
|
||||
}
|
||||
|
||||
int acpi_processor_get_throttling_info(struct acpi_processor *pr)
|
||||
{
|
||||
int result = 0;
|
||||
int step = 0;
|
||||
int i = 0;
|
||||
|
||||
int no_ptc = 0;
|
||||
int no_tss = 0;
|
||||
int no_tsd = 0;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
|
||||
@ -182,6 +539,21 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
|
||||
return -EINVAL;
|
||||
|
||||
/* TBD: Support ACPI 2.0 objects */
|
||||
no_ptc = acpi_processor_get_throttling_control(pr);
|
||||
no_tss = acpi_processor_get_throttling_states(pr);
|
||||
no_tsd = acpi_processor_get_tsd(pr);
|
||||
|
||||
if (no_ptc || no_tss) {
|
||||
pr->throttling.acpi_processor_get_throttling =
|
||||
&acpi_processor_get_throttling_fadt;
|
||||
pr->throttling.acpi_processor_set_throttling =
|
||||
&acpi_processor_set_throttling_fadt;
|
||||
} else {
|
||||
pr->throttling.acpi_processor_get_throttling =
|
||||
&acpi_processor_get_throttling_ptc;
|
||||
pr->throttling.acpi_processor_set_throttling =
|
||||
&acpi_processor_set_throttling_ptc;
|
||||
}
|
||||
|
||||
if (!pr->throttling.address) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling register\n"));
|
||||
@ -262,7 +634,6 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
|
||||
int i = 0;
|
||||
int result = 0;
|
||||
|
||||
|
||||
if (!pr)
|
||||
goto end;
|
||||
|
||||
@ -280,15 +651,25 @@ static int acpi_processor_throttling_seq_show(struct seq_file *seq,
|
||||
}
|
||||
|
||||
seq_printf(seq, "state count: %d\n"
|
||||
"active state: T%d\n",
|
||||
pr->throttling.state_count, pr->throttling.state);
|
||||
"active state: T%d\n"
|
||||
"state available: T%d to T%d\n",
|
||||
pr->throttling.state_count, pr->throttling.state,
|
||||
pr->throttling_platform_limit,
|
||||
pr->throttling.state_count - 1);
|
||||
|
||||
seq_puts(seq, "states:\n");
|
||||
for (i = 0; i < pr->throttling.state_count; i++)
|
||||
seq_printf(seq, " %cT%d: %02d%%\n",
|
||||
(i == pr->throttling.state ? '*' : ' '), i,
|
||||
(pr->throttling.states[i].performance ? pr->
|
||||
throttling.states[i].performance / 10 : 0));
|
||||
if (acpi_processor_get_throttling == acpi_processor_get_throttling_fadt)
|
||||
for (i = 0; i < pr->throttling.state_count; i++)
|
||||
seq_printf(seq, " %cT%d: %02d%%\n",
|
||||
(i == pr->throttling.state ? '*' : ' '), i,
|
||||
(pr->throttling.states[i].performance ? pr->
|
||||
throttling.states[i].performance / 10 : 0));
|
||||
else
|
||||
for (i = 0; i < pr->throttling.state_count; i++)
|
||||
seq_printf(seq, " %cT%d: %02d%%\n",
|
||||
(i == pr->throttling.state ? '*' : ' '), i,
|
||||
(int)pr->throttling.states_tss[i].
|
||||
freqpercentage);
|
||||
|
||||
end:
|
||||
return 0;
|
||||
@ -301,7 +682,7 @@ static int acpi_processor_throttling_open_fs(struct inode *inode,
|
||||
PDE(inode)->data);
|
||||
}
|
||||
|
||||
static ssize_t acpi_processor_write_throttling(struct file * file,
|
||||
static ssize_t acpi_processor_write_throttling(struct file *file,
|
||||
const char __user * buffer,
|
||||
size_t count, loff_t * data)
|
||||
{
|
||||
@ -310,7 +691,6 @@ static ssize_t acpi_processor_write_throttling(struct file * file,
|
||||
struct acpi_processor *pr = m->private;
|
||||
char state_string[12] = { '\0' };
|
||||
|
||||
|
||||
if (!pr || (count > sizeof(state_string) - 1))
|
||||
return -EINVAL;
|
||||
|
||||
|
@ -127,7 +127,7 @@ static int acpi_sbs_resume(struct acpi_device *device);
|
||||
static struct acpi_driver acpi_sbs_driver = {
|
||||
.name = "sbs",
|
||||
.class = ACPI_SBS_CLASS,
|
||||
.ids = ACPI_SBS_HID,
|
||||
.ids = "ACPI0001,ACPI0005",
|
||||
.ops = {
|
||||
.add = acpi_sbs_add,
|
||||
.remove = acpi_sbs_remove,
|
||||
@ -176,10 +176,8 @@ struct acpi_battery {
|
||||
};
|
||||
|
||||
struct acpi_sbs {
|
||||
acpi_handle handle;
|
||||
int base;
|
||||
struct acpi_device *device;
|
||||
struct acpi_ec_smbus *smbus;
|
||||
struct mutex mutex;
|
||||
int sbsm_present;
|
||||
int sbsm_batteries_supported;
|
||||
@ -511,7 +509,7 @@ static int acpi_sbsm_get_info(struct acpi_sbs *sbs)
|
||||
"acpi_sbs_read_word() failed"));
|
||||
goto end;
|
||||
}
|
||||
|
||||
sbs->sbsm_present = 1;
|
||||
sbs->sbsm_batteries_supported = battery_system_info & 0x000f;
|
||||
|
||||
end:
|
||||
@ -1630,13 +1628,12 @@ static int acpi_sbs_add(struct acpi_device *device)
|
||||
{
|
||||
struct acpi_sbs *sbs = NULL;
|
||||
int result = 0, remove_result = 0;
|
||||
unsigned long sbs_obj;
|
||||
int id;
|
||||
acpi_status status = AE_OK;
|
||||
unsigned long val;
|
||||
|
||||
status =
|
||||
acpi_evaluate_integer(device->parent->handle, "_EC", NULL, &val);
|
||||
acpi_evaluate_integer(device->handle, "_EC", NULL, &val);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
ACPI_EXCEPTION((AE_INFO, AE_ERROR, "Error obtaining _EC"));
|
||||
return -EIO;
|
||||
@ -1653,7 +1650,7 @@ static int acpi_sbs_add(struct acpi_device *device)
|
||||
|
||||
sbs_mutex_lock(sbs);
|
||||
|
||||
sbs->base = (val & 0xff00ull) >> 8;
|
||||
sbs->base = 0xff & (val >> 8);
|
||||
sbs->device = device;
|
||||
|
||||
strcpy(acpi_device_name(device), ACPI_SBS_DEVICE_NAME);
|
||||
@ -1665,24 +1662,10 @@ static int acpi_sbs_add(struct acpi_device *device)
|
||||
ACPI_EXCEPTION((AE_INFO, AE_ERROR, "acpi_ac_add() failed"));
|
||||
goto end;
|
||||
}
|
||||
status = acpi_evaluate_integer(device->handle, "_SBS", NULL, &sbs_obj);
|
||||
if (status) {
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"acpi_evaluate_integer() failed"));
|
||||
result = -EIO;
|
||||
goto end;
|
||||
}
|
||||
if (sbs_obj > 0) {
|
||||
result = acpi_sbsm_get_info(sbs);
|
||||
if (result) {
|
||||
ACPI_EXCEPTION((AE_INFO, AE_ERROR,
|
||||
"acpi_sbsm_get_info() failed"));
|
||||
goto end;
|
||||
}
|
||||
sbs->sbsm_present = 1;
|
||||
}
|
||||
|
||||
if (sbs->sbsm_present == 0) {
|
||||
acpi_sbsm_get_info(sbs);
|
||||
|
||||
if (!sbs->sbsm_present) {
|
||||
result = acpi_battery_add(sbs, 0);
|
||||
if (result) {
|
||||
ACPI_EXCEPTION((AE_INFO, AE_ERROR,
|
||||
@ -1702,8 +1685,6 @@ static int acpi_sbs_add(struct acpi_device *device)
|
||||
}
|
||||
}
|
||||
|
||||
sbs->handle = device->handle;
|
||||
|
||||
init_timer(&sbs->update_timer);
|
||||
result = acpi_check_update_proc(sbs);
|
||||
if (result)
|
||||
|
@ -210,11 +210,6 @@ static void acpi_hibernation_finish(void)
|
||||
|
||||
/* reset firmware waking vector */
|
||||
acpi_set_firmware_waking_vector((acpi_physical_address) 0);
|
||||
|
||||
if (init_8259A_after_S1) {
|
||||
printk("Broken toshiba laptop -> kicking interrupts\n");
|
||||
init_8259A(0);
|
||||
}
|
||||
}
|
||||
|
||||
static int acpi_hibernation_pre_restore(void)
|
||||
|
@ -39,15 +39,12 @@ ACPI_MODULE_NAME("system");
|
||||
|
||||
#define ACPI_SYSTEM_CLASS "system"
|
||||
#define ACPI_SYSTEM_DEVICE_NAME "System"
|
||||
#define ACPI_SYSTEM_FILE_INFO "info"
|
||||
#define ACPI_SYSTEM_FILE_EVENT "event"
|
||||
#define ACPI_SYSTEM_FILE_DSDT "dsdt"
|
||||
#define ACPI_SYSTEM_FILE_FADT "fadt"
|
||||
|
||||
/*
|
||||
* Make ACPICA version work as module param
|
||||
*/
|
||||
static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
|
||||
static int param_get_acpica_version(char *buffer, struct kernel_param *kp)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = sprintf(buffer, "%x", ACPI_CA_VERSION);
|
||||
@ -57,10 +54,127 @@ static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
|
||||
|
||||
module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/sys)
|
||||
-------------------------------------------------------------------------- */
|
||||
static LIST_HEAD(acpi_table_attr_list);
|
||||
static struct kobject tables_kobj;
|
||||
|
||||
struct acpi_table_attr {
|
||||
struct bin_attribute attr;
|
||||
char name[8];
|
||||
int instance;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static ssize_t acpi_table_show(struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr, char *buf,
|
||||
loff_t offset, size_t count)
|
||||
{
|
||||
struct acpi_table_attr *table_attr =
|
||||
container_of(bin_attr, struct acpi_table_attr, attr);
|
||||
struct acpi_table_header *table_header = NULL;
|
||||
acpi_status status;
|
||||
ssize_t ret_count = count;
|
||||
|
||||
status =
|
||||
acpi_get_table(table_attr->name, table_attr->instance,
|
||||
&table_header);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
if (offset >= table_header->length) {
|
||||
ret_count = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (offset + ret_count > table_header->length)
|
||||
ret_count = table_header->length - offset;
|
||||
|
||||
memcpy(buf, ((char *)table_header) + offset, ret_count);
|
||||
|
||||
end:
|
||||
return ret_count;
|
||||
}
|
||||
|
||||
static void acpi_table_attr_init(struct acpi_table_attr *table_attr,
|
||||
struct acpi_table_header *table_header)
|
||||
{
|
||||
struct acpi_table_header *header = NULL;
|
||||
struct acpi_table_attr *attr = NULL;
|
||||
|
||||
memcpy(table_attr->name, table_header->signature, ACPI_NAME_SIZE);
|
||||
|
||||
list_for_each_entry(attr, &acpi_table_attr_list, node) {
|
||||
if (!memcmp(table_header->signature, attr->name,
|
||||
ACPI_NAME_SIZE))
|
||||
if (table_attr->instance < attr->instance)
|
||||
table_attr->instance = attr->instance;
|
||||
}
|
||||
table_attr->instance++;
|
||||
|
||||
if (table_attr->instance > 1 || (table_attr->instance == 1 &&
|
||||
!acpi_get_table(table_header->
|
||||
signature, 2,
|
||||
&header)))
|
||||
sprintf(table_attr->name + 4, "%d", table_attr->instance);
|
||||
|
||||
table_attr->attr.size = 0;
|
||||
table_attr->attr.read = acpi_table_show;
|
||||
table_attr->attr.attr.name = table_attr->name;
|
||||
table_attr->attr.attr.mode = 0444;
|
||||
table_attr->attr.attr.owner = THIS_MODULE;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int acpi_system_sysfs_init(void)
|
||||
{
|
||||
struct acpi_table_attr *table_attr;
|
||||
struct acpi_table_header *table_header = NULL;
|
||||
int table_index = 0;
|
||||
int result;
|
||||
|
||||
tables_kobj.parent = &acpi_subsys.kobj;
|
||||
kobject_set_name(&tables_kobj, "tables");
|
||||
result = kobject_register(&tables_kobj);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
do {
|
||||
result = acpi_get_table_by_index(table_index, &table_header);
|
||||
if (!result) {
|
||||
table_index++;
|
||||
table_attr = NULL;
|
||||
table_attr =
|
||||
kzalloc(sizeof(struct acpi_table_attr), GFP_KERNEL);
|
||||
if (!table_attr)
|
||||
return -ENOMEM;
|
||||
|
||||
acpi_table_attr_init(table_attr, table_header);
|
||||
result =
|
||||
sysfs_create_bin_file(&tables_kobj,
|
||||
&table_attr->attr);
|
||||
if (result) {
|
||||
kfree(table_attr);
|
||||
return result;
|
||||
} else
|
||||
list_add_tail(&table_attr->node,
|
||||
&acpi_table_attr_list);
|
||||
}
|
||||
} while (!result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
#define ACPI_SYSTEM_FILE_INFO "info"
|
||||
#define ACPI_SYSTEM_FILE_EVENT "event"
|
||||
#define ACPI_SYSTEM_FILE_DSDT "dsdt"
|
||||
#define ACPI_SYSTEM_FILE_FADT "fadt"
|
||||
|
||||
static int acpi_system_read_info(struct seq_file *seq, void *offset)
|
||||
{
|
||||
@ -80,7 +194,6 @@ static const struct file_operations acpi_system_info_ops = {
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
#endif
|
||||
|
||||
static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
|
||||
loff_t *);
|
||||
@ -97,13 +210,11 @@ acpi_system_read_dsdt(struct file *file,
|
||||
struct acpi_table_header *dsdt = NULL;
|
||||
ssize_t res;
|
||||
|
||||
|
||||
status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
res = simple_read_from_buffer(buffer, count, ppos,
|
||||
dsdt, dsdt->length);
|
||||
res = simple_read_from_buffer(buffer, count, ppos, dsdt, dsdt->length);
|
||||
|
||||
return res;
|
||||
}
|
||||
@ -123,28 +234,21 @@ acpi_system_read_fadt(struct file *file,
|
||||
struct acpi_table_header *fadt = NULL;
|
||||
ssize_t res;
|
||||
|
||||
|
||||
status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
res = simple_read_from_buffer(buffer, count, ppos,
|
||||
fadt, fadt->length);
|
||||
res = simple_read_from_buffer(buffer, count, ppos, fadt, fadt->length);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int __init acpi_system_init(void)
|
||||
static int acpi_system_procfs_init(void)
|
||||
{
|
||||
struct proc_dir_entry *entry;
|
||||
int error = 0;
|
||||
char *name;
|
||||
|
||||
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
/* 'info' [R] */
|
||||
name = ACPI_SYSTEM_FILE_INFO;
|
||||
entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
|
||||
@ -153,7 +257,6 @@ static int __init acpi_system_init(void)
|
||||
else {
|
||||
entry->proc_fops = &acpi_system_info_ops;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 'dsdt' [R] */
|
||||
name = ACPI_SYSTEM_FILE_DSDT;
|
||||
@ -177,12 +280,32 @@ static int __init acpi_system_init(void)
|
||||
Error:
|
||||
remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
|
||||
remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
|
||||
#endif
|
||||
|
||||
error = -EFAULT;
|
||||
goto Done;
|
||||
}
|
||||
#else
|
||||
static int acpi_system_procfs_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int __init acpi_system_init(void)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if (acpi_disabled)
|
||||
return 0;
|
||||
|
||||
result = acpi_system_procfs_init();
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = acpi_system_sysfs_init();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
subsys_initcall(acpi_system_init);
|
||||
|
@ -211,14 +211,17 @@ void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
|
||||
* DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
|
||||
* Performs validation on some important FADT fields.
|
||||
*
|
||||
* NOTE: We create a local copy of the FADT regardless of the version.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
|
||||
{
|
||||
|
||||
/*
|
||||
* Check if the FADT is larger than what we know about (ACPI 2.0 version).
|
||||
* Truncate the table, but make some noise.
|
||||
* Check if the FADT is larger than the largest table that we expect
|
||||
* (the ACPI 2.0/3.0 version). If so, truncate the table, and issue
|
||||
* a warning.
|
||||
*/
|
||||
if (length > sizeof(struct acpi_table_fadt)) {
|
||||
ACPI_WARNING((AE_INFO,
|
||||
@ -227,10 +230,12 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
|
||||
sizeof(struct acpi_table_fadt)));
|
||||
}
|
||||
|
||||
/* Copy the entire FADT locally. Zero first for tb_convert_fadt */
|
||||
/* Clear the entire local FADT */
|
||||
|
||||
ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
|
||||
|
||||
/* Copy the original FADT, up to sizeof (struct acpi_table_fadt) */
|
||||
|
||||
ACPI_MEMCPY(&acpi_gbl_FADT, table,
|
||||
ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
|
||||
|
||||
@ -251,7 +256,7 @@ void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
|
||||
* RETURN: None
|
||||
*
|
||||
* DESCRIPTION: Converts all versions of the FADT to a common internal format.
|
||||
* -> Expand all 32-bit addresses to 64-bit.
|
||||
* Expand all 32-bit addresses to 64-bit.
|
||||
*
|
||||
* NOTE: acpi_gbl_FADT must be of size (struct acpi_table_fadt),
|
||||
* and must contain a copy of the actual FADT.
|
||||
@ -292,8 +297,23 @@ static void acpi_tb_convert_fadt(void)
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
|
||||
* structures as necessary.
|
||||
* For ACPI 1.0 FADTs (revision 1 or 2), ensure that reserved fields which
|
||||
* should be zero are indeed zero. This will workaround BIOSs that
|
||||
* inadvertently place values in these fields.
|
||||
*
|
||||
* The ACPI 1.0 reserved fields that will be zeroed are the bytes located at
|
||||
* offset 45, 55, 95, and the word located at offset 109, 110.
|
||||
*/
|
||||
if (acpi_gbl_FADT.header.revision < 3) {
|
||||
acpi_gbl_FADT.preferred_profile = 0;
|
||||
acpi_gbl_FADT.pstate_control = 0;
|
||||
acpi_gbl_FADT.cst_control = 0;
|
||||
acpi_gbl_FADT.boot_flags = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Expand the ACPI 1.0 32-bit V1.0 addresses to the ACPI 2.0 64-bit "X"
|
||||
* generic address structures as necessary.
|
||||
*/
|
||||
for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
|
||||
target =
|
||||
@ -349,18 +369,6 @@ static void acpi_tb_convert_fadt(void)
|
||||
acpi_gbl_FADT.xpm1a_event_block.space_id;
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* For ACPI 1.0 FADTs, ensure that reserved fields (which should be zero)
|
||||
* are indeed zero. This will workaround BIOSs that inadvertently placed
|
||||
* values in these fields.
|
||||
*/
|
||||
if (acpi_gbl_FADT.header.revision < 3) {
|
||||
acpi_gbl_FADT.preferred_profile = 0;
|
||||
acpi_gbl_FADT.pstate_control = 0;
|
||||
acpi_gbl_FADT.cst_control = 0;
|
||||
acpi_gbl_FADT.boot_flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -62,16 +62,13 @@ acpi_ut_translate_one_cid(union acpi_operand_object *obj_desc,
|
||||
static char *acpi_interfaces_supported[] = {
|
||||
/* Operating System Vendor Strings */
|
||||
|
||||
"Windows 2000",
|
||||
"Windows 2001",
|
||||
"Windows 2001 SP0",
|
||||
"Windows 2001 SP1",
|
||||
"Windows 2001 SP2",
|
||||
"Windows 2001 SP3",
|
||||
"Windows 2001 SP4",
|
||||
"Windows 2001.1",
|
||||
"Windows 2001.1 SP1", /* Added 03/2006 */
|
||||
"Windows 2006", /* Added 03/2006 */
|
||||
"Windows 2000", /* Windows 2000 */
|
||||
"Windows 2001", /* Windows XP */
|
||||
"Windows 2001 SP1", /* Windows XP SP1 */
|
||||
"Windows 2001 SP2", /* Windows XP SP2 */
|
||||
"Windows 2001.1", /* Windows Server 2003 */
|
||||
"Windows 2001.1 SP1", /* Windows Server 2003 SP1 - Added 03/2006 */
|
||||
"Windows 2006", /* Windows Vista - Added 03/2006 */
|
||||
|
||||
/* Feature Group Strings */
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <linux/seq_file.h>
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/video_output.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <acpi/acpi_bus.h>
|
||||
@ -169,6 +170,7 @@ struct acpi_video_device {
|
||||
struct acpi_device *dev;
|
||||
struct acpi_video_device_brightness *brightness;
|
||||
struct backlight_device *backlight;
|
||||
struct output_device *output_dev;
|
||||
};
|
||||
|
||||
/* bus */
|
||||
@ -272,6 +274,10 @@ static int acpi_video_get_next_level(struct acpi_video_device *device,
|
||||
u32 level_current, u32 event);
|
||||
static void acpi_video_switch_brightness(struct acpi_video_device *device,
|
||||
int event);
|
||||
static int acpi_video_device_get_state(struct acpi_video_device *device,
|
||||
unsigned long *state);
|
||||
static int acpi_video_output_get(struct output_device *od);
|
||||
static int acpi_video_device_set_state(struct acpi_video_device *device, int state);
|
||||
|
||||
/*backlight device sysfs support*/
|
||||
static int acpi_video_get_brightness(struct backlight_device *bd)
|
||||
@ -297,6 +303,28 @@ static struct backlight_ops acpi_backlight_ops = {
|
||||
.update_status = acpi_video_set_brightness,
|
||||
};
|
||||
|
||||
/*video output device sysfs support*/
|
||||
static int acpi_video_output_get(struct output_device *od)
|
||||
{
|
||||
unsigned long state;
|
||||
struct acpi_video_device *vd =
|
||||
(struct acpi_video_device *)class_get_devdata(&od->class_dev);
|
||||
acpi_video_device_get_state(vd, &state);
|
||||
return (int)state;
|
||||
}
|
||||
|
||||
static int acpi_video_output_set(struct output_device *od)
|
||||
{
|
||||
unsigned long state = od->request_state;
|
||||
struct acpi_video_device *vd=
|
||||
(struct acpi_video_device *)class_get_devdata(&od->class_dev);
|
||||
return acpi_video_device_set_state(vd, state);
|
||||
}
|
||||
|
||||
static struct output_properties acpi_output_properties = {
|
||||
.set_state = acpi_video_output_set,
|
||||
.get_status = acpi_video_output_get,
|
||||
};
|
||||
/* --------------------------------------------------------------------------
|
||||
Video Management
|
||||
-------------------------------------------------------------------------- */
|
||||
@ -531,7 +559,6 @@ acpi_video_bus_DOS(struct acpi_video_bus *video, int bios_flag, int lcd_flag)
|
||||
|
||||
static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
||||
{
|
||||
acpi_integer status;
|
||||
acpi_handle h_dummy1;
|
||||
int i;
|
||||
u32 max_level = 0;
|
||||
@ -565,50 +592,55 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
||||
device->cap._DSS = 1;
|
||||
}
|
||||
|
||||
status = acpi_video_device_lcd_query_levels(device, &obj);
|
||||
if (ACPI_SUCCESS(acpi_video_device_lcd_query_levels(device, &obj))) {
|
||||
|
||||
if (obj && obj->type == ACPI_TYPE_PACKAGE && obj->package.count >= 2) {
|
||||
int count = 0;
|
||||
union acpi_object *o;
|
||||
if (obj->package.count >= 2) {
|
||||
int count = 0;
|
||||
union acpi_object *o;
|
||||
|
||||
br = kzalloc(sizeof(*br), GFP_KERNEL);
|
||||
if (!br) {
|
||||
printk(KERN_ERR "can't allocate memory\n");
|
||||
} else {
|
||||
br->levels = kmalloc(obj->package.count *
|
||||
sizeof *(br->levels), GFP_KERNEL);
|
||||
if (!br->levels)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < obj->package.count; i++) {
|
||||
o = (union acpi_object *)&obj->package.
|
||||
elements[i];
|
||||
if (o->type != ACPI_TYPE_INTEGER) {
|
||||
printk(KERN_ERR PREFIX "Invalid data\n");
|
||||
continue;
|
||||
}
|
||||
br->levels[count] = (u32) o->integer.value;
|
||||
if (br->levels[count] > max_level)
|
||||
max_level = br->levels[count];
|
||||
count++;
|
||||
}
|
||||
out:
|
||||
if (count < 2) {
|
||||
kfree(br->levels);
|
||||
kfree(br);
|
||||
br = kzalloc(sizeof(*br), GFP_KERNEL);
|
||||
if (!br) {
|
||||
printk(KERN_ERR "can't allocate memory\n");
|
||||
} else {
|
||||
br->count = count;
|
||||
device->brightness = br;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"found %d brightness levels\n",
|
||||
count));
|
||||
br->levels = kmalloc(obj->package.count *
|
||||
sizeof *(br->levels), GFP_KERNEL);
|
||||
if (!br->levels)
|
||||
goto out;
|
||||
|
||||
for (i = 0; i < obj->package.count; i++) {
|
||||
o = (union acpi_object *)&obj->package.
|
||||
elements[i];
|
||||
if (o->type != ACPI_TYPE_INTEGER) {
|
||||
printk(KERN_ERR PREFIX "Invalid data\n");
|
||||
continue;
|
||||
}
|
||||
br->levels[count] = (u32) o->integer.value;
|
||||
|
||||
if (br->levels[count] > max_level)
|
||||
max_level = br->levels[count];
|
||||
count++;
|
||||
}
|
||||
out:
|
||||
if (count < 2) {
|
||||
kfree(br->levels);
|
||||
kfree(br);
|
||||
} else {
|
||||
br->count = count;
|
||||
device->brightness = br;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"found %d brightness levels\n",
|
||||
count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Could not query available LCD brightness level\n"));
|
||||
}
|
||||
|
||||
kfree(obj);
|
||||
|
||||
if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
|
||||
if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
|
||||
unsigned long tmp;
|
||||
static int count = 0;
|
||||
char *name;
|
||||
@ -626,6 +658,17 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
||||
|
||||
kfree(name);
|
||||
}
|
||||
if (device->cap._DCS && device->cap._DSS){
|
||||
static int count = 0;
|
||||
char *name;
|
||||
name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
|
||||
if (!name)
|
||||
return;
|
||||
sprintf(name, "acpi_video%d", count++);
|
||||
device->output_dev = video_output_register(name,
|
||||
NULL, device, &acpi_output_properties);
|
||||
kfree(name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1669,6 +1712,7 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
acpi_video_device_notify);
|
||||
backlight_device_unregister(device->backlight);
|
||||
video_output_unregister(device->output_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -150,6 +150,7 @@ config THINKPAD_ACPI
|
||||
depends on X86 && ACPI
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select HWMON
|
||||
select NVRAM
|
||||
---help---
|
||||
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
||||
support for Fn-Fx key combinations, Bluetooth control, video
|
||||
@ -196,4 +197,17 @@ config THINKPAD_ACPI_BAY
|
||||
|
||||
If you are not sure, say Y here.
|
||||
|
||||
config THINKPAD_ACPI_INPUT_ENABLED
|
||||
bool "Enable input layer support by default"
|
||||
depends on THINKPAD_ACPI
|
||||
default y
|
||||
---help---
|
||||
Enables hot key handling over the input layer by default. If unset,
|
||||
the driver does not enable any hot key handling by default, and also
|
||||
starts up with a mostly empty keymap.
|
||||
|
||||
If you are not sure, say Y here. Say N to retain the deprecated
|
||||
behavior of ibm-acpi, and thinkpad-acpi for kernels up to 2.6.21.
|
||||
|
||||
|
||||
endif # MISC_DEVICES
|
||||
|
@ -142,43 +142,124 @@ struct sony_laptop_keypress {
|
||||
int key;
|
||||
};
|
||||
|
||||
/* Correspondance table between sonypi events and input layer events */
|
||||
static struct {
|
||||
int sonypiev;
|
||||
int inputev;
|
||||
} sony_laptop_inputkeys[] = {
|
||||
{ SONYPI_EVENT_CAPTURE_PRESSED, KEY_CAMERA },
|
||||
{ SONYPI_EVENT_FNKEY_ONLY, KEY_FN },
|
||||
{ SONYPI_EVENT_FNKEY_ESC, KEY_FN_ESC },
|
||||
{ SONYPI_EVENT_FNKEY_F1, KEY_FN_F1 },
|
||||
{ SONYPI_EVENT_FNKEY_F2, KEY_FN_F2 },
|
||||
{ SONYPI_EVENT_FNKEY_F3, KEY_FN_F3 },
|
||||
{ SONYPI_EVENT_FNKEY_F4, KEY_FN_F4 },
|
||||
{ SONYPI_EVENT_FNKEY_F5, KEY_FN_F5 },
|
||||
{ SONYPI_EVENT_FNKEY_F6, KEY_FN_F6 },
|
||||
{ SONYPI_EVENT_FNKEY_F7, KEY_FN_F7 },
|
||||
{ SONYPI_EVENT_FNKEY_F8, KEY_FN_F8 },
|
||||
{ SONYPI_EVENT_FNKEY_F9, KEY_FN_F9 },
|
||||
{ SONYPI_EVENT_FNKEY_F10, KEY_FN_F10 },
|
||||
{ SONYPI_EVENT_FNKEY_F11, KEY_FN_F11 },
|
||||
{ SONYPI_EVENT_FNKEY_F12, KEY_FN_F12 },
|
||||
{ SONYPI_EVENT_FNKEY_1, KEY_FN_1 },
|
||||
{ SONYPI_EVENT_FNKEY_2, KEY_FN_2 },
|
||||
{ SONYPI_EVENT_FNKEY_D, KEY_FN_D },
|
||||
{ SONYPI_EVENT_FNKEY_E, KEY_FN_E },
|
||||
{ SONYPI_EVENT_FNKEY_F, KEY_FN_F },
|
||||
{ SONYPI_EVENT_FNKEY_S, KEY_FN_S },
|
||||
{ SONYPI_EVENT_FNKEY_B, KEY_FN_B },
|
||||
{ SONYPI_EVENT_BLUETOOTH_PRESSED, KEY_BLUE },
|
||||
{ SONYPI_EVENT_BLUETOOTH_ON, KEY_BLUE },
|
||||
{ SONYPI_EVENT_PKEY_P1, KEY_PROG1 },
|
||||
{ SONYPI_EVENT_PKEY_P2, KEY_PROG2 },
|
||||
{ SONYPI_EVENT_PKEY_P3, KEY_PROG3 },
|
||||
{ SONYPI_EVENT_BACK_PRESSED, KEY_BACK },
|
||||
{ SONYPI_EVENT_HELP_PRESSED, KEY_HELP },
|
||||
{ SONYPI_EVENT_ZOOM_PRESSED, KEY_ZOOM },
|
||||
{ SONYPI_EVENT_THUMBPHRASE_PRESSED, BTN_THUMB },
|
||||
{ 0, 0 },
|
||||
/* Correspondance table between sonypi events
|
||||
* and input layer indexes in the keymap
|
||||
*/
|
||||
static int sony_laptop_input_index[] = {
|
||||
-1, /* no event */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_DOWN */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_UP */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_PRESSED */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_RELEASED */
|
||||
0, /* SONYPI_EVENT_CAPTURE_PRESSED */
|
||||
1, /* SONYPI_EVENT_CAPTURE_RELEASED */
|
||||
2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
|
||||
3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
|
||||
4, /* SONYPI_EVENT_FNKEY_ESC */
|
||||
5, /* SONYPI_EVENT_FNKEY_F1 */
|
||||
6, /* SONYPI_EVENT_FNKEY_F2 */
|
||||
7, /* SONYPI_EVENT_FNKEY_F3 */
|
||||
8, /* SONYPI_EVENT_FNKEY_F4 */
|
||||
9, /* SONYPI_EVENT_FNKEY_F5 */
|
||||
10, /* SONYPI_EVENT_FNKEY_F6 */
|
||||
11, /* SONYPI_EVENT_FNKEY_F7 */
|
||||
12, /* SONYPI_EVENT_FNKEY_F8 */
|
||||
13, /* SONYPI_EVENT_FNKEY_F9 */
|
||||
14, /* SONYPI_EVENT_FNKEY_F10 */
|
||||
15, /* SONYPI_EVENT_FNKEY_F11 */
|
||||
16, /* SONYPI_EVENT_FNKEY_F12 */
|
||||
17, /* SONYPI_EVENT_FNKEY_1 */
|
||||
18, /* SONYPI_EVENT_FNKEY_2 */
|
||||
19, /* SONYPI_EVENT_FNKEY_D */
|
||||
20, /* SONYPI_EVENT_FNKEY_E */
|
||||
21, /* SONYPI_EVENT_FNKEY_F */
|
||||
22, /* SONYPI_EVENT_FNKEY_S */
|
||||
23, /* SONYPI_EVENT_FNKEY_B */
|
||||
24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */
|
||||
25, /* SONYPI_EVENT_PKEY_P1 */
|
||||
26, /* SONYPI_EVENT_PKEY_P2 */
|
||||
27, /* SONYPI_EVENT_PKEY_P3 */
|
||||
28, /* SONYPI_EVENT_BACK_PRESSED */
|
||||
-1, /* SONYPI_EVENT_LID_CLOSED */
|
||||
-1, /* SONYPI_EVENT_LID_OPENED */
|
||||
29, /* SONYPI_EVENT_BLUETOOTH_ON */
|
||||
30, /* SONYPI_EVENT_BLUETOOTH_OFF */
|
||||
31, /* SONYPI_EVENT_HELP_PRESSED */
|
||||
32, /* SONYPI_EVENT_FNKEY_ONLY */
|
||||
33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
|
||||
34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */
|
||||
35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
|
||||
36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
|
||||
37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
|
||||
38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
|
||||
39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
|
||||
40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
|
||||
41, /* SONYPI_EVENT_ZOOM_PRESSED */
|
||||
42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
|
||||
43, /* SONYPI_EVENT_MEYE_FACE */
|
||||
44, /* SONYPI_EVENT_MEYE_OPPOSITE */
|
||||
45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */
|
||||
46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */
|
||||
-1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */
|
||||
-1, /* SONYPI_EVENT_BATTERY_INSERT */
|
||||
-1, /* SONYPI_EVENT_BATTERY_REMOVE */
|
||||
-1, /* SONYPI_EVENT_FNKEY_RELEASED */
|
||||
47, /* SONYPI_EVENT_WIRELESS_ON */
|
||||
48, /* SONYPI_EVENT_WIRELESS_OFF */
|
||||
};
|
||||
|
||||
static int sony_laptop_input_keycode_map[] = {
|
||||
KEY_CAMERA, /* 0 SONYPI_EVENT_CAPTURE_PRESSED */
|
||||
KEY_RESERVED, /* 1 SONYPI_EVENT_CAPTURE_RELEASED */
|
||||
KEY_RESERVED, /* 2 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
|
||||
KEY_RESERVED, /* 3 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
|
||||
KEY_FN_ESC, /* 4 SONYPI_EVENT_FNKEY_ESC */
|
||||
KEY_FN_F1, /* 5 SONYPI_EVENT_FNKEY_F1 */
|
||||
KEY_FN_F2, /* 6 SONYPI_EVENT_FNKEY_F2 */
|
||||
KEY_FN_F3, /* 7 SONYPI_EVENT_FNKEY_F3 */
|
||||
KEY_FN_F4, /* 8 SONYPI_EVENT_FNKEY_F4 */
|
||||
KEY_FN_F5, /* 9 SONYPI_EVENT_FNKEY_F5 */
|
||||
KEY_FN_F6, /* 10 SONYPI_EVENT_FNKEY_F6 */
|
||||
KEY_FN_F7, /* 11 SONYPI_EVENT_FNKEY_F7 */
|
||||
KEY_FN_F8, /* 12 SONYPI_EVENT_FNKEY_F8 */
|
||||
KEY_FN_F9, /* 13 SONYPI_EVENT_FNKEY_F9 */
|
||||
KEY_FN_F10, /* 14 SONYPI_EVENT_FNKEY_F10 */
|
||||
KEY_FN_F11, /* 15 SONYPI_EVENT_FNKEY_F11 */
|
||||
KEY_FN_F12, /* 16 SONYPI_EVENT_FNKEY_F12 */
|
||||
KEY_FN_F1, /* 17 SONYPI_EVENT_FNKEY_1 */
|
||||
KEY_FN_F2, /* 18 SONYPI_EVENT_FNKEY_2 */
|
||||
KEY_FN_D, /* 19 SONYPI_EVENT_FNKEY_D */
|
||||
KEY_FN_E, /* 20 SONYPI_EVENT_FNKEY_E */
|
||||
KEY_FN_F, /* 21 SONYPI_EVENT_FNKEY_F */
|
||||
KEY_FN_S, /* 22 SONYPI_EVENT_FNKEY_S */
|
||||
KEY_FN_B, /* 23 SONYPI_EVENT_FNKEY_B */
|
||||
KEY_BLUETOOTH, /* 24 SONYPI_EVENT_BLUETOOTH_PRESSED */
|
||||
KEY_PROG1, /* 25 SONYPI_EVENT_PKEY_P1 */
|
||||
KEY_PROG2, /* 26 SONYPI_EVENT_PKEY_P2 */
|
||||
KEY_PROG3, /* 27 SONYPI_EVENT_PKEY_P3 */
|
||||
KEY_BACK, /* 28 SONYPI_EVENT_BACK_PRESSED */
|
||||
KEY_BLUETOOTH, /* 29 SONYPI_EVENT_BLUETOOTH_ON */
|
||||
KEY_BLUETOOTH, /* 30 SONYPI_EVENT_BLUETOOTH_OFF */
|
||||
KEY_HELP, /* 31 SONYPI_EVENT_HELP_PRESSED */
|
||||
KEY_FN, /* 32 SONYPI_EVENT_FNKEY_ONLY */
|
||||
KEY_RESERVED, /* 33 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
|
||||
KEY_RESERVED, /* 34 SONYPI_EVENT_JOGDIAL_FAST_UP */
|
||||
KEY_RESERVED, /* 35 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
|
||||
KEY_RESERVED, /* 36 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
|
||||
KEY_RESERVED, /* 37 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
|
||||
KEY_RESERVED, /* 38 SONYPI_EVENT_JOGDIAL_VFAST_UP */
|
||||
KEY_RESERVED, /* 39 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
|
||||
KEY_RESERVED, /* 40 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
|
||||
KEY_ZOOM, /* 41 SONYPI_EVENT_ZOOM_PRESSED */
|
||||
BTN_THUMB, /* 42 SONYPI_EVENT_THUMBPHRASE_PRESSED */
|
||||
KEY_RESERVED, /* 43 SONYPI_EVENT_MEYE_FACE */
|
||||
KEY_RESERVED, /* 44 SONYPI_EVENT_MEYE_OPPOSITE */
|
||||
KEY_RESERVED, /* 45 SONYPI_EVENT_MEMORYSTICK_INSERT */
|
||||
KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
|
||||
KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
|
||||
KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */
|
||||
};
|
||||
|
||||
/* release buttons after a short delay if pressed */
|
||||
@ -202,7 +283,6 @@ static void sony_laptop_report_input_event(u8 event)
|
||||
struct input_dev *jog_dev = sony_laptop_input.jog_dev;
|
||||
struct input_dev *key_dev = sony_laptop_input.key_dev;
|
||||
struct sony_laptop_keypress kp = { NULL };
|
||||
int i;
|
||||
|
||||
if (event == SONYPI_EVENT_FNKEY_RELEASED) {
|
||||
/* Nothing, not all VAIOs generate this event */
|
||||
@ -231,17 +311,22 @@ static void sony_laptop_report_input_event(u8 event)
|
||||
break;
|
||||
|
||||
default:
|
||||
for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
|
||||
if (event == sony_laptop_inputkeys[i].sonypiev) {
|
||||
if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) {
|
||||
dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
|
||||
break;
|
||||
}
|
||||
if (sony_laptop_input_index[event] != -1) {
|
||||
kp.key = sony_laptop_input_keycode_map[sony_laptop_input_index[event]];
|
||||
if (kp.key != KEY_UNKNOWN)
|
||||
kp.dev = key_dev;
|
||||
kp.key = sony_laptop_inputkeys[i].inputev;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (kp.dev) {
|
||||
input_report_key(kp.dev, kp.key, 1);
|
||||
/* we emit the scancode so we can always remap the key */
|
||||
input_event(kp.dev, EV_MSC, MSC_SCAN, event);
|
||||
input_sync(kp.dev);
|
||||
kfifo_put(sony_laptop_input.fifo,
|
||||
(unsigned char *)&kp, sizeof(kp));
|
||||
@ -296,11 +381,18 @@ static int sony_laptop_setup_input(void)
|
||||
key_dev->id.vendor = PCI_VENDOR_ID_SONY;
|
||||
|
||||
/* Initialize the Input Drivers: special keys */
|
||||
key_dev->evbit[0] = BIT(EV_KEY);
|
||||
for (i = 0; sony_laptop_inputkeys[i].sonypiev; i++)
|
||||
if (sony_laptop_inputkeys[i].inputev)
|
||||
set_bit(sony_laptop_inputkeys[i].inputev,
|
||||
key_dev->keybit);
|
||||
set_bit(EV_KEY, key_dev->evbit);
|
||||
set_bit(EV_MSC, key_dev->evbit);
|
||||
set_bit(MSC_SCAN, key_dev->mscbit);
|
||||
key_dev->keycodesize = sizeof(sony_laptop_input_keycode_map[0]);
|
||||
key_dev->keycodemax = ARRAY_SIZE(sony_laptop_input_keycode_map);
|
||||
key_dev->keycode = &sony_laptop_input_keycode_map;
|
||||
for (i = 0; i < ARRAY_SIZE(sony_laptop_input_keycode_map); i++) {
|
||||
if (sony_laptop_input_keycode_map[i] != KEY_RESERVED) {
|
||||
set_bit(sony_laptop_input_keycode_map[i],
|
||||
key_dev->keybit);
|
||||
}
|
||||
}
|
||||
|
||||
error = input_register_device(key_dev);
|
||||
if (error)
|
||||
@ -487,6 +579,14 @@ SNC_HANDLE_NAMES(audiopower_set, "AZPW");
|
||||
SNC_HANDLE_NAMES(lanpower_get, "GLNP");
|
||||
SNC_HANDLE_NAMES(lanpower_set, "LNPW");
|
||||
|
||||
SNC_HANDLE_NAMES(lidstate_get, "GLID");
|
||||
|
||||
SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");
|
||||
SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");
|
||||
|
||||
SNC_HANDLE_NAMES(gainbass_get, "GMGB");
|
||||
SNC_HANDLE_NAMES(gainbass_set, "CMGB");
|
||||
|
||||
SNC_HANDLE_NAMES(PID_get, "GPID");
|
||||
|
||||
SNC_HANDLE_NAMES(CTR_get, "GCTR");
|
||||
@ -507,6 +607,12 @@ static struct sony_nc_value sony_nc_values[] = {
|
||||
boolean_validate, 0),
|
||||
SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
|
||||
boolean_validate, 1),
|
||||
SNC_HANDLE(lidstate, snc_lidstate_get, NULL,
|
||||
boolean_validate, 0),
|
||||
SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set,
|
||||
boolean_validate, 0),
|
||||
SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set,
|
||||
boolean_validate, 0),
|
||||
/* unknown methods */
|
||||
SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1),
|
||||
SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1),
|
||||
@ -688,14 +794,117 @@ static struct backlight_ops sony_backlight_ops = {
|
||||
.get_brightness = sony_backlight_get_brightness,
|
||||
};
|
||||
|
||||
/*
|
||||
* New SNC-only Vaios event mapping to driver known keys
|
||||
*/
|
||||
struct sony_nc_event {
|
||||
u8 data;
|
||||
u8 event;
|
||||
};
|
||||
|
||||
static struct sony_nc_event *sony_nc_events;
|
||||
|
||||
/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence
|
||||
* for Fn keys
|
||||
*/
|
||||
static int sony_nc_C_enable(struct dmi_system_id *id)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident);
|
||||
|
||||
sony_nc_events = id->driver_data;
|
||||
|
||||
if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0
|
||||
|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0
|
||||
|| acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0
|
||||
|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0
|
||||
|| acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0
|
||||
|| acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) {
|
||||
printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some "
|
||||
"functionalities may be missing\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sony_nc_event sony_C_events[] = {
|
||||
{ 0x81, SONYPI_EVENT_FNKEY_F1 },
|
||||
{ 0x01, SONYPI_EVENT_FNKEY_RELEASED },
|
||||
{ 0x85, SONYPI_EVENT_FNKEY_F5 },
|
||||
{ 0x05, SONYPI_EVENT_FNKEY_RELEASED },
|
||||
{ 0x86, SONYPI_EVENT_FNKEY_F6 },
|
||||
{ 0x06, SONYPI_EVENT_FNKEY_RELEASED },
|
||||
{ 0x87, SONYPI_EVENT_FNKEY_F7 },
|
||||
{ 0x07, SONYPI_EVENT_FNKEY_RELEASED },
|
||||
{ 0x8A, SONYPI_EVENT_FNKEY_F10 },
|
||||
{ 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
|
||||
{ 0x8C, SONYPI_EVENT_FNKEY_F12 },
|
||||
{ 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
|
||||
{ 0, 0 },
|
||||
};
|
||||
|
||||
/* SNC-only model map */
|
||||
struct dmi_system_id sony_nc_ids[] = {
|
||||
{
|
||||
.ident = "Sony Vaio FE Series",
|
||||
.callback = sony_nc_C_enable,
|
||||
.driver_data = sony_C_events,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.ident = "Sony Vaio C Series",
|
||||
.callback = sony_nc_C_enable,
|
||||
.driver_data = sony_C_events,
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* ACPI callbacks
|
||||
*/
|
||||
static void sony_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
dprintk("sony_acpi_notify, event: %d\n", event);
|
||||
sony_laptop_report_input_event(event);
|
||||
acpi_bus_generate_event(sony_nc_acpi_device, 1, event);
|
||||
struct sony_nc_event *evmap;
|
||||
u32 ev = event;
|
||||
int result;
|
||||
|
||||
if (ev == 0x92) {
|
||||
/* read the key pressed from EC.GECR
|
||||
* A call to SN07 with 0x0202 will do it as well respecting
|
||||
* the current protocol on different OSes
|
||||
*
|
||||
* Note: the path for GECR may be
|
||||
* \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends)
|
||||
* \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR)
|
||||
*
|
||||
* TODO: we may want to do the same for the older GHKE -need
|
||||
* dmi list- so this snippet may become one more callback.
|
||||
*/
|
||||
if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0)
|
||||
dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev);
|
||||
else
|
||||
ev = result & 0xFF;
|
||||
}
|
||||
|
||||
if (sony_nc_events)
|
||||
for (evmap = sony_nc_events; evmap->event; evmap++) {
|
||||
if (evmap->data == ev) {
|
||||
ev = evmap->event;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dprintk("sony_acpi_notify, event: 0x%.2x\n", ev);
|
||||
sony_laptop_report_input_event(ev);
|
||||
acpi_bus_generate_event(sony_nc_acpi_device, 1, ev);
|
||||
}
|
||||
|
||||
static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
|
||||
@ -732,6 +941,10 @@ static int sony_nc_resume(struct acpi_device *device)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* re-initialize models with specific requirements */
|
||||
dmi_check_system(sony_nc_ids);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -750,6 +963,15 @@ static int sony_nc_add(struct acpi_device *device)
|
||||
|
||||
sony_nc_acpi_handle = device->handle;
|
||||
|
||||
/* read device status */
|
||||
result = acpi_bus_get_status(device);
|
||||
/* bail IFF the above call was successful and the device is not present */
|
||||
if (!result && !device->status.present) {
|
||||
dprintk("Device not present\n");
|
||||
result = -ENODEV;
|
||||
goto outwalk;
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
|
||||
1, sony_walk_callback, NULL, NULL);
|
||||
@ -760,6 +982,15 @@ static int sony_nc_add(struct acpi_device *device)
|
||||
}
|
||||
}
|
||||
|
||||
/* try to _INI the device if such method exists (ACPI spec 3.0-6.5.1
|
||||
* should be respected as we already checked for the device presence above */
|
||||
if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, METHOD_NAME__INI, &handle))) {
|
||||
dprintk("Invoking _INI\n");
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(sony_nc_acpi_handle, METHOD_NAME__INI,
|
||||
NULL, NULL)))
|
||||
dprintk("_INI Method failed\n");
|
||||
}
|
||||
|
||||
/* setup input devices and helper fifo */
|
||||
result = sony_laptop_setup_input();
|
||||
if (result) {
|
||||
@ -772,7 +1003,7 @@ static int sony_nc_add(struct acpi_device *device)
|
||||
ACPI_DEVICE_NOTIFY,
|
||||
sony_acpi_notify, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_WARNING DRV_PFX "unable to install notify handler\n");
|
||||
printk(KERN_WARNING DRV_PFX "unable to install notify handler (%u)\n", status);
|
||||
result = -ENODEV;
|
||||
goto outinput;
|
||||
}
|
||||
@ -795,6 +1026,9 @@ static int sony_nc_add(struct acpi_device *device)
|
||||
|
||||
}
|
||||
|
||||
/* initialize models with specific requirements */
|
||||
dmi_check_system(sony_nc_ids);
|
||||
|
||||
result = sony_pf_add();
|
||||
if (result)
|
||||
goto outbacklight;
|
||||
@ -908,7 +1142,9 @@ static struct acpi_driver sony_nc_driver = {
|
||||
#define SONYPI_DEVICE_TYPE2 0x00000002
|
||||
#define SONYPI_DEVICE_TYPE3 0x00000004
|
||||
|
||||
#define SONY_PIC_EV_MASK 0xff
|
||||
#define SONYPI_TYPE1_OFFSET 0x04
|
||||
#define SONYPI_TYPE2_OFFSET 0x12
|
||||
#define SONYPI_TYPE3_OFFSET 0x12
|
||||
|
||||
struct sony_pic_ioport {
|
||||
struct acpi_resource_io io;
|
||||
@ -922,6 +1158,7 @@ struct sony_pic_irq {
|
||||
|
||||
struct sony_pic_dev {
|
||||
int model;
|
||||
u16 evport_offset;
|
||||
u8 camera_power;
|
||||
u8 bluetooth_power;
|
||||
u8 wwan_power;
|
||||
@ -1999,20 +2236,17 @@ end:
|
||||
static irqreturn_t sony_pic_irq(int irq, void *dev_id)
|
||||
{
|
||||
int i, j;
|
||||
u32 port_val = 0;
|
||||
u8 ev = 0;
|
||||
u8 data_mask = 0;
|
||||
u8 device_event = 0;
|
||||
|
||||
struct sony_pic_dev *dev = (struct sony_pic_dev *) dev_id;
|
||||
|
||||
acpi_os_read_port(dev->cur_ioport->io.minimum, &port_val,
|
||||
dev->cur_ioport->io.address_length);
|
||||
ev = port_val & SONY_PIC_EV_MASK;
|
||||
data_mask = 0xff & (port_val >> (dev->cur_ioport->io.address_length - 8));
|
||||
ev = inb_p(dev->cur_ioport->io.minimum);
|
||||
data_mask = inb_p(dev->cur_ioport->io.minimum + dev->evport_offset);
|
||||
|
||||
dprintk("event (0x%.8x [%.2x] [%.2x]) at port 0x%.4x\n",
|
||||
port_val, ev, data_mask, dev->cur_ioport->io.minimum);
|
||||
dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
|
||||
ev, data_mask, dev->cur_ioport->io.minimum, dev->evport_offset);
|
||||
|
||||
if (ev == 0x00 || ev == 0xff)
|
||||
return IRQ_HANDLED;
|
||||
@ -2103,6 +2337,20 @@ static int sony_pic_add(struct acpi_device *device)
|
||||
spic_dev.model = sony_pic_detect_device_type();
|
||||
mutex_init(&spic_dev.lock);
|
||||
|
||||
/* model specific characteristics */
|
||||
switch(spic_dev.model) {
|
||||
case SONYPI_DEVICE_TYPE1:
|
||||
spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
|
||||
break;
|
||||
case SONYPI_DEVICE_TYPE3:
|
||||
spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
|
||||
break;
|
||||
case SONYPI_DEVICE_TYPE2:
|
||||
default:
|
||||
spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read _PRS resources */
|
||||
result = sony_pic_possible_resources(device);
|
||||
if (result) {
|
||||
|
@ -21,8 +21,8 @@
|
||||
* 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#define IBM_VERSION "0.14"
|
||||
#define TPACPI_SYSFS_VERSION 0x000100
|
||||
#define IBM_VERSION "0.15"
|
||||
#define TPACPI_SYSFS_VERSION 0x010000
|
||||
|
||||
/*
|
||||
* Changelog:
|
||||
@ -92,6 +92,29 @@ MODULE_LICENSE("GPL");
|
||||
/* Please remove this in year 2009 */
|
||||
MODULE_ALIAS("ibm_acpi");
|
||||
|
||||
/*
|
||||
* DMI matching for module autoloading
|
||||
*
|
||||
* See http://thinkwiki.org/wiki/List_of_DMI_IDs
|
||||
* See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
|
||||
*
|
||||
* Only models listed in thinkwiki will be supported, so add yours
|
||||
* if it is not there yet.
|
||||
*/
|
||||
#define IBM_BIOS_MODULE_ALIAS(__type) \
|
||||
MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")
|
||||
|
||||
/* Non-ancient thinkpads */
|
||||
MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");
|
||||
MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");
|
||||
|
||||
/* Ancient thinkpad BIOSes have to be identified by
|
||||
* BIOS type or model number, and there are far less
|
||||
* BIOS types than model numbers... */
|
||||
IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");
|
||||
IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");
|
||||
IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");
|
||||
|
||||
#define __unused __attribute__ ((unused))
|
||||
|
||||
/****************************************************************************
|
||||
@ -106,7 +129,7 @@ MODULE_ALIAS("ibm_acpi");
|
||||
* ACPI basic handles
|
||||
*/
|
||||
|
||||
static acpi_handle root_handle = NULL;
|
||||
static acpi_handle root_handle;
|
||||
|
||||
#define IBM_HANDLE(object, parent, paths...) \
|
||||
static acpi_handle object##_handle; \
|
||||
@ -487,19 +510,36 @@ static char *next_cmd(char **cmds)
|
||||
/****************************************************************************
|
||||
****************************************************************************
|
||||
*
|
||||
* Device model: hwmon and platform
|
||||
* Device model: input, hwmon and platform
|
||||
*
|
||||
****************************************************************************
|
||||
****************************************************************************/
|
||||
|
||||
static struct platform_device *tpacpi_pdev = NULL;
|
||||
static struct class_device *tpacpi_hwmon = NULL;
|
||||
static struct platform_device *tpacpi_pdev;
|
||||
static struct class_device *tpacpi_hwmon;
|
||||
static struct input_dev *tpacpi_inputdev;
|
||||
|
||||
|
||||
static int tpacpi_resume_handler(struct platform_device *pdev)
|
||||
{
|
||||
struct ibm_struct *ibm, *itmp;
|
||||
|
||||
list_for_each_entry_safe(ibm, itmp,
|
||||
&tpacpi_all_drivers,
|
||||
all_drivers) {
|
||||
if (ibm->resume)
|
||||
(ibm->resume)();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tpacpi_pdriver = {
|
||||
.driver = {
|
||||
.name = IBM_DRVR_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.resume = tpacpi_resume_handler,
|
||||
};
|
||||
|
||||
|
||||
@ -677,9 +717,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
|
||||
printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
|
||||
printk(IBM_INFO "%s\n", IBM_URL);
|
||||
|
||||
if (ibm_thinkpad_ec_found)
|
||||
printk(IBM_INFO "ThinkPad EC firmware %s\n",
|
||||
ibm_thinkpad_ec_found);
|
||||
printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
|
||||
(thinkpad_id.bios_version_str) ?
|
||||
thinkpad_id.bios_version_str : "unknown",
|
||||
(thinkpad_id.ec_version_str) ?
|
||||
thinkpad_id.ec_version_str : "unknown");
|
||||
|
||||
if (thinkpad_id.vendor && thinkpad_id.model_str)
|
||||
printk(IBM_INFO "%s %s\n",
|
||||
(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
|
||||
"IBM" : ((thinkpad_id.vendor ==
|
||||
PCI_VENDOR_ID_LENOVO) ?
|
||||
"Lenovo" : "Unknown vendor"),
|
||||
thinkpad_id.model_str);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -704,16 +754,28 @@ static struct ibm_struct thinkpad_acpi_driver_data = {
|
||||
*/
|
||||
|
||||
static int hotkey_orig_status;
|
||||
static int hotkey_orig_mask;
|
||||
static u32 hotkey_orig_mask;
|
||||
static u32 hotkey_all_mask;
|
||||
static u32 hotkey_reserved_mask;
|
||||
|
||||
static struct attribute_set *hotkey_dev_attributes = NULL;
|
||||
static u16 *hotkey_keycode_map;
|
||||
|
||||
static struct attribute_set *hotkey_dev_attributes;
|
||||
|
||||
static int hotkey_get_wlsw(int *status)
|
||||
{
|
||||
if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* sysfs hotkey enable ------------------------------------------------- */
|
||||
static ssize_t hotkey_enable_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int res, status, mask;
|
||||
int res, status;
|
||||
u32 mask;
|
||||
|
||||
res = hotkey_get(&status, &mask);
|
||||
if (res)
|
||||
@ -727,7 +789,8 @@ static ssize_t hotkey_enable_store(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
int res, status, mask;
|
||||
int res, status;
|
||||
u32 mask;
|
||||
|
||||
if (parse_strtoul(buf, 1, &t))
|
||||
return -EINVAL;
|
||||
@ -748,13 +811,14 @@ static ssize_t hotkey_mask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int res, status, mask;
|
||||
int res, status;
|
||||
u32 mask;
|
||||
|
||||
res = hotkey_get(&status, &mask);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%04x\n", mask);
|
||||
return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);
|
||||
}
|
||||
|
||||
static ssize_t hotkey_mask_store(struct device *dev,
|
||||
@ -762,9 +826,10 @@ static ssize_t hotkey_mask_store(struct device *dev,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned long t;
|
||||
int res, status, mask;
|
||||
int res, status;
|
||||
u32 mask;
|
||||
|
||||
if (parse_strtoul(buf, 0xffff, &t))
|
||||
if (parse_strtoul(buf, 0xffffffffUL, &t))
|
||||
return -EINVAL;
|
||||
|
||||
res = hotkey_get(&status, &mask);
|
||||
@ -794,26 +859,123 @@ static ssize_t hotkey_bios_mask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "0x%04x\n", hotkey_orig_mask);
|
||||
return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_bios_mask =
|
||||
__ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);
|
||||
|
||||
/* sysfs hotkey all_mask ----------------------------------------------- */
|
||||
static ssize_t hotkey_all_mask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_all_mask =
|
||||
__ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);
|
||||
|
||||
/* sysfs hotkey recommended_mask --------------------------------------- */
|
||||
static ssize_t hotkey_recommended_mask_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "0x%08x\n",
|
||||
hotkey_all_mask & ~hotkey_reserved_mask);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_recommended_mask =
|
||||
__ATTR(hotkey_recommended_mask, S_IRUGO,
|
||||
hotkey_recommended_mask_show, NULL);
|
||||
|
||||
/* sysfs hotkey radio_sw ----------------------------------------------- */
|
||||
static ssize_t hotkey_radio_sw_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int res, s;
|
||||
res = hotkey_get_wlsw(&s);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_radio_sw =
|
||||
__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static struct attribute *hotkey_mask_attributes[] = {
|
||||
&dev_attr_hotkey_mask.attr,
|
||||
&dev_attr_hotkey_bios_enabled.attr,
|
||||
&dev_attr_hotkey_bios_mask.attr,
|
||||
&dev_attr_hotkey_all_mask.attr,
|
||||
&dev_attr_hotkey_recommended_mask.attr,
|
||||
};
|
||||
|
||||
static int __init hotkey_init(struct ibm_init_struct *iibm)
|
||||
{
|
||||
int res;
|
||||
|
||||
static u16 ibm_keycode_map[] __initdata = {
|
||||
/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
|
||||
KEY_FN_F1, KEY_FN_F2, KEY_COFFEE, KEY_SLEEP,
|
||||
KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
|
||||
KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
|
||||
/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
|
||||
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
|
||||
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
|
||||
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
|
||||
KEY_RESERVED, /* 0x0F: FN+HOME (brightness up) */
|
||||
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
|
||||
KEY_RESERVED, /* 0x10: FN+END (brightness down) */
|
||||
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
|
||||
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
|
||||
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
|
||||
KEY_RESERVED, /* 0x14: VOLUME UP */
|
||||
KEY_RESERVED, /* 0x15: VOLUME DOWN */
|
||||
KEY_RESERVED, /* 0x16: MUTE */
|
||||
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
|
||||
/* (assignments unknown, please report if found) */
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
};
|
||||
static u16 lenovo_keycode_map[] __initdata = {
|
||||
/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
|
||||
KEY_FN_F1, KEY_COFFEE, KEY_BATTERY, KEY_SLEEP,
|
||||
KEY_WLAN, KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,
|
||||
KEY_FN_F9, KEY_FN_F10, KEY_FN_F11, KEY_SUSPEND,
|
||||
/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */
|
||||
KEY_UNKNOWN, /* 0x0C: FN+BACKSPACE */
|
||||
KEY_UNKNOWN, /* 0x0D: FN+INSERT */
|
||||
KEY_UNKNOWN, /* 0x0E: FN+DELETE */
|
||||
KEY_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
|
||||
/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
|
||||
KEY_BRIGHTNESSDOWN, /* 0x10: FN+END (brightness down) */
|
||||
KEY_RESERVED, /* 0x11: FN+PGUP (thinklight toggle) */
|
||||
KEY_UNKNOWN, /* 0x12: FN+PGDOWN */
|
||||
KEY_ZOOM, /* 0x13: FN+SPACE (zoom) */
|
||||
KEY_RESERVED, /* 0x14: VOLUME UP */
|
||||
KEY_RESERVED, /* 0x15: VOLUME DOWN */
|
||||
KEY_RESERVED, /* 0x16: MUTE */
|
||||
KEY_VENDOR, /* 0x17: Thinkpad/AccessIBM/Lenovo */
|
||||
/* (assignments unknown, please report if found) */
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
};
|
||||
|
||||
#define TPACPI_HOTKEY_MAP_LEN ARRAY_SIZE(ibm_keycode_map)
|
||||
#define TPACPI_HOTKEY_MAP_SIZE sizeof(ibm_keycode_map)
|
||||
#define TPACPI_HOTKEY_MAP_TYPESIZE sizeof(ibm_keycode_map[0])
|
||||
|
||||
int res, i;
|
||||
int status;
|
||||
|
||||
vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");
|
||||
|
||||
BUG_ON(!tpacpi_inputdev);
|
||||
|
||||
IBM_ACPIHANDLE_INIT(hkey);
|
||||
mutex_init(&hotkey_mutex);
|
||||
|
||||
@ -824,7 +986,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
||||
str_supported(tp_features.hotkey));
|
||||
|
||||
if (tp_features.hotkey) {
|
||||
hotkey_dev_attributes = create_attr_set(4, NULL);
|
||||
hotkey_dev_attributes = create_attr_set(7, NULL);
|
||||
if (!hotkey_dev_attributes)
|
||||
return -ENOMEM;
|
||||
res = add_to_attr_set(hotkey_dev_attributes,
|
||||
@ -840,19 +1002,92 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
||||
vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",
|
||||
str_supported(tp_features.hotkey_mask));
|
||||
|
||||
if (tp_features.hotkey_mask) {
|
||||
/* MHKA available in A31, R40, R40e, T4x, X31, and later */
|
||||
if (!acpi_evalf(hkey_handle, &hotkey_all_mask,
|
||||
"MHKA", "qd"))
|
||||
hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */
|
||||
}
|
||||
|
||||
res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask);
|
||||
if (!res && tp_features.hotkey_mask) {
|
||||
res = add_many_to_attr_set(hotkey_dev_attributes,
|
||||
hotkey_mask_attributes,
|
||||
ARRAY_SIZE(hotkey_mask_attributes));
|
||||
}
|
||||
|
||||
/* Not all thinkpads have a hardware radio switch */
|
||||
if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) {
|
||||
tp_features.hotkey_wlsw = 1;
|
||||
printk(IBM_INFO
|
||||
"radio switch found; radios are %s\n",
|
||||
enabled(status, 0));
|
||||
res = add_to_attr_set(hotkey_dev_attributes,
|
||||
&dev_attr_hotkey_radio_sw.attr);
|
||||
}
|
||||
|
||||
if (!res)
|
||||
res = register_attr_set_with_sysfs(
|
||||
hotkey_dev_attributes,
|
||||
&tpacpi_pdev->dev.kobj);
|
||||
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
/* Set up key map */
|
||||
|
||||
hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE,
|
||||
GFP_KERNEL);
|
||||
if (!hotkey_keycode_map) {
|
||||
printk(IBM_ERR "failed to allocate memory for key map\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) {
|
||||
dbg_printk(TPACPI_DBG_INIT,
|
||||
"using Lenovo default hot key map\n");
|
||||
memcpy(hotkey_keycode_map, &lenovo_keycode_map,
|
||||
TPACPI_HOTKEY_MAP_SIZE);
|
||||
} else {
|
||||
dbg_printk(TPACPI_DBG_INIT,
|
||||
"using IBM default hot key map\n");
|
||||
memcpy(hotkey_keycode_map, &ibm_keycode_map,
|
||||
TPACPI_HOTKEY_MAP_SIZE);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
|
||||
for (i = 0; i < 12; i++)
|
||||
hotkey_keycode_map[i] = KEY_UNKNOWN;
|
||||
#endif /* ! CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
|
||||
|
||||
set_bit(EV_KEY, tpacpi_inputdev->evbit);
|
||||
set_bit(EV_MSC, tpacpi_inputdev->evbit);
|
||||
set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
|
||||
tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE;
|
||||
tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN;
|
||||
tpacpi_inputdev->keycode = hotkey_keycode_map;
|
||||
for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) {
|
||||
if (hotkey_keycode_map[i] != KEY_RESERVED) {
|
||||
set_bit(hotkey_keycode_map[i],
|
||||
tpacpi_inputdev->keybit);
|
||||
} else {
|
||||
if (i < sizeof(hotkey_reserved_mask)*8)
|
||||
hotkey_reserved_mask |= 1 << i;
|
||||
}
|
||||
}
|
||||
|
||||
if (tp_features.hotkey_wlsw) {
|
||||
set_bit(EV_SW, tpacpi_inputdev->evbit);
|
||||
set_bit(SW_RADIO, tpacpi_inputdev->swbit);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
|
||||
dbg_printk(TPACPI_DBG_INIT,
|
||||
"enabling hot key handling\n");
|
||||
res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask)
|
||||
| hotkey_orig_mask);
|
||||
if (res)
|
||||
return res;
|
||||
#endif /* CONFIG_THINKPAD_ACPI_INPUT_ENABLED */
|
||||
}
|
||||
|
||||
return (tp_features.hotkey)? 0 : 1;
|
||||
@ -875,22 +1110,101 @@ static void hotkey_exit(void)
|
||||
}
|
||||
}
|
||||
|
||||
static void tpacpi_input_send_key(unsigned int scancode,
|
||||
unsigned int keycode)
|
||||
{
|
||||
if (keycode != KEY_RESERVED) {
|
||||
input_report_key(tpacpi_inputdev, keycode, 1);
|
||||
if (keycode == KEY_UNKNOWN)
|
||||
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
|
||||
scancode);
|
||||
input_sync(tpacpi_inputdev);
|
||||
|
||||
input_report_key(tpacpi_inputdev, keycode, 0);
|
||||
if (keycode == KEY_UNKNOWN)
|
||||
input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN,
|
||||
scancode);
|
||||
input_sync(tpacpi_inputdev);
|
||||
}
|
||||
}
|
||||
|
||||
static void tpacpi_input_send_radiosw(void)
|
||||
{
|
||||
int wlsw;
|
||||
|
||||
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw))
|
||||
input_report_switch(tpacpi_inputdev,
|
||||
SW_RADIO, !!wlsw);
|
||||
}
|
||||
|
||||
static void hotkey_notify(struct ibm_struct *ibm, u32 event)
|
||||
{
|
||||
int hkey;
|
||||
u32 hkey;
|
||||
unsigned int keycode, scancode;
|
||||
int sendacpi = 1;
|
||||
|
||||
if (acpi_evalf(hkey_handle, &hkey, "MHKP", "d"))
|
||||
acpi_bus_generate_event(ibm->acpi->device, event, hkey);
|
||||
else {
|
||||
printk(IBM_ERR "unknown hotkey event %d\n", event);
|
||||
if (event == 0x80 && acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) {
|
||||
if (tpacpi_inputdev->users > 0) {
|
||||
switch (hkey >> 12) {
|
||||
case 1:
|
||||
/* 0x1000-0x1FFF: key presses */
|
||||
scancode = hkey & 0xfff;
|
||||
if (scancode > 0 && scancode < 0x21) {
|
||||
scancode--;
|
||||
keycode = hotkey_keycode_map[scancode];
|
||||
tpacpi_input_send_key(scancode, keycode);
|
||||
sendacpi = (keycode == KEY_RESERVED
|
||||
|| keycode == KEY_UNKNOWN);
|
||||
} else {
|
||||
printk(IBM_ERR
|
||||
"hotkey 0x%04x out of range for keyboard map\n",
|
||||
hkey);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
/* 0x5000-0x5FFF: LID */
|
||||
/* we don't handle it through this path, just
|
||||
* eat up known LID events */
|
||||
if (hkey != 0x5001 && hkey != 0x5002) {
|
||||
printk(IBM_ERR
|
||||
"unknown LID-related hotkey event: 0x%04x\n",
|
||||
hkey);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
/* 0x7000-0x7FFF: misc */
|
||||
if (tp_features.hotkey_wlsw && hkey == 0x7000) {
|
||||
tpacpi_input_send_radiosw();
|
||||
sendacpi = 0;
|
||||
break;
|
||||
}
|
||||
/* fallthrough to default */
|
||||
default:
|
||||
/* case 2: dock-related */
|
||||
/* 0x2305 - T43 waking up due to bay lever eject while aslept */
|
||||
/* case 3: ultra-bay related. maybe bay in dock? */
|
||||
/* 0x3003 - T43 after wake up by bay lever eject (0x2305) */
|
||||
printk(IBM_NOTICE "unhandled hotkey event 0x%04x\n", hkey);
|
||||
}
|
||||
}
|
||||
|
||||
if (sendacpi)
|
||||
acpi_bus_generate_event(ibm->acpi->device, event, hkey);
|
||||
} else {
|
||||
printk(IBM_ERR "unknown hotkey notification event %d\n", event);
|
||||
acpi_bus_generate_event(ibm->acpi->device, event, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static void hotkey_resume(void)
|
||||
{
|
||||
tpacpi_input_send_radiosw();
|
||||
}
|
||||
|
||||
/*
|
||||
* Call with hotkey_mutex held
|
||||
*/
|
||||
static int hotkey_get(int *status, int *mask)
|
||||
static int hotkey_get(int *status, u32 *mask)
|
||||
{
|
||||
if (!acpi_evalf(hkey_handle, status, "DHKC", "d"))
|
||||
return -EIO;
|
||||
@ -905,7 +1219,7 @@ static int hotkey_get(int *status, int *mask)
|
||||
/*
|
||||
* Call with hotkey_mutex held
|
||||
*/
|
||||
static int hotkey_set(int status, int mask)
|
||||
static int hotkey_set(int status, u32 mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -926,7 +1240,8 @@ static int hotkey_set(int status, int mask)
|
||||
/* procfs -------------------------------------------------------------- */
|
||||
static int hotkey_read(char *p)
|
||||
{
|
||||
int res, status, mask;
|
||||
int res, status;
|
||||
u32 mask;
|
||||
int len = 0;
|
||||
|
||||
if (!tp_features.hotkey) {
|
||||
@ -944,7 +1259,7 @@ static int hotkey_read(char *p)
|
||||
|
||||
len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0));
|
||||
if (tp_features.hotkey_mask) {
|
||||
len += sprintf(p + len, "mask:\t\t0x%04x\n", mask);
|
||||
len += sprintf(p + len, "mask:\t\t0x%08x\n", mask);
|
||||
len += sprintf(p + len,
|
||||
"commands:\tenable, disable, reset, <mask>\n");
|
||||
} else {
|
||||
@ -957,7 +1272,8 @@ static int hotkey_read(char *p)
|
||||
|
||||
static int hotkey_write(char *buf)
|
||||
{
|
||||
int res, status, mask;
|
||||
int res, status;
|
||||
u32 mask;
|
||||
char *cmd;
|
||||
int do_cmd = 0;
|
||||
|
||||
@ -1012,6 +1328,7 @@ static struct ibm_struct hotkey_driver_data = {
|
||||
.read = hotkey_read,
|
||||
.write = hotkey_write,
|
||||
.exit = hotkey_exit,
|
||||
.resume = hotkey_resume,
|
||||
.acpi = &ibm_hotkey_acpidriver,
|
||||
};
|
||||
|
||||
@ -1770,7 +2087,10 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
|
||||
.type = ACPI_SYSTEM_NOTIFY,
|
||||
},
|
||||
{
|
||||
.hid = IBM_PCI_HID,
|
||||
/* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
|
||||
* We just use it to get notifications of dock hotplug
|
||||
* in very old thinkpads */
|
||||
.hid = PCI_ROOT_HID_STRING,
|
||||
.notify = dock_notify,
|
||||
.handle = &pci_handle,
|
||||
.type = ACPI_SYSTEM_NOTIFY,
|
||||
@ -1829,7 +2149,7 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
|
||||
static void dock_notify(struct ibm_struct *ibm, u32 event)
|
||||
{
|
||||
int docked = dock_docked();
|
||||
int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, IBM_PCI_HID);
|
||||
int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING);
|
||||
|
||||
if (event == 1 && !pci) /* 570 */
|
||||
acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
|
||||
@ -2389,7 +2709,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
|
||||
|
||||
acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
|
||||
|
||||
if (ibm_thinkpad_ec_found && experimental) {
|
||||
if (thinkpad_id.ec_model) {
|
||||
/*
|
||||
* Direct EC access mode: sensors at registers
|
||||
* 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
|
||||
@ -2533,6 +2853,8 @@ static int thermal_get_sensor(int idx, s32 *value)
|
||||
snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
|
||||
if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
|
||||
return -EIO;
|
||||
if (t > 127 || t < -127)
|
||||
t = TP_EC_THERMAL_TMP_NA;
|
||||
*value = t * 1000;
|
||||
return 0;
|
||||
}
|
||||
@ -2671,22 +2993,39 @@ static struct ibm_struct ecdump_driver_data = {
|
||||
* Backlight/brightness subdriver
|
||||
*/
|
||||
|
||||
static struct backlight_device *ibm_backlight_device = NULL;
|
||||
static struct backlight_device *ibm_backlight_device;
|
||||
|
||||
static struct backlight_ops ibm_backlight_data = {
|
||||
.get_brightness = brightness_get,
|
||||
.update_status = brightness_update_status,
|
||||
};
|
||||
|
||||
static struct mutex brightness_mutex;
|
||||
|
||||
static int __init brightness_init(struct ibm_init_struct *iibm)
|
||||
{
|
||||
int b;
|
||||
|
||||
vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
|
||||
|
||||
mutex_init(&brightness_mutex);
|
||||
|
||||
if (!brightness_mode) {
|
||||
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
|
||||
brightness_mode = 2;
|
||||
else
|
||||
brightness_mode = 3;
|
||||
|
||||
dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
|
||||
brightness_mode);
|
||||
}
|
||||
|
||||
if (brightness_mode > 3)
|
||||
return -EINVAL;
|
||||
|
||||
b = brightness_get(NULL);
|
||||
if (b < 0)
|
||||
return b;
|
||||
return 1;
|
||||
|
||||
ibm_backlight_device = backlight_device_register(
|
||||
TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
|
||||
@ -2722,34 +3061,79 @@ static int brightness_update_status(struct backlight_device *bd)
|
||||
bd->props.brightness : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* ThinkPads can read brightness from two places: EC 0x31, or
|
||||
* CMOS NVRAM byte 0x5E, bits 0-3.
|
||||
*/
|
||||
static int brightness_get(struct backlight_device *bd)
|
||||
{
|
||||
u8 level;
|
||||
if (!acpi_ec_read(brightness_offset, &level))
|
||||
return -EIO;
|
||||
u8 lec = 0, lcmos = 0, level = 0;
|
||||
|
||||
level &= 0x7;
|
||||
if (brightness_mode & 1) {
|
||||
if (!acpi_ec_read(brightness_offset, &lec))
|
||||
return -EIO;
|
||||
lec &= 7;
|
||||
level = lec;
|
||||
};
|
||||
if (brightness_mode & 2) {
|
||||
lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
|
||||
& TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
|
||||
>> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
|
||||
level = lcmos;
|
||||
}
|
||||
|
||||
if (brightness_mode == 3 && lec != lcmos) {
|
||||
printk(IBM_ERR
|
||||
"CMOS NVRAM (%u) and EC (%u) do not agree "
|
||||
"on display brightness level\n",
|
||||
(unsigned int) lcmos,
|
||||
(unsigned int) lec);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
static int brightness_set(int value)
|
||||
{
|
||||
int cmos_cmd, inc, i;
|
||||
int current_value = brightness_get(NULL);
|
||||
int cmos_cmd, inc, i, res;
|
||||
int current_value;
|
||||
|
||||
value &= 7;
|
||||
if (value > 7)
|
||||
return -EINVAL;
|
||||
|
||||
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;
|
||||
if (!acpi_ec_write(brightness_offset, i + inc))
|
||||
return -EIO;
|
||||
res = mutex_lock_interruptible(&brightness_mutex);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
current_value = brightness_get(NULL);
|
||||
if (current_value < 0) {
|
||||
res = current_value;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
return 0;
|
||||
cmos_cmd = value > current_value ?
|
||||
TP_CMOS_BRIGHTNESS_UP :
|
||||
TP_CMOS_BRIGHTNESS_DOWN;
|
||||
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(brightness_offset, i + inc)) {
|
||||
res = -EIO;
|
||||
goto errout;;
|
||||
}
|
||||
}
|
||||
|
||||
errout:
|
||||
mutex_unlock(&brightness_mutex);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int brightness_read(char *p)
|
||||
@ -3273,20 +3657,19 @@ static int __init fan_init(struct ibm_init_struct *iibm)
|
||||
* Enable for TP-1Y (T43), TP-78 (R51e),
|
||||
* TP-76 (R52), TP-70 (T43, R52), which are known
|
||||
* to be buggy. */
|
||||
if (fan_control_initial_status == 0x07 &&
|
||||
ibm_thinkpad_ec_found &&
|
||||
((ibm_thinkpad_ec_found[0] == '1' &&
|
||||
ibm_thinkpad_ec_found[1] == 'Y') ||
|
||||
(ibm_thinkpad_ec_found[0] == '7' &&
|
||||
(ibm_thinkpad_ec_found[1] == '6' ||
|
||||
ibm_thinkpad_ec_found[1] == '8' ||
|
||||
ibm_thinkpad_ec_found[1] == '0'))
|
||||
)) {
|
||||
printk(IBM_NOTICE
|
||||
"fan_init: initial fan status is "
|
||||
"unknown, assuming it is in auto "
|
||||
"mode\n");
|
||||
tp_features.fan_ctrl_status_undef = 1;
|
||||
if (fan_control_initial_status == 0x07) {
|
||||
switch (thinkpad_id.ec_model) {
|
||||
case 0x5931: /* TP-1Y */
|
||||
case 0x3837: /* TP-78 */
|
||||
case 0x3637: /* TP-76 */
|
||||
case 0x3037: /* TP-70 */
|
||||
printk(IBM_NOTICE
|
||||
"fan_init: initial fan status is "
|
||||
"unknown, assuming it is in auto "
|
||||
"mode\n");
|
||||
tp_features.fan_ctrl_status_undef = 1;
|
||||
;;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
printk(IBM_ERR
|
||||
@ -3474,7 +3857,7 @@ static void fan_watchdog_fire(struct work_struct *ignored)
|
||||
|
||||
static void fan_watchdog_reset(void)
|
||||
{
|
||||
static int fan_watchdog_active = 0;
|
||||
static int fan_watchdog_active;
|
||||
|
||||
if (fan_control_access_mode == TPACPI_FAN_WR_NONE)
|
||||
return;
|
||||
@ -3877,7 +4260,7 @@ static struct ibm_struct fan_driver_data = {
|
||||
****************************************************************************/
|
||||
|
||||
/* /proc support */
|
||||
static struct proc_dir_entry *proc_dir = NULL;
|
||||
static struct proc_dir_entry *proc_dir;
|
||||
|
||||
/* Subdriver registry */
|
||||
static LIST_HEAD(tpacpi_all_drivers);
|
||||
@ -4020,13 +4403,30 @@ static void ibm_exit(struct ibm_struct *ibm)
|
||||
|
||||
/* Probing */
|
||||
|
||||
static char *ibm_thinkpad_ec_found = NULL;
|
||||
|
||||
static char* __init check_dmi_for_ec(void)
|
||||
static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
|
||||
{
|
||||
struct dmi_device *dev = NULL;
|
||||
char ec_fw_string[18];
|
||||
|
||||
if (!tp)
|
||||
return;
|
||||
|
||||
memset(tp, 0, sizeof(*tp));
|
||||
|
||||
if (dmi_name_in_vendors("IBM"))
|
||||
tp->vendor = PCI_VENDOR_ID_IBM;
|
||||
else if (dmi_name_in_vendors("LENOVO"))
|
||||
tp->vendor = PCI_VENDOR_ID_LENOVO;
|
||||
else
|
||||
return;
|
||||
|
||||
tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
|
||||
GFP_KERNEL);
|
||||
if (!tp->bios_version_str)
|
||||
return;
|
||||
tp->bios_model = tp->bios_version_str[0]
|
||||
| (tp->bios_version_str[1] << 8);
|
||||
|
||||
/*
|
||||
* ThinkPad T23 or newer, A31 or newer, R50e or newer,
|
||||
* X32 or newer, all Z series; Some models must have an
|
||||
@ -4040,10 +4440,20 @@ static char* __init check_dmi_for_ec(void)
|
||||
ec_fw_string) == 1) {
|
||||
ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
|
||||
ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
|
||||
return kstrdup(ec_fw_string, GFP_KERNEL);
|
||||
|
||||
tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
|
||||
tp->ec_model = ec_fw_string[0]
|
||||
| (ec_fw_string[1] << 8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
|
||||
tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
|
||||
GFP_KERNEL);
|
||||
if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
|
||||
kfree(tp->model_str);
|
||||
tp->model_str = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int __init probe_for_thinkpad(void)
|
||||
@ -4057,7 +4467,7 @@ static int __init probe_for_thinkpad(void)
|
||||
* Non-ancient models have better DMI tagging, but very old models
|
||||
* don't.
|
||||
*/
|
||||
is_thinkpad = dmi_name_in_vendors("ThinkPad");
|
||||
is_thinkpad = (thinkpad_id.model_str != NULL);
|
||||
|
||||
/* ec is required because many other handles are relative to it */
|
||||
IBM_ACPIHANDLE_INIT(ec);
|
||||
@ -4073,7 +4483,7 @@ static int __init probe_for_thinkpad(void)
|
||||
* false positives a damn great deal
|
||||
*/
|
||||
if (!is_thinkpad)
|
||||
is_thinkpad = dmi_name_in_vendors("IBM");
|
||||
is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
|
||||
|
||||
if (!is_thinkpad && !force_load)
|
||||
return -ENODEV;
|
||||
@ -4185,10 +4595,13 @@ static u32 dbg_level;
|
||||
module_param_named(debug, dbg_level, uint, 0);
|
||||
|
||||
static int force_load;
|
||||
module_param(force_load, int, 0);
|
||||
module_param(force_load, bool, 0);
|
||||
|
||||
static int fan_control_allowed;
|
||||
module_param_named(fan_control, fan_control_allowed, int, 0);
|
||||
module_param_named(fan_control, fan_control_allowed, bool, 0);
|
||||
|
||||
static int brightness_mode;
|
||||
module_param_named(brightness_mode, brightness_mode, int, 0);
|
||||
|
||||
#define IBM_PARAM(feature) \
|
||||
module_param_call(feature, set_ibm_param, NULL, NULL, 0)
|
||||
@ -4216,12 +4629,16 @@ static int __init thinkpad_acpi_module_init(void)
|
||||
int ret, i;
|
||||
|
||||
/* Driver-level probe */
|
||||
|
||||
get_thinkpad_model_data(&thinkpad_id);
|
||||
ret = probe_for_thinkpad();
|
||||
if (ret)
|
||||
if (ret) {
|
||||
thinkpad_acpi_module_exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Driver initialization */
|
||||
ibm_thinkpad_ec_found = check_dmi_for_ec();
|
||||
|
||||
IBM_ACPIHANDLE_INIT(ecrd);
|
||||
IBM_ACPIHANDLE_INIT(ecwr);
|
||||
|
||||
@ -4265,6 +4682,22 @@ static int __init thinkpad_acpi_module_init(void)
|
||||
thinkpad_acpi_module_exit();
|
||||
return ret;
|
||||
}
|
||||
tpacpi_inputdev = input_allocate_device();
|
||||
if (!tpacpi_inputdev) {
|
||||
printk(IBM_ERR "unable to allocate input device\n");
|
||||
thinkpad_acpi_module_exit();
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
/* Prepare input device, but don't register */
|
||||
tpacpi_inputdev->name = "ThinkPad Extra Buttons";
|
||||
tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
|
||||
tpacpi_inputdev->id.bustype = BUS_HOST;
|
||||
tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
|
||||
thinkpad_id.vendor :
|
||||
PCI_VENDOR_ID_IBM;
|
||||
tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
|
||||
tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
|
||||
}
|
||||
for (i = 0; i < ARRAY_SIZE(ibms_init); i++) {
|
||||
ret = ibm_init(&ibms_init[i]);
|
||||
if (ret >= 0 && *ibms_init[i].param)
|
||||
@ -4274,6 +4707,14 @@ static int __init thinkpad_acpi_module_init(void)
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ret = input_register_device(tpacpi_inputdev);
|
||||
if (ret < 0) {
|
||||
printk(IBM_ERR "unable to register input device\n");
|
||||
thinkpad_acpi_module_exit();
|
||||
return ret;
|
||||
} else {
|
||||
tp_features.input_device_registered = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -4290,6 +4731,13 @@ static void thinkpad_acpi_module_exit(void)
|
||||
|
||||
dbg_printk(TPACPI_DBG_INIT, "finished subdriver exit path...\n");
|
||||
|
||||
if (tpacpi_inputdev) {
|
||||
if (tp_features.input_device_registered)
|
||||
input_unregister_device(tpacpi_inputdev);
|
||||
else
|
||||
input_free_device(tpacpi_inputdev);
|
||||
}
|
||||
|
||||
if (tpacpi_hwmon)
|
||||
hwmon_device_unregister(tpacpi_hwmon);
|
||||
|
||||
@ -4302,7 +4750,9 @@ static void thinkpad_acpi_module_exit(void)
|
||||
if (proc_dir)
|
||||
remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);
|
||||
|
||||
kfree(ibm_thinkpad_ec_found);
|
||||
kfree(thinkpad_id.bios_version_str);
|
||||
kfree(thinkpad_id.ec_version_str);
|
||||
kfree(thinkpad_id.model_str);
|
||||
}
|
||||
|
||||
module_init(thinkpad_acpi_module_init);
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/nvram.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/backlight.h>
|
||||
@ -39,6 +40,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/input.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/dmi.h>
|
||||
@ -48,6 +50,7 @@
|
||||
#include <acpi/acpi_drivers.h>
|
||||
#include <acpi/acnamesp.h>
|
||||
|
||||
#include <linux/pci_ids.h>
|
||||
|
||||
/****************************************************************************
|
||||
* Main driver
|
||||
@ -78,6 +81,11 @@
|
||||
#define TP_CMOS_BRIGHTNESS_UP 4
|
||||
#define TP_CMOS_BRIGHTNESS_DOWN 5
|
||||
|
||||
/* ThinkPad CMOS NVRAM constants */
|
||||
#define TP_NVRAM_ADDR_BRIGHTNESS 0x5e
|
||||
#define TP_NVRAM_MASK_LEVEL_BRIGHTNESS 0x07
|
||||
#define TP_NVRAM_POS_LEVEL_BRIGHTNESS 0
|
||||
|
||||
#define onoff(status,bit) ((status) & (1 << (bit)) ? "on" : "off")
|
||||
#define enabled(status,bit) ((status) & (1 << (bit)) ? "enabled" : "disabled")
|
||||
#define strlencmp(a,b) (strncmp((a), (b), strlen(b)))
|
||||
@ -98,9 +106,13 @@ static const char *str_supported(int is_supported);
|
||||
#define vdbg_printk(a_dbg_level, format, arg...)
|
||||
#endif
|
||||
|
||||
/* Input IDs */
|
||||
#define TPACPI_HKEY_INPUT_VENDOR PCI_VENDOR_ID_IBM
|
||||
#define TPACPI_HKEY_INPUT_PRODUCT 0x5054 /* "TP" */
|
||||
#define TPACPI_HKEY_INPUT_VERSION 0x4101
|
||||
|
||||
/* ACPI HIDs */
|
||||
#define IBM_HKEY_HID "IBM0068"
|
||||
#define IBM_PCI_HID "PNP0A03"
|
||||
|
||||
/* ACPI helpers */
|
||||
static int __must_check acpi_evalf(acpi_handle handle,
|
||||
@ -161,6 +173,7 @@ static int parse_strtoul(const char *buf, unsigned long max,
|
||||
static struct platform_device *tpacpi_pdev;
|
||||
static struct class_device *tpacpi_hwmon;
|
||||
static struct platform_driver tpacpi_pdriver;
|
||||
static struct input_dev *tpacpi_inputdev;
|
||||
static int tpacpi_create_driver_attributes(struct device_driver *drv);
|
||||
static void tpacpi_remove_driver_attributes(struct device_driver *drv);
|
||||
|
||||
@ -168,9 +181,7 @@ static void tpacpi_remove_driver_attributes(struct device_driver *drv);
|
||||
static int experimental;
|
||||
static u32 dbg_level;
|
||||
static int force_load;
|
||||
static char *ibm_thinkpad_ec_found;
|
||||
|
||||
static char* check_dmi_for_ec(void);
|
||||
static int thinkpad_acpi_module_init(void);
|
||||
static void thinkpad_acpi_module_exit(void);
|
||||
|
||||
@ -197,6 +208,7 @@ struct ibm_struct {
|
||||
int (*read) (char *);
|
||||
int (*write) (char *);
|
||||
void (*exit) (void);
|
||||
void (*resume) (void);
|
||||
|
||||
struct list_head all_drivers;
|
||||
|
||||
@ -228,12 +240,29 @@ static struct {
|
||||
u16 bluetooth:1;
|
||||
u16 hotkey:1;
|
||||
u16 hotkey_mask:1;
|
||||
u16 hotkey_wlsw:1;
|
||||
u16 light:1;
|
||||
u16 light_status:1;
|
||||
u16 wan:1;
|
||||
u16 fan_ctrl_status_undef:1;
|
||||
u16 input_device_registered:1;
|
||||
} tp_features;
|
||||
|
||||
struct thinkpad_id_data {
|
||||
unsigned int vendor; /* ThinkPad vendor:
|
||||
* PCI_VENDOR_ID_IBM/PCI_VENDOR_ID_LENOVO */
|
||||
|
||||
char *bios_version_str; /* Something like 1ZET51WW (1.03z) */
|
||||
char *ec_version_str; /* Something like 1ZHT51WW-1.04a */
|
||||
|
||||
u16 bios_model; /* Big Endian, TP-1Y = 0x5931, 0 = unknown */
|
||||
u16 ec_model;
|
||||
|
||||
char *model_str;
|
||||
};
|
||||
|
||||
static struct thinkpad_id_data thinkpad_id;
|
||||
|
||||
static struct list_head tpacpi_all_drivers;
|
||||
|
||||
static struct ibm_init_struct ibms_init[];
|
||||
@ -300,6 +329,7 @@ static int bluetooth_write(char *buf);
|
||||
|
||||
static struct backlight_device *ibm_backlight_device;
|
||||
static int brightness_offset = 0x31;
|
||||
static int brightness_mode;
|
||||
|
||||
static int brightness_init(struct ibm_init_struct *iibm);
|
||||
static void brightness_exit(void);
|
||||
@ -415,14 +445,14 @@ static int fan_write_cmd_watchdog(const char *cmd, int *rc);
|
||||
*/
|
||||
|
||||
static int hotkey_orig_status;
|
||||
static int hotkey_orig_mask;
|
||||
static u32 hotkey_orig_mask;
|
||||
|
||||
static struct mutex hotkey_mutex;
|
||||
|
||||
static int hotkey_init(struct ibm_init_struct *iibm);
|
||||
static void hotkey_exit(void);
|
||||
static int hotkey_get(int *status, int *mask);
|
||||
static int hotkey_set(int status, int mask);
|
||||
static int hotkey_get(int *status, u32 *mask);
|
||||
static int hotkey_set(int status, u32 mask);
|
||||
static void hotkey_notify(struct ibm_struct *ibm, u32 event);
|
||||
static int hotkey_read(char *p);
|
||||
static int hotkey_write(char *buf);
|
||||
|
@ -12,6 +12,13 @@ config VGASTATE
|
||||
tristate
|
||||
default n
|
||||
|
||||
config VIDEO_OUTPUT_CONTROL
|
||||
tristate "Lowlevel video output switch controls"
|
||||
default m
|
||||
help
|
||||
This framework adds support for low-level control of the video
|
||||
output switch.
|
||||
|
||||
config FB
|
||||
tristate "Support for frame buffer devices"
|
||||
---help---
|
||||
|
@ -123,3 +123,6 @@ obj-$(CONFIG_FB_OF) += offb.o
|
||||
|
||||
# the test framebuffer is last
|
||||
obj-$(CONFIG_FB_VIRTUAL) += vfb.o
|
||||
|
||||
#video output switch sysfs driver
|
||||
obj-$(CONFIG_VIDEO_OUTPUT_CONTROL) += output.o
|
||||
|
@ -486,6 +486,8 @@
|
||||
#define ACPI_FUNCTION_NAME(name)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_FUNC_TRACE
|
||||
|
||||
#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \
|
||||
acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
|
||||
#define ACPI_FUNCTION_TRACE_PTR(a,b) ACPI_FUNCTION_NAME(a) \
|
||||
@ -563,6 +565,27 @@
|
||||
|
||||
#endif /* ACPI_SIMPLE_RETURN_MACROS */
|
||||
|
||||
#else /* !DEBUG_FUNC_TRACE */
|
||||
|
||||
#define ACPI_FUNCTION_TRACE(a)
|
||||
#define ACPI_FUNCTION_TRACE_PTR(a,b)
|
||||
#define ACPI_FUNCTION_TRACE_U32(a,b)
|
||||
#define ACPI_FUNCTION_TRACE_STR(a,b)
|
||||
#define ACPI_FUNCTION_EXIT
|
||||
#define ACPI_FUNCTION_STATUS_EXIT(s)
|
||||
#define ACPI_FUNCTION_VALUE_EXIT(s)
|
||||
#define ACPI_FUNCTION_TRACE(a)
|
||||
#define ACPI_FUNCTION_ENTRY()
|
||||
|
||||
#define return_VOID return
|
||||
#define return_ACPI_STATUS(s) return(s)
|
||||
#define return_VALUE(s) return(s)
|
||||
#define return_UINT8(s) return(s)
|
||||
#define return_UINT32(s) return(s)
|
||||
#define return_PTR(s) return(s)
|
||||
|
||||
#endif /* DEBUG_FUNC_TRACE */
|
||||
|
||||
/* Conditional execution */
|
||||
|
||||
#define ACPI_DEBUG_EXEC(a) a
|
||||
@ -599,26 +622,26 @@
|
||||
#define ACPI_DEBUG_EXEC(a)
|
||||
#define ACPI_NORMAL_EXEC(a) a;
|
||||
|
||||
#define ACPI_DEBUG_DEFINE(a)
|
||||
#define ACPI_DEBUG_ONLY_MEMBERS(a)
|
||||
#define ACPI_FUNCTION_NAME(a)
|
||||
#define ACPI_FUNCTION_TRACE(a)
|
||||
#define ACPI_FUNCTION_TRACE_PTR(a,b)
|
||||
#define ACPI_FUNCTION_TRACE_U32(a,b)
|
||||
#define ACPI_FUNCTION_TRACE_STR(a,b)
|
||||
#define ACPI_FUNCTION_EXIT
|
||||
#define ACPI_FUNCTION_STATUS_EXIT(s)
|
||||
#define ACPI_FUNCTION_VALUE_EXIT(s)
|
||||
#define ACPI_FUNCTION_ENTRY()
|
||||
#define ACPI_DUMP_STACK_ENTRY(a)
|
||||
#define ACPI_DUMP_OPERANDS(a,b,c,d,e)
|
||||
#define ACPI_DUMP_ENTRY(a,b)
|
||||
#define ACPI_DUMP_TABLES(a,b)
|
||||
#define ACPI_DUMP_PATHNAME(a,b,c,d)
|
||||
#define ACPI_DUMP_RESOURCE_LIST(a)
|
||||
#define ACPI_DUMP_BUFFER(a,b)
|
||||
#define ACPI_DEBUG_PRINT(pl)
|
||||
#define ACPI_DEBUG_PRINT_RAW(pl)
|
||||
#define ACPI_DEBUG_DEFINE(a) do { } while(0)
|
||||
#define ACPI_DEBUG_ONLY_MEMBERS(a) do { } while(0)
|
||||
#define ACPI_FUNCTION_NAME(a) do { } while(0)
|
||||
#define ACPI_FUNCTION_TRACE(a) do { } while(0)
|
||||
#define ACPI_FUNCTION_TRACE_PTR(a,b) do { } while(0)
|
||||
#define ACPI_FUNCTION_TRACE_U32(a,b) do { } while(0)
|
||||
#define ACPI_FUNCTION_TRACE_STR(a,b) do { } while(0)
|
||||
#define ACPI_FUNCTION_EXIT do { } while(0)
|
||||
#define ACPI_FUNCTION_STATUS_EXIT(s) do { } while(0)
|
||||
#define ACPI_FUNCTION_VALUE_EXIT(s) do { } while(0)
|
||||
#define ACPI_FUNCTION_ENTRY() do { } while(0)
|
||||
#define ACPI_DUMP_STACK_ENTRY(a) do { } while(0)
|
||||
#define ACPI_DUMP_OPERANDS(a,b,c,d,e) do { } while(0)
|
||||
#define ACPI_DUMP_ENTRY(a,b) do { } while(0)
|
||||
#define ACPI_DUMP_TABLES(a,b) do { } while(0)
|
||||
#define ACPI_DUMP_PATHNAME(a,b,c,d) do { } while(0)
|
||||
#define ACPI_DUMP_RESOURCE_LIST(a) do { } while(0)
|
||||
#define ACPI_DUMP_BUFFER(a,b) do { } while(0)
|
||||
#define ACPI_DEBUG_PRINT(pl) do { } while(0)
|
||||
#define ACPI_DEBUG_PRINT_RAW(pl) do { } while(0)
|
||||
|
||||
#define return_VOID return
|
||||
#define return_ACPI_STATUS(s) return(s)
|
||||
|
@ -178,8 +178,8 @@
|
||||
|
||||
/* Defaults for debug_level, debug and normal */
|
||||
|
||||
#define ACPI_DEBUG_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
|
||||
#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR | ACPI_LV_DEBUG_OBJECT)
|
||||
#define ACPI_DEBUG_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
|
||||
#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_WARN | ACPI_LV_ERROR)
|
||||
#define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL)
|
||||
|
||||
#endif /* __ACOUTPUT_H__ */
|
||||
|
@ -321,7 +321,8 @@ struct acpi_bus_event {
|
||||
};
|
||||
|
||||
extern struct kset acpi_subsys;
|
||||
|
||||
extern int acpi_bus_generate_genetlink_event(struct acpi_device *device,
|
||||
u8 type, int data);
|
||||
/*
|
||||
* External Functions
|
||||
*/
|
||||
|
@ -136,7 +136,7 @@
|
||||
|
||||
/*! [Begin] no source code translation */
|
||||
|
||||
#if defined(__linux__)
|
||||
#if defined(_LINUX) || defined(__linux__)
|
||||
#include "aclinux.h"
|
||||
|
||||
#elif defined(_AED_EFI)
|
||||
|
@ -91,7 +91,10 @@
|
||||
#define ACPI_USE_NATIVE_DIVIDE
|
||||
#endif
|
||||
|
||||
#ifndef __cdecl
|
||||
#define __cdecl
|
||||
#endif
|
||||
|
||||
#define ACPI_FLUSH_CPU_CACHE()
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
|
@ -21,6 +21,8 @@
|
||||
#define ACPI_PSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
|
||||
#define ACPI_PSD_REV0_ENTRIES 5
|
||||
|
||||
#define ACPI_TSD_REV0_REVISION 0 /* Support for _PSD as in ACPI 3.0 */
|
||||
#define ACPI_TSD_REV0_ENTRIES 5
|
||||
/*
|
||||
* Types of coordination defined in ACPI 3.0. Same macros can be used across
|
||||
* P, C and T states
|
||||
@ -125,17 +127,53 @@ struct acpi_processor_performance {
|
||||
|
||||
/* Throttling Control */
|
||||
|
||||
struct acpi_tsd_package {
|
||||
acpi_integer num_entries;
|
||||
acpi_integer revision;
|
||||
acpi_integer domain;
|
||||
acpi_integer coord_type;
|
||||
acpi_integer num_processors;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct acpi_ptc_register {
|
||||
u8 descriptor;
|
||||
u16 length;
|
||||
u8 space_id;
|
||||
u8 bit_width;
|
||||
u8 bit_offset;
|
||||
u8 reserved;
|
||||
u64 address;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct acpi_processor_tx_tss {
|
||||
acpi_integer freqpercentage; /* */
|
||||
acpi_integer power; /* milliWatts */
|
||||
acpi_integer transition_latency; /* microseconds */
|
||||
acpi_integer control; /* control value */
|
||||
acpi_integer status; /* success indicator */
|
||||
};
|
||||
struct acpi_processor_tx {
|
||||
u16 power;
|
||||
u16 performance;
|
||||
};
|
||||
|
||||
struct acpi_processor;
|
||||
struct acpi_processor_throttling {
|
||||
int state;
|
||||
unsigned int state;
|
||||
unsigned int platform_limit;
|
||||
struct acpi_pct_register control_register;
|
||||
struct acpi_pct_register status_register;
|
||||
unsigned int state_count;
|
||||
struct acpi_processor_tx_tss *states_tss;
|
||||
struct acpi_tsd_package domain_info;
|
||||
cpumask_t shared_cpu_map;
|
||||
int (*acpi_processor_get_throttling) (struct acpi_processor * pr);
|
||||
int (*acpi_processor_set_throttling) (struct acpi_processor * pr,
|
||||
int state);
|
||||
|
||||
u32 address;
|
||||
u8 duty_offset;
|
||||
u8 duty_width;
|
||||
int state_count;
|
||||
struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING];
|
||||
};
|
||||
|
||||
@ -169,6 +207,9 @@ struct acpi_processor {
|
||||
u32 id;
|
||||
u32 pblk;
|
||||
int performance_platform_limit;
|
||||
int throttling_platform_limit;
|
||||
/* 0 - states 0..n-th state available */
|
||||
|
||||
struct acpi_processor_flags flags;
|
||||
struct acpi_processor_power power;
|
||||
struct acpi_processor_performance *performance;
|
||||
@ -270,7 +311,7 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
|
||||
|
||||
/* in processor_throttling.c */
|
||||
int acpi_processor_get_throttling_info(struct acpi_processor *pr);
|
||||
int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
|
||||
extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
|
||||
extern struct file_operations acpi_processor_throttling_fops;
|
||||
|
||||
/* in processor_idle.c */
|
||||
|
@ -2040,6 +2040,8 @@
|
||||
#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
|
||||
#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb
|
||||
|
||||
#define PCI_VENDOR_ID_LENOVO 0x17aa
|
||||
|
||||
#define PCI_VENDOR_ID_ARECA 0x17d3
|
||||
#define PCI_DEVICE_ID_ARECA_1110 0x1110
|
||||
#define PCI_DEVICE_ID_ARECA_1120 0x1120
|
||||
|
Loading…
x
Reference in New Issue
Block a user