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: (112 commits)
  ACPI: fix build warning
  Revert "cpuidle: build fix for non-x86"
  ACPI: update intrd DSDT override console messages
  ACPI: update DSDT override documentation
  ACPI: Add "acpi_no_initrd_override" kernel parameter
  ACPI: its a directory not a folder....
  ACPI: misc cleanups
  ACPI: add missing prink prefix strings
  ACPI: cleanup acpi.h
  ACPICA: fix CONFIG_ACPI_DEBUG_FUNC_TRACE build
  ACPI: video: Ignore ACPI video devices that aren't present in hardware
  ACPI: video: reset brightness on resume
  ACPI: video: call ACPI notifier chain for ACPI video notifications
  ACPI: create notifier chain to get hotkey events to graphics driver
  ACPI: video: delete unused display switch on hotkey event code
  ACPI: video: create "brightness_switch_enabled" modparam
  cpuidle: Add a poll_idle method
  ACPI: cpuidle: Support C1 idle time accounting
  ACPI: enable MWAIT for C1 idle
  ACPI: idle: Fix acpi_safe_halt usages and interrupt enabling/disabling
  ...
This commit is contained in:
Linus Torvalds 2008-02-07 09:45:58 -08:00
commit f0f1b3364a
95 changed files with 9213 additions and 2690 deletions

View File

@ -14,6 +14,7 @@ Following translations are available on the WWW:
- this file. - this file.
ABI/ ABI/
- info on kernel <-> userspace ABI and relative interface stability. - info on kernel <-> userspace ABI and relative interface stability.
BUG-HUNTING BUG-HUNTING
- brute force method of doing binary search of patches to find bug. - brute force method of doing binary search of patches to find bug.
Changes Changes
@ -66,6 +67,8 @@ VGA-softcursor.txt
- how to change your VGA cursor from a blinking underscore. - how to change your VGA cursor from a blinking underscore.
accounting/ accounting/
- documentation on accounting and taskstats. - documentation on accounting and taskstats.
acpi/
- info on ACPI-specific hooks in the kernel.
aoe/ aoe/
- description of AoE (ATA over Ethernet) along with config examples. - description of AoE (ATA over Ethernet) along with config examples.
applying-patches.txt applying-patches.txt

View File

@ -0,0 +1,99 @@
What: /sys/firmware/acpi/interrupts/
Date: February 2008
Contact: Len Brown <lenb@kernel.org>
Description:
All ACPI interrupts are handled via a single IRQ,
the System Control Interrupt (SCI), which appears
as "acpi" in /proc/interrupts.
However, one of the main functions of ACPI is to make
the platform understand random hardware without
special driver support. So while the SCI handles a few
well known (fixed feature) interrupts sources, such
as the power button, it can also handle a variable
number of a "General Purpose Events" (GPE).
A GPE vectors to a specified handler in AML, which
can do a anything the BIOS writer wants from
OS context. GPE 0x12, for example, would vector
to a level or edge handler called _L12 or _E12.
The handler may do its business and return.
Or the handler may send send a Notify event
to a Linux device driver registered on an ACPI device,
such as a battery, or a processor.
To figure out where all the SCI's are coming from,
/sys/firmware/acpi/interrupts contains a file listing
every possible source, and the count of how many
times it has triggered.
$ cd /sys/firmware/acpi/interrupts
$ grep . *
error:0
ff_gbl_lock:0
ff_pmtimer:0
ff_pwr_btn:0
ff_rt_clk:0
ff_slp_btn:0
gpe00:0
gpe01:0
gpe02:0
gpe03:0
gpe04:0
gpe05:0
gpe06:0
gpe07:0
gpe08:0
gpe09:174
gpe0A:0
gpe0B:0
gpe0C:0
gpe0D:0
gpe0E:0
gpe0F:0
gpe10:0
gpe11:60
gpe12:0
gpe13:0
gpe14:0
gpe15:0
gpe16:0
gpe17:0
gpe18:0
gpe19:7
gpe1A:0
gpe1B:0
gpe1C:0
gpe1D:0
gpe1E:0
gpe1F:0
gpe_all:241
sci:241
sci - The total number of times the ACPI SCI
has claimed an interrupt.
gpe_all - count of SCI caused by GPEs.
gpeXX - count for individual GPE source
ff_gbl_lock - Global Lock
ff_pmtimer - PM Timer
ff_pwr_btn - Power Button
ff_rt_clk - Real Time Clock
ff_slp_btn - Sleep Button
error - an interrupt that can't be accounted for above.
Root has permission to clear any of these counters. Eg.
# echo 0 > gpe11
All counters can be cleared by clearing the total "sci":
# echo 0 > sci
None of these counters has an effect on the function
of the system, they are simply statistics.

View File

@ -0,0 +1,15 @@
Linux supports two methods of overriding the BIOS DSDT:
CONFIG_ACPI_CUSTOM_DSDT builds the image into the kernel.
CONFIG_ACPI_CUSTOM_DSDT_INITRD adds the image to the initrd.
When to use these methods is described in detail on the
Linux/ACPI home page:
http://www.lesswatts.org/projects/acpi/overridingDSDT.php
Note that if both options are used, the DSDT supplied
by the INITRD method takes precedence.
Documentation/initramfs-add-dsdt.sh is provided for convenience
for use with the CONFIG_ACPI_CUSTOM_DSDT_INITRD method.

View File

@ -0,0 +1,43 @@
#!/bin/bash
# Adds a DSDT file to the initrd (if it's an initramfs)
# first argument is the name of archive
# second argument is the name of the file to add
# The file will be copied as /DSDT.aml
# 20060126: fix "Premature end of file" with some old cpio (Roland Robic)
# 20060205: this time it should really work
# check the arguments
if [ $# -ne 2 ]; then
program_name=$(basename $0)
echo "\
$program_name: too few arguments
Usage: $program_name initrd-name.img DSDT-to-add.aml
Adds a DSDT file to an initrd (in initramfs format)
initrd-name.img: filename of the initrd in initramfs format
DSDT-to-add.aml: filename of the DSDT file to add
" 1>&2
exit 1
fi
# we should check it's an initramfs
tempcpio=$(mktemp -d)
# cleanup on exit, hangup, interrupt, quit, termination
trap 'rm -rf $tempcpio' 0 1 2 3 15
# extract the archive
gunzip -c "$1" > "$tempcpio"/initramfs.cpio || exit 1
# copy the DSDT file at the root of the directory so that we can call it "/DSDT.aml"
cp -f "$2" "$tempcpio"/DSDT.aml
# add the file
cd "$tempcpio"
(echo DSDT.aml | cpio --quiet -H newc -o -A -O "$tempcpio"/initramfs.cpio) || exit 1
cd "$OLDPWD"
# re-compress the archive
gzip -c "$tempcpio"/initramfs.cpio > "$1"

View File

@ -0,0 +1,26 @@
/sys/module/acpi/parameters/:
trace_method_name
The AML method name that the user wants to trace
trace_debug_layer
The temporary debug_layer used when tracing the method.
Using 0xffffffff by default if it is 0.
trace_debug_level
The temporary debug_level used when tracing the method.
Using 0x00ffffff by default if it is 0.
trace_state
The status of the tracing feature.
"enabled" means this feature is enabled
and the AML method is traced every time it's executed.
"1" means this feature is enabled and the AML method
will only be traced during the next execution.
"disabled" means this feature is disabled.
Users can enable/disable this debug tracing feature by
"echo string > /sys/module/acpi/parameters/trace_state".
"string" should be one of "enable", "disable" and "1".

View File

@ -147,8 +147,10 @@ and is between 256 and 4096 characters. It is defined in the file
default: 0 default: 0
acpi_sleep= [HW,ACPI] Sleep options acpi_sleep= [HW,ACPI] Sleep options
Format: { s3_bios, s3_mode } Format: { s3_bios, s3_mode, s3_beep }
See Documentation/power/video.txt See Documentation/power/video.txt for s3_bios and s3_mode.
s3_beep is for debugging; it makes the PC's speaker beep
as soon as the kernel's real-mode entry point is called.
acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode acpi_sci= [HW,ACPI] ACPI System Control Interrupt trigger mode
Format: { level | edge | high | low } Format: { level | edge | high | low }
@ -175,6 +177,9 @@ and is between 256 and 4096 characters. It is defined in the file
acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT acpi_no_auto_ssdt [HW,ACPI] Disable automatic loading of SSDT
acpi_no_initrd_override [KNL,ACPI]
Disable loading custom ACPI tables from the initramfs
acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS acpi_os_name= [HW,ACPI] Tell ACPI BIOS the name of the OS
Format: To spoof as Windows 98: ="Microsoft Windows" Format: To spoof as Windows 98: ="Microsoft Windows"

View File

@ -386,6 +386,11 @@ before suspending; then remount them after resuming.
There is a work-around for this problem. For more information, see There is a work-around for this problem. For more information, see
Documentation/usb/persist.txt. Documentation/usb/persist.txt.
Q: Can I suspend-to-disk using a swap partition under LVM?
A: No. You can suspend successfully, but you'll not be able to
resume. uswsusp should be able to work with LVM. See suspend.sf.net.
Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
compiled with the similar configuration files. Anyway I found that compiled with the similar configuration files. Anyway I found that
suspend to disk (and resume) is much slower on 2.6.16 compared to suspend to disk (and resume) is much slower on 2.6.16 compared to

View File

@ -0,0 +1,246 @@
Generic Thermal Sysfs driver How To
=========================
Written by Sujith Thomas <sujith.thomas@intel.com>, Zhang Rui <rui.zhang@intel.com>
Updated: 2 January 2008
Copyright (c) 2008 Intel Corporation
0. Introduction
The generic thermal sysfs provides a set of interfaces for thermal zone devices (sensors)
and thermal cooling devices (fan, processor...) to register with the thermal management
solution and to be a part of it.
This how-to focusses on enabling new thermal zone and cooling devices to participate
in thermal management.
This solution is platform independent and any type of thermal zone devices and
cooling devices should be able to make use of the infrastructure.
The main task of the thermal sysfs driver is to expose thermal zone attributes as well
as cooling device attributes to the user space.
An intelligent thermal management application can make decisions based on inputs
from thermal zone attributes (the current temperature and trip point temperature)
and throttle appropriate devices.
[0-*] denotes any positive number starting from 0
[1-*] denotes any positive number starting from 1
1. thermal sysfs driver interface functions
1.1 thermal zone device interface
1.1.1 struct thermal_zone_device *thermal_zone_device_register(char *name, int trips,
void *devdata, struct thermal_zone_device_ops *ops)
This interface function adds a new thermal zone device (sensor) to
/sys/class/thermal folder as thermal_zone[0-*].
It tries to bind all the thermal cooling devices registered at the same time.
name: the thermal zone name.
trips: the total number of trip points this thermal zone supports.
devdata: device private data
ops: thermal zone device callbacks.
.bind: bind the thermal zone device with a thermal cooling device.
.unbind: unbing the thermal zone device with a thermal cooling device.
.get_temp: get the current temperature of the thermal zone.
.get_mode: get the current mode (user/kernel) of the thermal zone.
"kernel" means thermal management is done in kernel.
"user" will prevent kernel thermal driver actions upon trip points
so that user applications can take charge of thermal management.
.set_mode: set the mode (user/kernel) of the thermal zone.
.get_trip_type: get the type of certain trip point.
.get_trip_temp: get the temperature above which the certain trip point
will be fired.
1.1.2 void thermal_zone_device_unregister(struct thermal_zone_device *tz)
This interface function removes the thermal zone device.
It deletes the corresponding entry form /sys/class/thermal folder and unbind all
the thermal cooling devices it uses.
1.2 thermal cooling device interface
1.2.1 struct thermal_cooling_device *thermal_cooling_device_register(char *name,
void *devdata, struct thermal_cooling_device_ops *)
This interface function adds a new thermal cooling device (fan/processor/...) to
/sys/class/thermal/ folder as cooling_device[0-*].
It tries to bind itself to all the thermal zone devices register at the same time.
name: the cooling device name.
devdata: device private data.
ops: thermal cooling devices callbacks.
.get_max_state: get the Maximum throttle state of the cooling device.
.get_cur_state: get the Current throttle state of the cooling device.
.set_cur_state: set the Current throttle state of the cooling device.
1.2.2 void thermal_cooling_device_unregister(struct thermal_cooling_device *cdev)
This interface function remove the thermal cooling device.
It deletes the corresponding entry form /sys/class/thermal folder and unbind
itself from all the thermal zone devices using it.
1.3 interface for binding a thermal zone device with a thermal cooling device
1.3.1 int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
int trip, struct thermal_cooling_device *cdev);
This interface function bind a thermal cooling device to the certain trip point
of a thermal zone device.
This function is usually called in the thermal zone device .bind callback.
tz: the thermal zone device
cdev: thermal cooling device
trip: indicates which trip point the cooling devices is associated with
in this thermal zone.
1.3.2 int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
int trip, struct thermal_cooling_device *cdev);
This interface function unbind a thermal cooling device from the certain trip point
of a thermal zone device.
This function is usually called in the thermal zone device .unbind callback.
tz: the thermal zone device
cdev: thermal cooling device
trip: indicates which trip point the cooling devices is associated with
in this thermal zone.
2. sysfs attributes structure
RO read only value
RW read/write value
All thermal sysfs attributes will be represented under /sys/class/thermal
/sys/class/thermal/
Thermal zone device sys I/F, created once it's registered:
|thermal_zone[0-*]:
|-----type: Type of the thermal zone
|-----temp: Current temperature
|-----mode: Working mode of the thermal zone
|-----trip_point_[0-*]_temp: Trip point temperature
|-----trip_point_[0-*]_type: Trip point type
Thermal cooling device sys I/F, created once it's registered:
|cooling_device[0-*]:
|-----type : Type of the cooling device(processor/fan/...)
|-----max_state: Maximum cooling state of the cooling device
|-----cur_state: Current cooling state of the cooling device
These two dynamic attributes are created/removed in pairs.
They represent the relationship between a thermal zone and its associated cooling device.
They are created/removed for each
thermal_zone_bind_cooling_device/thermal_zone_unbind_cooling_device successful exection.
|thermal_zone[0-*]
|-----cdev[0-*]: The [0-*]th cooling device in the current thermal zone
|-----cdev[0-*]_trip_point: Trip point that cdev[0-*] is associated with
***************************
* Thermal zone attributes *
***************************
type Strings which represent the thermal zone type.
This is given by thermal zone driver as part of registration.
Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
RO
Optional
temp Current temperature as reported by thermal zone (sensor)
Unit: degree celsius
RO
Required
mode One of the predifned values in [kernel, user]
This file gives information about the algorithm
that is currently managing the thermal zone.
It can be either default kernel based algorithm
or user space application.
RW
Optional
kernel = Thermal management in kernel thermal zone driver.
user = Preventing kernel thermal zone driver actions upon
trip points so that user application can take full
charge of the thermal management.
trip_point_[0-*]_temp The temperature above which trip point will be fired
Unit: degree celsius
RO
Optional
trip_point_[0-*]_type Strings which indicate the type of the trip point
Eg. it can be one of critical, hot, passive,
active[0-*] for ACPI thermal zone.
RO
Optional
cdev[0-*] Sysfs link to the thermal cooling device node where the sys I/F
for cooling device throttling control represents.
RO
Optional
cdev[0-*]_trip_point The trip point with which cdev[0-*] is assocated in this thermal zone
-1 means the cooling device is not associated with any trip point.
RO
Optional
******************************
* Cooling device attributes *
******************************
type String which represents the type of device
eg: For generic ACPI: this should be "Fan",
"Processor" or "LCD"
eg. For memory controller device on intel_menlow platform:
this should be "Memory controller"
RO
Optional
max_state The maximum permissible cooling state of this cooling device.
RO
Required
cur_state The current cooling state of this cooling device.
the value can any integer numbers between 0 and max_state,
cur_state == 0 means no cooling
cur_state == max_state means the maximum cooling.
RW
Required
3. A simple implementation
ACPI thermal zone may support multiple trip points like critical/hot/passive/active.
If an ACPI thermal zone supports critical, passive, active[0] and active[1] at the same time,
it may register itself as a thermale_zone_device (thermal_zone1) with 4 trip points in all.
It has one processor and one fan, which are both registered as thermal_cooling_device.
If the processor is listed in _PSL method, and the fan is listed in _AL0 method,
the sys I/F structure will be built like this:
/sys/class/thermal:
|thermal_zone1:
|-----type: ACPI thermal zone
|-----temp: 37
|-----mode: kernel
|-----trip_point_0_temp: 100
|-----trip_point_0_type: critical
|-----trip_point_1_temp: 80
|-----trip_point_1_type: passive
|-----trip_point_2_temp: 70
|-----trip_point_2_type: active[0]
|-----trip_point_3_temp: 60
|-----trip_point_3_type: active[1]
|-----cdev0: --->/sys/class/thermal/cooling_device0
|-----cdev0_trip_point: 1 /* cdev0 can be used for passive */
|-----cdev1: --->/sys/class/thermal/cooling_device3
|-----cdev1_trip_point: 2 /* cdev1 can be used for active[0]*/
|cooling_device0:
|-----type: Processor
|-----max_state: 8
|-----cur_state: 0
|cooling_device3:
|-----type: Fan
|-----max_state: 2
|-----cur_state: 0

View File

@ -1,7 +1,7 @@
ThinkPad ACPI Extras Driver ThinkPad ACPI Extras Driver
Version 0.17 Version 0.19
October 04th, 2007 January 06th, 2008
Borislav Deianov <borislav@users.sf.net> Borislav Deianov <borislav@users.sf.net>
Henrique de Moraes Holschuh <hmh@hmh.eng.br> Henrique de Moraes Holschuh <hmh@hmh.eng.br>
@ -215,6 +215,11 @@ The following commands can be written to the /proc/acpi/ibm/hotkey file:
... any other 8-hex-digit mask ... ... any other 8-hex-digit mask ...
echo reset > /proc/acpi/ibm/hotkey -- restore the original mask echo reset > /proc/acpi/ibm/hotkey -- restore the original mask
The procfs interface does not support NVRAM polling control. So as to
maintain maximum bug-to-bug compatibility, it does not report any masks,
nor does it allow one to manipulate the hot key mask when the firmware
does not support masks at all, even if NVRAM polling is in use.
sysfs notes: sysfs notes:
hotkey_bios_enabled: hotkey_bios_enabled:
@ -231,17 +236,26 @@ sysfs notes:
to this value. to this value.
hotkey_enable: hotkey_enable:
Enables/disables the hot keys feature, and reports Enables/disables the hot keys feature in the ACPI
current status of the hot keys feature. firmware, and reports current status of the hot keys
feature. Has no effect on the NVRAM hot key polling
functionality.
0: disables the hot keys feature / feature disabled 0: disables the hot keys feature / feature disabled
1: enables the hot keys feature / feature enabled 1: enables the hot keys feature / feature enabled
hotkey_mask: hotkey_mask:
bit mask to enable driver-handling and ACPI event bit mask to enable driver-handling (and depending on
generation for each hot key (see above). Returns the the firmware, ACPI event generation) for each hot key
current status of the hot keys mask, and allows one to (see above). Returns the current status of the hot keys
modify it. mask, and allows one to modify it.
Note: when NVRAM polling is active, the firmware mask
will be different from the value returned by
hotkey_mask. The driver will retain enabled bits for
hotkeys that are under NVRAM polling even if the
firmware refuses them, and will not set these bits on
the firmware hot key mask.
hotkey_all_mask: hotkey_all_mask:
bit mask that should enable event reporting for all bit mask that should enable event reporting for all
@ -257,12 +271,48 @@ sysfs notes:
handled by the firmware anyway. Echo it to handled by the firmware anyway. Echo it to
hotkey_mask above, to use. hotkey_mask above, to use.
hotkey_source_mask:
bit mask that selects which hot keys will the driver
poll the NVRAM for. This is auto-detected by the driver
based on the capabilities reported by the ACPI firmware,
but it can be overridden at runtime.
Hot keys whose bits are set in both hotkey_source_mask
and also on hotkey_mask are polled for in NVRAM. Only a
few hot keys are available through CMOS NVRAM polling.
Warning: when in NVRAM mode, the volume up/down/mute
keys are synthesized according to changes in the mixer,
so you have to use volume up or volume down to unmute,
as per the ThinkPad volume mixer user interface. When
in ACPI event mode, volume up/down/mute are reported as
separate events, but this behaviour may be corrected in
future releases of this driver, in which case the
ThinkPad volume mixer user interface semanthics will be
enforced.
hotkey_poll_freq:
frequency in Hz for hot key polling. It must be between
0 and 25 Hz. Polling is only carried out when strictly
needed.
Setting hotkey_poll_freq to zero disables polling, and
will cause hot key presses that require NVRAM polling
to never be reported.
Setting hotkey_poll_freq too low will cause repeated
pressings of the same hot key to be misreported as a
single key press, or to not even be detected at all.
The recommended polling frequency is 10Hz.
hotkey_radio_sw: hotkey_radio_sw:
if the ThinkPad has a hardware radio switch, this if the ThinkPad has a hardware radio switch, this
attribute will read 0 if the switch is in the "radios attribute will read 0 if the switch is in the "radios
disabled" postition, and 1 if the switch is in the disabled" postition, and 1 if the switch is in the
"radios enabled" position. "radios enabled" position.
This attribute has poll()/select() support.
hotkey_report_mode: hotkey_report_mode:
Returns the state of the procfs ACPI event report mode Returns the state of the procfs ACPI event report mode
filter for hot keys. If it is set to 1 (the default), filter for hot keys. If it is set to 1 (the default),
@ -277,6 +327,25 @@ sysfs notes:
May return -EPERM (write access locked out by module May return -EPERM (write access locked out by module
parameter) or -EACCES (read-only). parameter) or -EACCES (read-only).
wakeup_reason:
Set to 1 if the system is waking up because the user
requested a bay ejection. Set to 2 if the system is
waking up because the user requested the system to
undock. Set to zero for normal wake-ups or wake-ups
due to unknown reasons.
This attribute has poll()/select() support.
wakeup_hotunplug_complete:
Set to 1 if the system was waken up because of an
undock or bay ejection request, and that request
was sucessfully completed. At this point, it might
be useful to send the system back to sleep, at the
user's choice. Refer to HKEY events 0x4003 and
0x3003, below.
This attribute has poll()/select() support.
input layer notes: input layer notes:
A Hot key is mapped to a single input layer EV_KEY event, possibly A Hot key is mapped to a single input layer EV_KEY event, possibly
@ -427,6 +496,23 @@ Non hot-key ACPI HKEY event map:
The above events are not propagated by the driver, except for legacy The above events are not propagated by the driver, except for legacy
compatibility purposes when hotkey_report_mode is set to 1. compatibility purposes when hotkey_report_mode is set to 1.
0x2304 System is waking up from suspend to undock
0x2305 System is waking up from suspend to eject bay
0x2404 System is waking up from hibernation to undock
0x2405 System is waking up from hibernation to eject bay
The above events are never propagated by the driver.
0x3003 Bay ejection (see 0x2x05) complete, can sleep again
0x4003 Undocked (see 0x2x04), can sleep again
0x5009 Tablet swivel: switched to tablet mode
0x500A Tablet swivel: switched to normal mode
0x500B Tablet pen insterted into its storage bay
0x500C Tablet pen removed from its storage bay
0x5010 Brightness level changed (newer Lenovo BIOSes)
The above events are propagated by the driver.
Compatibility notes: Compatibility notes:
ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never ibm-acpi and thinkpad-acpi 0.15 (mainline kernels before 2.6.23) never
@ -1263,3 +1349,17 @@ Sysfs interface changelog:
and the hwmon class for libsensors4 (lm-sensors 3) and the hwmon class for libsensors4 (lm-sensors 3)
compatibility. Moved all hwmon attributes to this compatibility. Moved all hwmon attributes to this
new platform device. new platform device.
0x020100: Marker for thinkpad-acpi with hot key NVRAM polling
support. If you must, use it to know you should not
start an userspace NVRAM poller (allows to detect when
NVRAM is compiled out by the user because it is
unneeded/undesired in the first place).
0x020101: Marker for thinkpad-acpi with hot key NVRAM polling
and proper hotkey_mask semanthics (version 8 of the
NVRAM polling patch). Some development snapshots of
0.18 had an earlier version that did strange things
to hotkey_mask.
0x020200: Add poll()/select() support to the following attributes:
hotkey_radio_sw, wakeup_hotunplug_complete, wakeup_reason

View File

@ -202,6 +202,13 @@ L: linux-scsi@vger.kernel.org
W: http://www.adaptec.com/ W: http://www.adaptec.com/
S: Supported S: Supported
ACER WMI LAPTOP EXTRAS
P: Carlos Corbacho
M: carlos@strangeworlds.co.uk
L: aceracpi@googlegroups.com (subscribers-only)
W: http://code.google.com/p/aceracpi
S: Maintained
ACPI ACPI
P: Len Brown P: Len Brown
M: len.brown@intel.com M: len.brown@intel.com
@ -252,6 +259,13 @@ L: linux-acpi@vger.kernel.org
W: http://acpi.sourceforge.net/ W: http://acpi.sourceforge.net/
S: Supported S: Supported
ACPI WMI DRIVER
P: Carlos Corbacho
M: carlos@strangeworlds.co.uk
L: linux-acpi@vger.kernel.org
W: http://www.lesswatts.org/projects/acpi/
S: Maintained
ADM1025 HARDWARE MONITOR DRIVER ADM1025 HARDWARE MONITOR DRIVER
P: Jean Delvare P: Jean Delvare
M: khali@linux-fr.org M: khali@linux-fr.org
@ -1790,6 +1804,11 @@ P: Jaroslav Kysela
M: perex@perex.cz M: perex@perex.cz
S: Maintained S: Maintained
HP COMPAQ TC1100 TABLET WMI EXTRAS DRIVER
P: Carlos Corbacho
M: carlos@strangeworlds.co.uk
S: Odd Fixes
HPET: High Precision Event Timers driver (hpet.c) HPET: High Precision Event Timers driver (hpet.c)
P: Clemens Ladisch P: Clemens Ladisch
M: clemens@ladisch.de M: clemens@ladisch.de

View File

@ -45,6 +45,12 @@ static void init_intel_pdc(struct acpi_processor *pr)
buf[0] = ACPI_PDC_REVISION_ID; buf[0] = ACPI_PDC_REVISION_ID;
buf[1] = 1; buf[1] = 1;
buf[2] = ACPI_PDC_EST_CAPABILITY_SMP; buf[2] = ACPI_PDC_EST_CAPABILITY_SMP;
/*
* The default of PDC_SMP_T_SWCOORD bit is set for IA64 cpu so
* that OSPM is capable of native ACPI throttling software
* coordination using BIOS supplied _TSD info.
*/
buf[2] |= ACPI_PDC_SMP_T_SWCOORD;
obj->type = ACPI_TYPE_BUFFER; obj->type = ACPI_TYPE_BUFFER;
obj->buffer.length = 12; obj->buffer.length = 12;

View File

@ -69,6 +69,20 @@ unsigned int acpi_cpei_phys_cpuid;
unsigned long acpi_wakeup_address = 0; unsigned long acpi_wakeup_address = 0;
#ifdef CONFIG_IA64_GENERIC
static unsigned long __init acpi_find_rsdp(void)
{
unsigned long rsdp_phys = 0;
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
rsdp_phys = efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
printk(KERN_WARNING PREFIX
"v1.0/r0.71 tables no longer supported\n");
return rsdp_phys;
}
#endif
const char __init * const char __init *
acpi_get_sysname(void) acpi_get_sysname(void)
{ {
@ -152,7 +166,7 @@ int acpi_request_vector(u32 int_type)
return vector; return vector;
} }
char *__acpi_map_table(unsigned long phys_addr, unsigned long size) char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
{ {
return __va(phys_addr); return __va(phys_addr);
} }
@ -601,8 +615,6 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
IOSAPIC_LEVEL); IOSAPIC_LEVEL);
} }
EXPORT_SYMBOL(acpi_register_gsi);
void acpi_unregister_gsi(u32 gsi) void acpi_unregister_gsi(u32 gsi)
{ {
if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM) if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM)
@ -611,8 +623,6 @@ void acpi_unregister_gsi(u32 gsi)
iosapic_unregister_intr(gsi); iosapic_unregister_intr(gsi);
} }
EXPORT_SYMBOL(acpi_unregister_gsi);
static int __init acpi_parse_fadt(struct acpi_table_header *table) static int __init acpi_parse_fadt(struct acpi_table_header *table)
{ {
struct acpi_table_header *fadt_header; struct acpi_table_header *fadt_header;
@ -631,18 +641,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
return 0; return 0;
} }
unsigned long __init acpi_find_rsdp(void)
{
unsigned long rsdp_phys = 0;
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
rsdp_phys = efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
printk(KERN_WARNING PREFIX
"v1.0/r0.71 tables no longer supported\n");
return rsdp_phys;
}
int __init acpi_boot_init(void) int __init acpi_boot_init(void)
{ {

View File

@ -105,6 +105,9 @@ config GENERIC_TIME_VSYSCALL
bool bool
default X86_64 default X86_64
config ARCH_HAS_CPU_RELAX
def_bool y
config HAVE_SETUP_PER_CPU_AREA config HAVE_SETUP_PER_CPU_AREA
def_bool X86_64 def_bool X86_64

View File

@ -78,7 +78,6 @@ int acpi_ht __initdata = 1; /* enable HT */
int acpi_lapic; int acpi_lapic;
int acpi_ioapic; int acpi_ioapic;
int acpi_strict; int acpi_strict;
EXPORT_SYMBOL(acpi_strict);
u8 acpi_sci_flags __initdata; u8 acpi_sci_flags __initdata;
int acpi_sci_override_gsi __initdata; int acpi_sci_override_gsi __initdata;
@ -106,7 +105,7 @@ enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
#ifdef CONFIG_X86_64 #ifdef CONFIG_X86_64
/* rely on all ACPI tables being in the direct mapping */ /* rely on all ACPI tables being in the direct mapping */
char *__acpi_map_table(unsigned long phys_addr, unsigned long size) char *__init __acpi_map_table(unsigned long phys_addr, unsigned long size)
{ {
if (!phys_addr || !size) if (!phys_addr || !size)
return NULL; return NULL;
@ -131,7 +130,7 @@ char *__acpi_map_table(unsigned long phys_addr, unsigned long size)
* from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and * from the fixed base. That's why we start at FIX_IO_APIC_BASE_END and
* count idx down while incrementing the phys address. * count idx down while incrementing the phys address.
*/ */
char *__acpi_map_table(unsigned long phys, unsigned long size) char *__init __acpi_map_table(unsigned long phys, unsigned long size)
{ {
unsigned long base, offset, mapped_size; unsigned long base, offset, mapped_size;
int idx; int idx;
@ -490,8 +489,6 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
return irq; return irq;
} }
EXPORT_SYMBOL(acpi_register_gsi);
/* /*
* ACPI based hotplug support for CPU * ACPI based hotplug support for CPU
*/ */
@ -587,25 +584,6 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
EXPORT_SYMBOL(acpi_unregister_ioapic); EXPORT_SYMBOL(acpi_unregister_ioapic);
static unsigned long __init
acpi_scan_rsdp(unsigned long start, unsigned long length)
{
unsigned long offset = 0;
unsigned long sig_len = sizeof("RSD PTR ") - 1;
/*
* Scan all 16-byte boundaries of the physical memory region for the
* RSDP signature.
*/
for (offset = 0; offset < length; offset += 16) {
if (strncmp((char *)(phys_to_virt(start) + offset), "RSD PTR ", sig_len))
continue;
return (start + offset);
}
return 0;
}
static int __init acpi_parse_sbf(struct acpi_table_header *table) static int __init acpi_parse_sbf(struct acpi_table_header *table)
{ {
struct acpi_table_boot *sb; struct acpi_table_boot *sb;
@ -748,27 +726,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
return 0; return 0;
} }
unsigned long __init acpi_find_rsdp(void)
{
unsigned long rsdp_phys = 0;
if (efi_enabled) {
if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
return efi.acpi20;
else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
return efi.acpi;
}
/*
* Scan memory looking for the RSDP signature. First search EBDA (low
* memory) paragraphs and then search upper memory (E0000-FFFFF).
*/
rsdp_phys = acpi_scan_rsdp(0, 0x400);
if (!rsdp_phys)
rsdp_phys = acpi_scan_rsdp(0xE0000, 0x20000);
return rsdp_phys;
}
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
/* /*
* Parse LAPIC entries in MADT * Parse LAPIC entries in MADT

View File

@ -46,6 +46,12 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
buf[1] = 1; buf[1] = 1;
buf[2] = ACPI_PDC_C_CAPABILITY_SMP; buf[2] = ACPI_PDC_C_CAPABILITY_SMP;
/*
* The default of PDC_SMP_T_SWCOORD bit is set for intel x86 cpu so
* that OSPM is capable of native ACPI throttling software
* coordination using BIOS supplied _TSD info.
*/
buf[2] |= ACPI_PDC_SMP_T_SWCOORD;
if (cpu_has(c, X86_FEATURE_EST)) if (cpu_has(c, X86_FEATURE_EST))
buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP; buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP;

View File

@ -189,10 +189,7 @@ static unsigned int pentium4_get_frequency(void)
printk(KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <linux@brodo.de>\n"); printk(KERN_DEBUG "speedstep-lib: couldn't detect FSB speed. Please send an e-mail to <linux@brodo.de>\n");
/* Multiplier. */ /* Multiplier. */
if (c->x86_model < 2) mult = msr_lo >> 24;
mult = msr_lo >> 27;
else
mult = msr_lo >> 24;
dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult)); dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult));

View File

@ -274,7 +274,7 @@ int __init get_memcfg_from_srat(void)
int tables = 0; int tables = 0;
int i = 0; int i = 0;
rsdp_address = acpi_find_rsdp(); rsdp_address = acpi_os_get_root_pointer();
if (!rsdp_address) { if (!rsdp_address) {
printk("%s: System description tables not found\n", printk("%s: System description tables not found\n",
__FUNCTION__); __FUNCTION__);

View File

@ -60,6 +60,8 @@ source "drivers/power/Kconfig"
source "drivers/hwmon/Kconfig" source "drivers/hwmon/Kconfig"
source "drivers/thermal/Kconfig"
source "drivers/watchdog/Kconfig" source "drivers/watchdog/Kconfig"
source "drivers/ssb/Kconfig" source "drivers/ssb/Kconfig"

View File

@ -65,6 +65,7 @@ obj-y += i2c/
obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_POWER_SUPPLY) += power/ obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/ obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_THERMAL) += thermal/
obj-$(CONFIG_WATCHDOG) += watchdog/ obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/ obj-$(CONFIG_MD) += md/

View File

@ -68,26 +68,28 @@ config ACPI_PROCFS
Say N to delete /proc/acpi/ files that have moved to /sys/ Say N to delete /proc/acpi/ files that have moved to /sys/
config ACPI_PROCFS_POWER config ACPI_PROCFS_POWER
bool "Deprecated power /proc/acpi folders" bool "Deprecated power /proc/acpi directories"
depends on PROC_FS depends on PROC_FS
default y default y
---help--- ---help---
For backwards compatibility, this option allows For backwards compatibility, this option allows
deprecated power /proc/acpi/ folders to exist, even when deprecated power /proc/acpi/ directories to exist, even when
they have been replaced by functions in /sys. they have been replaced by functions in /sys.
The deprecated folders (and their replacements) include: The deprecated directories (and their replacements) include:
/proc/acpi/battery/* (/sys/class/power_supply/*) /proc/acpi/battery/* (/sys/class/power_supply/*)
/proc/acpi/ac_adapter/* (sys/class/power_supply/*) /proc/acpi/ac_adapter/* (sys/class/power_supply/*)
This option has no effect on /proc/acpi/ folders This option has no effect on /proc/acpi/ directories
and functions, which do not yet exist in /sys and functions, which do not yet exist in /sys
Say N to delete power /proc/acpi/ folders that have moved to /sys/ Say N to delete power /proc/acpi/ directories that have moved to /sys/
config ACPI_SYSFS_POWER config ACPI_SYSFS_POWER
bool "Future power /sys interface" bool "Future power /sys interface"
select POWER_SUPPLY select POWER_SUPPLY
default y default y
---help--- ---help---
Say N to disable power /sys interface Say N to disable power /sys interface
config ACPI_PROC_EVENT config ACPI_PROC_EVENT
bool "Deprecated /proc/acpi/event support" bool "Deprecated /proc/acpi/event support"
depends on PROC_FS depends on PROC_FS
@ -186,6 +188,7 @@ config ACPI_HOTPLUG_CPU
config ACPI_THERMAL config ACPI_THERMAL
tristate "Thermal Zone" tristate "Thermal Zone"
depends on ACPI_PROCESSOR depends on ACPI_PROCESSOR
select THERMAL
default y default y
help help
This driver adds support for ACPI thermal zones. Most mobile and This driver adds support for ACPI thermal zones. Most mobile and
@ -199,6 +202,16 @@ config ACPI_NUMA
depends on (X86 || IA64) depends on (X86 || IA64)
default y if IA64_GENERIC || IA64_SGI_SN2 default y if IA64_GENERIC || IA64_SGI_SN2
config ACPI_WMI
tristate "WMI (EXPERIMENTAL)"
depends on EXPERIMENTAL
help
This driver adds support for the ACPI-WMI mapper device (PNP0C14)
found on some systems.
NOTE: You will need another driver or userspace application on top of
this to actually use anything defined in the ACPI-WMI mapper.
config ACPI_ASUS config ACPI_ASUS
tristate "ASUS/Medion Laptop Extras" tristate "ASUS/Medion Laptop Extras"
depends on X86 depends on X86
@ -263,8 +276,10 @@ config ACPI_CUSTOM_DSDT
depends on !STANDALONE depends on !STANDALONE
default n default n
help help
This option is to load a custom ACPI DSDT This option supports a custom DSDT by linking it into the kernel.
If you don't know what that is, say N. See Documentation/acpi/dsdt-override.txt
If unsure, say N.
config ACPI_CUSTOM_DSDT_FILE config ACPI_CUSTOM_DSDT_FILE
string "Custom DSDT Table file to include" string "Custom DSDT Table file to include"
@ -274,6 +289,17 @@ config ACPI_CUSTOM_DSDT_FILE
Enter the full path name to the file which includes the AmlCode Enter the full path name to the file which includes the AmlCode
declaration. declaration.
config ACPI_CUSTOM_DSDT_INITRD
bool "Read Custom DSDT from initramfs"
depends on BLK_DEV_INITRD
default n
help
This option supports a custom DSDT by optionally loading it from initrd.
See Documentation/acpi/dsdt-override.txt
If you are not using this feature now, but may use it later,
it is safe to say Y here.
config ACPI_BLACKLIST_YEAR config ACPI_BLACKLIST_YEAR
int "Disable ACPI for systems before Jan 1st this year" if X86_32 int "Disable ACPI for systems before Jan 1st this year" if X86_32
default 0 default 0

View File

@ -55,6 +55,7 @@ obj-$(CONFIG_ACPI_THERMAL) += thermal.o
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
obj-$(CONFIG_ACPI_DEBUG) += debug.o obj-$(CONFIG_ACPI_DEBUG) += debug.o
obj-$(CONFIG_ACPI_NUMA) += numa.o obj-$(CONFIG_ACPI_NUMA) += numa.o
obj-$(CONFIG_ACPI_WMI) += wmi.o
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o

View File

@ -142,6 +142,7 @@ struct asus_hotk {
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
A4S, //Z81sp A4S, //Z81sp
//(Centrino) //(Centrino)
F3Sa,
END_MODEL END_MODEL
} model; //Models currently supported } model; //Models currently supported
u16 event_count[128]; //count for each event TODO make this better u16 event_count[128]; //count for each event TODO make this better
@ -405,7 +406,20 @@ static struct model_data model_conf[END_MODEL] = {
.brightness_get = "GPLV", .brightness_get = "GPLV",
.mt_bt_switch = "BLED", .mt_bt_switch = "BLED",
.mt_wled = "WLED" .mt_wled = "WLED"
} },
{
.name = "F3Sa",
.mt_bt_switch = "BLED",
.mt_wled = "WLED",
.mt_mled = "MLED",
.brightness_get = "GPLV",
.brightness_set = "SPLV",
.mt_lcd_switch = "\\_SB.PCI0.SBRG.EC0._Q10",
.lcd_status = "\\_SB.PCI0.SBRG.EC0.RPIN",
.display_get = "\\ADVG",
.display_set = "SDSP",
},
}; };
@ -710,15 +724,8 @@ static int get_lcd_state(void)
{ {
int lcd = 0; int lcd = 0;
if (hotk->model != L3H) { if (hotk->model == L3H) {
/* We don't have to check anything if we are here */ /* L3H and the like have to be handled differently */
if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
printk(KERN_WARNING
"Asus ACPI: Error reading LCD status\n");
if (hotk->model == L2D)
lcd = ~lcd;
} else { /* L3H and the like have to be handled differently */
acpi_status status = 0; acpi_status status = 0;
struct acpi_object_list input; struct acpi_object_list input;
union acpi_object mt_params[2]; union acpi_object mt_params[2];
@ -745,6 +752,32 @@ static int get_lcd_state(void)
if (out_obj.type == ACPI_TYPE_INTEGER) if (out_obj.type == ACPI_TYPE_INTEGER)
/* That's what the AML code does */ /* That's what the AML code does */
lcd = out_obj.integer.value >> 8; lcd = out_obj.integer.value >> 8;
} else if (hotk->model == F3Sa) {
unsigned long tmp;
union acpi_object param;
struct acpi_object_list input;
acpi_status status;
/* Read pin 11 */
param.type = ACPI_TYPE_INTEGER;
param.integer.value = 0x11;
input.count = 1;
input.pointer = &param;
status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
&input, &tmp);
if (status != AE_OK)
return -1;
lcd = tmp;
} else {
/* We don't have to check anything if we are here */
if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
printk(KERN_WARNING
"Asus ACPI: Error reading LCD status\n");
if (hotk->model == L2D)
lcd = ~lcd;
} }
return (lcd & 1); return (lcd & 1);
@ -1134,6 +1167,8 @@ static int asus_model_match(char *model)
return W5A; return W5A;
else if (strncmp(model, "A4S", 3) == 0) else if (strncmp(model, "A4S", 3) == 0)
return A4S; return A4S;
else if (strncmp(model, "F3Sa", 4) == 0)
return F3Sa;
else else
return END_MODEL; return END_MODEL;
} }

View File

@ -194,6 +194,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
case POWER_SUPPLY_PROP_MANUFACTURER: case POWER_SUPPLY_PROP_MANUFACTURER:
val->strval = battery->oem_info; val->strval = battery->oem_info;
break; break;
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
val->strval = battery->serial_number;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
@ -212,6 +215,7 @@ static enum power_supply_property charge_battery_props[] = {
POWER_SUPPLY_PROP_CHARGE_NOW, POWER_SUPPLY_PROP_CHARGE_NOW,
POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
}; };
static enum power_supply_property energy_battery_props[] = { static enum power_supply_property energy_battery_props[] = {
@ -226,6 +230,7 @@ static enum power_supply_property energy_battery_props[] = {
POWER_SUPPLY_PROP_ENERGY_NOW, POWER_SUPPLY_PROP_ENERGY_NOW,
POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
}; };
#endif #endif

View File

@ -46,6 +46,12 @@ MODULE_LICENSE("GPL");
printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); } printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
static void bay_notify(acpi_handle handle, u32 event, void *data); static void bay_notify(acpi_handle handle, u32 event, void *data);
static const struct acpi_device_id bay_device_ids[] = {
{"LNXIOBAY", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, bay_device_ids);
struct bay { struct bay {
acpi_handle handle; acpi_handle handle;
char *name; char *name;
@ -128,7 +134,7 @@ static ssize_t show_present(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay)); return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
} }
DEVICE_ATTR(present, S_IRUGO, show_present, NULL); static DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
/* /*
* write_eject - write method for "eject" file in sysfs * write_eject - write method for "eject" file in sysfs
@ -144,7 +150,7 @@ static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
eject_device(bay->handle); eject_device(bay->handle);
return count; return count;
} }
DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject); static DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
/** /**
* is_ata - see if a device is an ata device * is_ata - see if a device is an ata device

View File

@ -70,8 +70,6 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
/* IBM 600E - _ADR should return 7, but it returns 1 */ /* IBM 600E - _ADR should return 7, but it returns 1 */
{"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
"Incorrect _ADR", 1}, "Incorrect _ADR", 1},
{"ASUS\0\0", "P2B-S ", 0, ACPI_SIG_DSDT, all_versions,
"Bogus PCI routing", 1},
{""} {""}
}; };
@ -208,33 +206,35 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* Disable OSI(Linux) warnings on all "Acer, inc." * Disable OSI(Linux) warnings on all "Acer, inc."
* *
* _OSI(Linux) disables the latest Windows BIOS code: * _OSI(Linux) disables the latest Windows BIOS code:
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"), * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5050"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"), * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"), * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
* _OSI(Linux) effect unknown: * _OSI(Linux) effect unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"), * DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
*/ */
{ /*
.callback = dmi_disable_osi_linux, * note that dmi_check_system() uses strstr()
.ident = "Acer, inc.", * to match sub-strings rather than !strcmp(),
.matches = { * so "Acer" below matches "Acer, inc." above.
DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."), */
},
},
/* /*
* Disable OSI(Linux) warnings on all "Acer" * Disable OSI(Linux) warnings on all "Acer"
* *
* _OSI(Linux) effect unknown: * _OSI(Linux) effect unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"), * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"), * DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"), * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"), * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"), * DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
* DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"), * DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
*
* _OSI(Linux) is a NOP:
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5315"),
*/ */
{ {
.callback = dmi_unknown_osi_linux, .callback = dmi_disable_osi_linux,
.ident = "Acer", .ident = "Acer",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"), DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
@ -242,21 +242,22 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
}, },
/* /*
* Disable OSI(Linux) warnings on all "Apple Computer, Inc." * Disable OSI(Linux) warnings on all "Apple Computer, Inc."
* Disable OSI(Linux) warnings on all "Apple Inc."
* *
* _OSI(Linux) confirmed to be a NOP: * _OSI(Linux) confirmed to be a NOP:
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"), * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"), * DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"), * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
* _OSI(Linux) effect unknown: * _OSI(Linux) effect unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"), * DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"), * DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
*/ */
{ {
.callback = dmi_disable_osi_linux, .callback = dmi_disable_osi_linux,
.ident = "Apple", .ident = "Apple",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Apple Computer, Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Apple"),
}, },
}, },
/* /*
@ -294,13 +295,13 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* DMI_MATCH(DMI_BOARD_NAME, "IFL91"), * DMI_MATCH(DMI_BOARD_NAME, "IFL91"),
*/ */
{ {
.callback = dmi_unknown_osi_linux, .callback = dmi_disable_osi_linux,
.ident = "Compal", .ident = "Compal",
.matches = { .matches = {
DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"), DMI_MATCH(DMI_BIOS_VENDOR, "COMPAL"),
}, },
}, },
{ /* OSI(Linux) touches USB, breaks suspend to disk */ { /* OSI(Linux) touches USB, unknown side-effect */
.callback = dmi_disable_osi_linux, .callback = dmi_disable_osi_linux,
.ident = "Dell Dimension 5150", .ident = "Dell Dimension 5150",
.matches = { .matches = {
@ -310,7 +311,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
}, },
{ /* OSI(Linux) is a NOP */ { /* OSI(Linux) is a NOP */
.callback = dmi_disable_osi_linux, .callback = dmi_disable_osi_linux,
.ident = "Dell", .ident = "Dell i1501",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"), DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1501"),
@ -318,7 +319,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
}, },
{ /* OSI(Linux) effect unknown */ { /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux, .callback = dmi_unknown_osi_linux,
.ident = "Dell", .ident = "Dell Latitude D830",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"), DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D830"),
@ -326,7 +327,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
}, },
{ /* OSI(Linux) effect unknown */ { /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux, .callback = dmi_unknown_osi_linux,
.ident = "Dell", .ident = "Dell OP GX620",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"), DMI_MATCH(DMI_PRODUCT_NAME, "OptiPlex GX620"),
@ -334,15 +335,23 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
}, },
{ /* OSI(Linux) effect unknown */ { /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux, .callback = dmi_unknown_osi_linux,
.ident = "Dell", .ident = "Dell PE 1900",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"), DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge 1900"),
}, },
}, },
{ /* OSI(Linux) is a NOP */
.callback = dmi_disable_osi_linux,
.ident = "Dell PE R200",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge R200"),
},
},
{ /* OSI(Linux) touches USB */ { /* OSI(Linux) touches USB */
.callback = dmi_disable_osi_linux, .callback = dmi_disable_osi_linux,
.ident = "Dell", .ident = "Dell PR 390",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"), DMI_MATCH(DMI_PRODUCT_NAME, "Precision WorkStation 390"),
@ -358,7 +367,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
}, },
{ /* OSI(Linux) effect unknown */ { /* OSI(Linux) effect unknown */
.callback = dmi_unknown_osi_linux, .callback = dmi_unknown_osi_linux,
.ident = "Dell", .ident = "Dell PE SC440",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"), DMI_MATCH(DMI_PRODUCT_NAME, "PowerEdge SC440"),
@ -474,6 +483,11 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* *
* _OSI(Linux) confirmed to be a NOP: * _OSI(Linux) confirmed to be a NOP:
* DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"), * DMI_MATCH(DMI_PRODUCT_NAME, "P1-J150B"),
* with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
*
* unknown:
* DMI_MATCH(DMI_PRODUCT_NAME, "S1-MDGDG"),
* with DMI_MATCH(DMI_BOARD_NAME, "ROCKY"),
*/ */
{ {
.callback = dmi_disable_osi_linux, .callback = dmi_disable_osi_linux,
@ -516,7 +530,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
* DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"), * DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
*/ */
{ {
.callback = dmi_unknown_osi_linux, .callback = dmi_disable_osi_linux,
.ident = "Sony", .ident = "Sony",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),

View File

@ -122,6 +122,31 @@ int acpi_bus_get_status(struct acpi_device *device)
EXPORT_SYMBOL(acpi_bus_get_status); EXPORT_SYMBOL(acpi_bus_get_status);
void acpi_bus_private_data_handler(acpi_handle handle,
u32 function, void *context)
{
return;
}
EXPORT_SYMBOL(acpi_bus_private_data_handler);
int acpi_bus_get_private_data(acpi_handle handle, void **data)
{
acpi_status status = AE_OK;
if (!*data)
return -EINVAL;
status = acpi_get_data(handle, acpi_bus_private_data_handler, data);
if (ACPI_FAILURE(status) || !*data) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
handle));
return -ENODEV;
}
return 0;
}
EXPORT_SYMBOL(acpi_bus_get_private_data);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Power Management Power Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
@ -366,7 +391,6 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
return 0; return 0;
} }
EXPORT_SYMBOL(acpi_bus_receive_event);
#endif /* CONFIG_ACPI_PROC_EVENT */ #endif /* CONFIG_ACPI_PROC_EVENT */
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------

View File

@ -130,6 +130,63 @@ static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644); module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644); module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
static char trace_method_name[6];
module_param_string(trace_method_name, trace_method_name, 6, 0644);
static unsigned int trace_debug_layer;
module_param(trace_debug_layer, uint, 0644);
static unsigned int trace_debug_level;
module_param(trace_debug_level, uint, 0644);
static int param_set_trace_state(const char *val, struct kernel_param *kp)
{
int result = 0;
if (!strncmp(val, "enable", strlen("enable") - 1)) {
result = acpi_debug_trace(trace_method_name, trace_debug_level,
trace_debug_layer, 0);
if (result)
result = -EBUSY;
goto exit;
}
if (!strncmp(val, "disable", strlen("disable") - 1)) {
int name = 0;
result = acpi_debug_trace((char *)&name, trace_debug_level,
trace_debug_layer, 0);
if (result)
result = -EBUSY;
goto exit;
}
if (!strncmp(val, "1", 1)) {
result = acpi_debug_trace(trace_method_name, trace_debug_level,
trace_debug_layer, 1);
if (result)
result = -EBUSY;
goto exit;
}
result = -EINVAL;
exit:
return result;
}
static int param_get_trace_state(char *buffer, struct kernel_param *kp)
{
if (!acpi_gbl_trace_method_name)
return sprintf(buffer, "disable");
else {
if (acpi_gbl_trace_flags & 1)
return sprintf(buffer, "1");
else
return sprintf(buffer, "enable");
}
return 0;
}
module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
NULL, 0644);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
FS Interface (/proc) FS Interface (/proc)
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */

View File

@ -359,7 +359,9 @@ acpi_status acpi_ds_get_region_arguments(union acpi_operand_object *obj_desc)
status = acpi_os_validate_address(obj_desc->region.space_id, status = acpi_os_validate_address(obj_desc->region.space_id,
obj_desc->region.address, obj_desc->region.address,
(acpi_size) obj_desc->region.length); (acpi_size) obj_desc->region.length,
acpi_ut_get_node_name(node));
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
/* /*
* Invalid address/length. We will emit an error message and mark * Invalid address/length. We will emit an error message and mark

View File

@ -51,6 +51,12 @@ 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"; static char dock_device_name[] = "dock";
static const struct acpi_device_id dock_device_ids[] = {
{"LNXDOCK", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, dock_device_ids);
struct dock_station { struct dock_station {
acpi_handle handle; acpi_handle handle;
unsigned long last_dock_time; unsigned long last_dock_time;
@ -680,7 +686,7 @@ static ssize_t show_docked(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station)); return snprintf(buf, PAGE_SIZE, "%d\n", dock_present(dock_station));
} }
DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
/* /*
* show_flags - read method for flags file in sysfs * show_flags - read method for flags file in sysfs
@ -691,7 +697,7 @@ static ssize_t show_flags(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
} }
DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); static DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
/* /*
* write_undock - write method for "undock" file in sysfs * write_undock - write method for "undock" file in sysfs
@ -707,7 +713,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST); ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
return ret ? ret: count; return ret ? ret: count;
} }
DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock); static DEVICE_ATTR(undock, S_IWUSR, NULL, write_undock);
/* /*
* show_dock_uid - read method for "uid" file in sysfs * show_dock_uid - read method for "uid" file in sysfs
@ -723,7 +729,7 @@ static ssize_t show_dock_uid(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf); return snprintf(buf, PAGE_SIZE, "%lx\n", lbuf);
} }
DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
/** /**
* dock_add - add a new dock station * dock_add - add a new dock station

View File

@ -573,7 +573,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
void *handler_context, void *region_context) void *handler_context, void *region_context)
{ {
struct acpi_ec *ec = handler_context; struct acpi_ec *ec = handler_context;
int result = 0, i = 0; int result = 0, i;
u8 temp = 0; u8 temp = 0;
if ((address > 0xFF) || !value || !handler_context) if ((address > 0xFF) || !value || !handler_context)
@ -585,7 +585,18 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
if (bits != 8 && acpi_strict) if (bits != 8 && acpi_strict)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
while (bits - i > 0) { acpi_ec_burst_enable(ec);
if (function == ACPI_READ) {
result = acpi_ec_read(ec, address, &temp);
*value = temp;
} else {
temp = 0xff & (*value);
result = acpi_ec_write(ec, address, temp);
}
for (i = 8; unlikely(bits - i > 0); i += 8) {
++address;
if (function == ACPI_READ) { if (function == ACPI_READ) {
result = acpi_ec_read(ec, address, &temp); result = acpi_ec_read(ec, address, &temp);
(*value) |= ((acpi_integer)temp) << i; (*value) |= ((acpi_integer)temp) << i;
@ -593,10 +604,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
temp = 0xff & ((*value) >> i); temp = 0xff & ((*value) >> i);
result = acpi_ec_write(ec, address, temp); result = acpi_ec_write(ec, address, temp);
} }
i += 8;
++address;
} }
acpi_ec_burst_disable(ec);
switch (result) { switch (result) {
case -EINVAL: case -EINVAL:
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;

View File

@ -109,6 +109,34 @@ static const struct file_operations acpi_system_event_ops = {
}; };
#endif /* CONFIG_ACPI_PROC_EVENT */ #endif /* CONFIG_ACPI_PROC_EVENT */
/* ACPI notifier chain */
BLOCKING_NOTIFIER_HEAD(acpi_chain_head);
int acpi_notifier_call_chain(struct acpi_device *dev, u32 type, u32 data)
{
struct acpi_bus_event event;
strcpy(event.device_class, dev->pnp.device_class);
strcpy(event.bus_id, dev->pnp.bus_id);
event.type = type;
event.data = data;
return (blocking_notifier_call_chain(&acpi_chain_head, 0, (void *)&event)
== NOTIFY_BAD) ? -EINVAL : 0;
}
EXPORT_SYMBOL(acpi_notifier_call_chain);
int register_acpi_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&acpi_chain_head, nb);
}
EXPORT_SYMBOL(register_acpi_notifier);
int unregister_acpi_notifier(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&acpi_chain_head, nb);
}
EXPORT_SYMBOL(unregister_acpi_notifier);
#ifdef CONFIG_NET #ifdef CONFIG_NET
static unsigned int acpi_event_seqnum; static unsigned int acpi_event_seqnum;
struct acpi_genl_event { struct acpi_genl_event {

View File

@ -259,7 +259,7 @@ u32 acpi_ev_fixed_event_detect(void)
enable_bit_mask)) { enable_bit_mask)) {
/* Found an active (signalled) event */ /* Found an active (signalled) event */
acpi_os_fixed_event_count(i);
int_status |= acpi_ev_fixed_event_dispatch((u32) i); int_status |= acpi_ev_fixed_event_dispatch((u32) i);
} }
} }

View File

@ -270,18 +270,18 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
case ACPI_GPE_TYPE_WAKE_RUN: case ACPI_GPE_TYPE_WAKE_RUN:
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED); ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
/*lint -fallthrough */ /* fallthrough */
case ACPI_GPE_TYPE_RUNTIME: case ACPI_GPE_TYPE_RUNTIME:
/* Disable the requested runtime GPE */ /* Disable the requested runtime GPE */
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED); ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
break; /* fallthrough */
default: default:
return_ACPI_STATUS(AE_BAD_PARAMETER); acpi_hw_write_gpe_enable_reg(gpe_event_info);
} }
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
@ -501,6 +501,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
* an interrupt handler. * an interrupt handler.
* *
******************************************************************************/ ******************************************************************************/
static void acpi_ev_asynch_enable_gpe(void *context);
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context) static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{ {
@ -576,22 +577,30 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
method_node))); method_node)));
} }
} }
/* Defer enabling of GPE until all notify handlers are done */
acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_ev_asynch_enable_gpe,
gpe_event_info);
return_VOID;
}
if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == static void acpi_ev_asynch_enable_gpe(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = context;
acpi_status status;
if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
ACPI_GPE_LEVEL_TRIGGERED) { ACPI_GPE_LEVEL_TRIGGERED) {
/* /*
* GPE is level-triggered, we clear the GPE status bit after * GPE is level-triggered, we clear the GPE status bit after
* handling the event. * handling the event.
*/ */
status = acpi_hw_clear_gpe(&local_gpe_event_info); status = acpi_hw_clear_gpe(gpe_event_info);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_VOID; return_VOID;
} }
} }
/* Enable this GPE */ /* Enable this GPE */
(void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
(void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info);
return_VOID; return_VOID;
} }
@ -618,7 +627,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
ACPI_FUNCTION_TRACE(ev_gpe_dispatch); ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
acpi_gpe_count++; acpi_os_gpe_count(gpe_number);
/* /*
* If edge-triggered, clear the GPE status bit now. Note that * If edge-triggered, clear the GPE status bit now. Note that

View File

@ -30,7 +30,7 @@
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
@ -68,9 +68,55 @@ static struct acpi_driver acpi_fan_driver = {
}, },
}; };
/* thermal cooling device callbacks */
static int fan_get_max_state(struct thermal_cooling_device *cdev, char *buf)
{
/* ACPI fan device only support two states: ON/OFF */
return sprintf(buf, "1\n");
}
static int fan_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
{
struct acpi_device *device = cdev->devdata;
int state;
int result;
if (!device)
return -EINVAL;
result = acpi_bus_get_power(device->handle, &state);
if (result)
return result;
return sprintf(buf, "%s\n", state == ACPI_STATE_D3 ? "0" :
(state == ACPI_STATE_D0 ? "1" : "unknown"));
}
static int
fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
{
struct acpi_device *device = cdev->devdata;
int result;
if (!device || (state != 0 && state != 1))
return -EINVAL;
result = acpi_bus_set_power(device->handle,
state ? ACPI_STATE_D0 : ACPI_STATE_D3);
return result;
}
static struct thermal_cooling_device_ops fan_cooling_ops = {
.get_max_state = fan_get_max_state,
.get_cur_state = fan_get_cur_state,
.set_cur_state = fan_set_cur_state,
};
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
FS Interface (/proc) FS Interface (/proc)
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
#ifdef CONFIG_ACPI_PROCFS
static struct proc_dir_entry *acpi_fan_dir; static struct proc_dir_entry *acpi_fan_dir;
@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
return 0; return 0;
} }
#else
static int acpi_fan_add_fs(struct acpi_device *device)
{
return 0;
}
static int acpi_fan_remove_fs(struct acpi_device *device)
{
return 0;
}
#endif
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Driver Interface Driver Interface
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
static int acpi_fan_add(struct acpi_device *device) static int acpi_fan_add(struct acpi_device *device)
{ {
int result = 0; int result = 0;
struct acpi_fan *fan = NULL;
int state = 0; int state = 0;
struct thermal_cooling_device *cdev;
if (!device) if (!device)
return -EINVAL; return -EINVAL;
@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device)
acpi_bus_set_power(device->handle, state); acpi_bus_set_power(device->handle, state);
device->flags.force_power_state = 0; device->flags.force_power_state = 0;
cdev = thermal_cooling_device_register("Fan", device,
&fan_cooling_ops);
if (cdev)
printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n",
device->dev.bus_id, cdev->id);
else
goto end;
acpi_driver_data(device) = cdev;
result = sysfs_create_link(&device->dev.kobj, &cdev->device.kobj,
"thermal_cooling");
if (result)
return result;
result = sysfs_create_link(&cdev->device.kobj, &device->dev.kobj,
"device");
if (result)
return result;
result = acpi_fan_add_fs(device); result = acpi_fan_add_fs(device);
if (result) if (result)
goto end; goto end;
@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device)
!device->power.state ? "on" : "off"); !device->power.state ? "on" : "off");
end: end:
if (result)
kfree(fan);
return result; return result;
} }
static int acpi_fan_remove(struct acpi_device *device, int type) static int acpi_fan_remove(struct acpi_device *device, int type)
{ {
if (!device || !acpi_driver_data(device)) struct thermal_cooling_device *cdev = acpi_driver_data(device);
if (!device || !cdev)
return -EINVAL; return -EINVAL;
acpi_fan_remove_fs(device); acpi_fan_remove_fs(device);
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&cdev->device.kobj, "device");
thermal_cooling_device_unregister(cdev);
return 0; return 0;
} }
@ -261,10 +337,12 @@ static int __init acpi_fan_init(void)
int result = 0; int result = 0;
#ifdef CONFIG_ACPI_PROCFS
acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir); acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
if (!acpi_fan_dir) if (!acpi_fan_dir)
return -ENODEV; return -ENODEV;
acpi_fan_dir->owner = THIS_MODULE; acpi_fan_dir->owner = THIS_MODULE;
#endif
result = acpi_bus_register_driver(&acpi_fan_driver); result = acpi_bus_register_driver(&acpi_fan_driver);
if (result < 0) { if (result < 0) {

View File

@ -36,8 +36,6 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
return -ENODEV; return -ENODEV;
} }
EXPORT_SYMBOL(register_acpi_bus_type);
int unregister_acpi_bus_type(struct acpi_bus_type *type) int unregister_acpi_bus_type(struct acpi_bus_type *type)
{ {
if (acpi_disabled) if (acpi_disabled)
@ -53,8 +51,6 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
return -ENODEV; return -ENODEV;
} }
EXPORT_SYMBOL(unregister_acpi_bus_type);
static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type) static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
{ {
struct acpi_bus_type *tmp, *ret = NULL; struct acpi_bus_type *tmp, *ret = NULL;

View File

@ -286,13 +286,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
} }
/* /*
* 1) Disable/Clear all GPEs
* 2) Enable all wakeup GPEs * 2) Enable all wakeup GPEs
*/ */
status = acpi_hw_disable_all_gpes(); status = acpi_hw_disable_all_gpes();
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
acpi_gbl_system_awake_and_running = FALSE; acpi_gbl_system_awake_and_running = FALSE;
status = acpi_hw_enable_all_wakeup_gpes(); status = acpi_hw_enable_all_wakeup_gpes();

View File

@ -443,6 +443,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
struct acpica_device_id hid; struct acpica_device_id hid;
struct acpi_compatible_id_list *cid; struct acpi_compatible_id_list *cid;
acpi_native_uint i; acpi_native_uint i;
int found;
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE); status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
@ -496,16 +497,19 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
/* Walk the CID list */ /* Walk the CID list */
found = 0;
for (i = 0; i < cid->count; i++) { for (i = 0; i < cid->count; i++) {
if (ACPI_STRNCMP(cid->id[i].value, info->hid, if (ACPI_STRNCMP(cid->id[i].value, info->hid,
sizeof(struct sizeof(struct
acpi_compatible_id)) != acpi_compatible_id)) ==
0) { 0) {
ACPI_FREE(cid); found = 1;
return (AE_OK); break;
} }
} }
ACPI_FREE(cid); ACPI_FREE(cid);
if (!found)
return (AE_OK);
} }
} }

View File

@ -78,6 +78,7 @@ int acpi_map_pxm_to_node(int pxm)
return node; return node;
} }
#if 0
void __cpuinit acpi_unmap_pxm_to_node(int node) void __cpuinit acpi_unmap_pxm_to_node(int node)
{ {
int pxm = node_to_pxm_map[node]; int pxm = node_to_pxm_map[node];
@ -85,6 +86,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
node_to_pxm_map[node] = PXM_INVAL; node_to_pxm_map[node] = PXM_INVAL;
node_clear(node, nodes_found_map); node_clear(node, nodes_found_map);
} }
#endif /* 0 */
static void __init static void __init
acpi_table_print_srat_entry(struct acpi_subtable_header *header) acpi_table_print_srat_entry(struct acpi_subtable_header *header)
@ -247,7 +249,6 @@ int acpi_get_pxm(acpi_handle h)
} while (ACPI_SUCCESS(status)); } while (ACPI_SUCCESS(status));
return -1; return -1;
} }
EXPORT_SYMBOL(acpi_get_pxm);
int acpi_get_node(acpi_handle *handle) int acpi_get_node(acpi_handle *handle)
{ {

View File

@ -44,6 +44,8 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/efi.h> #include <linux/efi.h>
#include <linux/ioport.h>
#include <linux/list.h>
#define _COMPONENT ACPI_OS_SERVICES #define _COMPONENT ACPI_OS_SERVICES
ACPI_MODULE_NAME("osl"); ACPI_MODULE_NAME("osl");
@ -74,9 +76,25 @@ static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq; static struct workqueue_struct *kacpid_wq;
static struct workqueue_struct *kacpi_notify_wq; static struct workqueue_struct *kacpi_notify_wq;
struct acpi_res_list {
resource_size_t start;
resource_size_t end;
acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
char name[5]; /* only can have a length of 4 chars, make use of this
one instead of res->name, no need to kalloc then */
struct list_head resource_list;
};
static LIST_HEAD(resource_list_head);
static DEFINE_SPINLOCK(acpi_res_lock);
#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */ #define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
static char osi_additional_string[OSI_STRING_LENGTH_MAX]; static char osi_additional_string[OSI_STRING_LENGTH_MAX];
#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
static int acpi_no_initrd_override;
#endif
/* /*
* "Ode to _OSI(Linux)" * "Ode to _OSI(Linux)"
* *
@ -120,7 +138,7 @@ static char osi_additional_string[OSI_STRING_LENGTH_MAX];
*/ */
#define OSI_LINUX_ENABLE 0 #define OSI_LINUX_ENABLE 0
struct osi_linux { static struct osi_linux {
unsigned int enable:1; unsigned int enable:1;
unsigned int dmi:1; unsigned int dmi:1;
unsigned int cmdline:1; unsigned int cmdline:1;
@ -219,8 +237,6 @@ void acpi_os_printf(const char *fmt, ...)
va_end(args); va_end(args);
} }
EXPORT_SYMBOL(acpi_os_printf);
void acpi_os_vprintf(const char *fmt, va_list args) void acpi_os_vprintf(const char *fmt, va_list args)
{ {
static char buffer[512]; static char buffer[512];
@ -250,11 +266,16 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
"System description tables not found\n"); "System description tables not found\n");
return 0; return 0;
} }
} else } else {
return acpi_find_rsdp(); acpi_physical_address pa = 0;
acpi_find_root_pointer(&pa);
return pa;
}
} }
void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size) void __iomem *__init_refok
acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
{ {
if (phys > ULONG_MAX) { if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n"); printk(KERN_ERR PREFIX "Cannot map memory that high\n");
@ -312,6 +333,67 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
return AE_OK; return AE_OK;
} }
#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
struct acpi_table_header *acpi_find_dsdt_initrd(void)
{
struct file *firmware_file;
mm_segment_t oldfs;
unsigned long len, len2;
struct acpi_table_header *dsdt_buffer, *ret = NULL;
struct kstat stat;
char *ramfs_dsdt_name = "/DSDT.aml";
printk(KERN_INFO PREFIX "Checking initramfs for custom DSDT");
/*
* Never do this at home, only the user-space is allowed to open a file.
* The clean way would be to use the firmware loader.
* But this code must be run before there is any userspace available.
* A static/init firmware infrastructure doesn't exist yet...
*/
if (vfs_stat(ramfs_dsdt_name, &stat) < 0)
return ret;
len = stat.size;
/* check especially against empty files */
if (len <= 4) {
printk(KERN_ERR PREFIX "Failed: DSDT only %lu bytes.\n", len);
return ret;
}
firmware_file = filp_open(ramfs_dsdt_name, O_RDONLY, 0);
if (IS_ERR(firmware_file)) {
printk(KERN_ERR PREFIX "Failed to open %s.\n", ramfs_dsdt_name);
return ret;
}
dsdt_buffer = kmalloc(len, GFP_ATOMIC);
if (!dsdt_buffer) {
printk(KERN_ERR PREFIX "Failed to allocate %lu bytes.\n", len);
goto err;
}
oldfs = get_fs();
set_fs(KERNEL_DS);
len2 = vfs_read(firmware_file, (char __user *)dsdt_buffer, len,
&firmware_file->f_pos);
set_fs(oldfs);
if (len2 < len) {
printk(KERN_ERR PREFIX "Failed to read %lu bytes from %s.\n",
len, ramfs_dsdt_name);
ACPI_FREE(dsdt_buffer);
goto err;
}
printk(KERN_INFO PREFIX "Found %lu byte DSDT in %s.\n",
len, ramfs_dsdt_name);
ret = dsdt_buffer;
err:
filp_close(firmware_file, NULL);
return ret;
}
#endif
acpi_status acpi_status
acpi_os_table_override(struct acpi_table_header * existing_table, acpi_os_table_override(struct acpi_table_header * existing_table,
struct acpi_table_header ** new_table) struct acpi_table_header ** new_table)
@ -319,20 +401,52 @@ acpi_os_table_override(struct acpi_table_header * existing_table,
if (!existing_table || !new_table) if (!existing_table || !new_table)
return AE_BAD_PARAMETER; return AE_BAD_PARAMETER;
*new_table = NULL;
#ifdef CONFIG_ACPI_CUSTOM_DSDT #ifdef CONFIG_ACPI_CUSTOM_DSDT
if (strncmp(existing_table->signature, "DSDT", 4) == 0) if (strncmp(existing_table->signature, "DSDT", 4) == 0)
*new_table = (struct acpi_table_header *)AmlCode; *new_table = (struct acpi_table_header *)AmlCode;
else
*new_table = NULL;
#else
*new_table = NULL;
#endif #endif
#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
if ((strncmp(existing_table->signature, "DSDT", 4) == 0) &&
!acpi_no_initrd_override) {
struct acpi_table_header *initrd_table;
initrd_table = acpi_find_dsdt_initrd();
if (initrd_table)
*new_table = initrd_table;
}
#endif
if (*new_table != NULL) {
printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
"this is unsafe: tainting kernel\n",
existing_table->signature,
existing_table->oem_table_id);
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
}
return AE_OK; return AE_OK;
} }
#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
int __init acpi_no_initrd_override_setup(char *s)
{
acpi_no_initrd_override = 1;
return 1;
}
__setup("acpi_no_initrd_override", acpi_no_initrd_override_setup);
#endif
static irqreturn_t acpi_irq(int irq, void *dev_id) static irqreturn_t acpi_irq(int irq, void *dev_id)
{ {
return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE; u32 handled;
handled = (*acpi_irq_handler) (acpi_irq_context);
if (handled) {
acpi_irq_handled++;
return IRQ_HANDLED;
} else
return IRQ_NONE;
} }
acpi_status acpi_status
@ -341,6 +455,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
{ {
unsigned int irq; unsigned int irq;
acpi_irq_stats_init();
/* /*
* Ignore the GSI from the core, and use the value in our copy of the * Ignore the GSI from the core, and use the value in our copy of the
* FADT. It may not be the same if an interrupt source override exists * FADT. It may not be the same if an interrupt source override exists
@ -384,8 +500,6 @@ void acpi_os_sleep(acpi_integer ms)
schedule_timeout_interruptible(msecs_to_jiffies(ms)); schedule_timeout_interruptible(msecs_to_jiffies(ms));
} }
EXPORT_SYMBOL(acpi_os_sleep);
void acpi_os_stall(u32 us) void acpi_os_stall(u32 us)
{ {
while (us) { while (us) {
@ -399,8 +513,6 @@ void acpi_os_stall(u32 us)
} }
} }
EXPORT_SYMBOL(acpi_os_stall);
/* /*
* Support ACPI 3.0 AML Timer operand * Support ACPI 3.0 AML Timer operand
* Returns 64-bit free-running, monotonically increasing timer * Returns 64-bit free-running, monotonically increasing timer
@ -550,8 +662,6 @@ acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
return (result ? AE_ERROR : AE_OK); return (result ? AE_ERROR : AE_OK);
} }
EXPORT_SYMBOL(acpi_os_read_pci_configuration);
acpi_status acpi_status
acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
acpi_integer value, u32 width) acpi_integer value, u32 width)
@ -661,25 +771,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
dpc->function(dpc->context); dpc->function(dpc->context);
kfree(dpc); kfree(dpc);
/* Yield cpu to notify thread */
cond_resched();
return;
}
static void acpi_os_execute_notify(struct work_struct *work)
{
struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
if (!dpc) {
printk(KERN_ERR PREFIX "Invalid (NULL) context\n");
return;
}
dpc->function(dpc->context);
kfree(dpc);
return; return;
} }
@ -703,7 +794,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_os_dpc *dpc; struct acpi_os_dpc *dpc;
struct workqueue_struct *queue;
ACPI_DEBUG_PRINT((ACPI_DB_EXEC, ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
"Scheduling function [%p(%p)] for deferred execution.\n", "Scheduling function [%p(%p)] for deferred execution.\n",
function, context)); function, context));
@ -727,20 +818,13 @@ acpi_status acpi_os_execute(acpi_execute_type type,
dpc->function = function; dpc->function = function;
dpc->context = context; dpc->context = context;
if (type == OSL_NOTIFY_HANDLER) { INIT_WORK(&dpc->work, acpi_os_execute_deferred);
INIT_WORK(&dpc->work, acpi_os_execute_notify); queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
if (!queue_work(kacpi_notify_wq, &dpc->work)) { if (!queue_work(queue, &dpc->work)) {
status = AE_ERROR; ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
kfree(dpc); "Call to queue_work() failed.\n"));
} status = AE_ERROR;
} else { kfree(dpc);
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
if (!queue_work(kacpid_wq, &dpc->work)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Call to queue_work() failed.\n"));
status = AE_ERROR;
kfree(dpc);
}
} }
return_ACPI_STATUS(status); return_ACPI_STATUS(status);
} }
@ -793,8 +877,6 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
return AE_OK; return AE_OK;
} }
EXPORT_SYMBOL(acpi_os_create_semaphore);
/* /*
* TODO: A better way to delete semaphores? Linux doesn't have a * TODO: A better way to delete semaphores? Linux doesn't have a
* 'delete_semaphore()' function -- may result in an invalid * 'delete_semaphore()' function -- may result in an invalid
@ -818,8 +900,6 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle)
return AE_OK; return AE_OK;
} }
EXPORT_SYMBOL(acpi_os_delete_semaphore);
/* /*
* TODO: The kernel doesn't have a 'down_timeout' function -- had to * TODO: The kernel doesn't have a 'down_timeout' function -- had to
* improvise. The process is to sleep for one scheduler quantum * improvise. The process is to sleep for one scheduler quantum
@ -912,8 +992,6 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
return status; return status;
} }
EXPORT_SYMBOL(acpi_os_wait_semaphore);
/* /*
* TODO: Support for units > 1? * TODO: Support for units > 1?
*/ */
@ -936,8 +1014,6 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
return AE_OK; return AE_OK;
} }
EXPORT_SYMBOL(acpi_os_signal_semaphore);
#ifdef ACPI_FUTURE_USAGE #ifdef ACPI_FUTURE_USAGE
u32 acpi_os_get_line(char *buffer) u32 acpi_os_get_line(char *buffer)
{ {
@ -981,8 +1057,6 @@ acpi_status acpi_os_signal(u32 function, void *info)
return AE_OK; return AE_OK;
} }
EXPORT_SYMBOL(acpi_os_signal);
static int __init acpi_os_name_setup(char *str) static int __init acpi_os_name_setup(char *str)
{ {
char *p = acpi_os_name; char *p = acpi_os_name;
@ -1102,6 +1176,128 @@ static int __init acpi_wake_gpes_always_on_setup(char *str)
__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup); __setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
/* Check of resource interference between native drivers and ACPI
* OperationRegions (SystemIO and System Memory only).
* IO ports and memory declared in ACPI might be used by the ACPI subsystem
* in arbitrary AML code and can interfere with legacy drivers.
* acpi_enforce_resources= can be set to:
*
* - strict (2)
* -> further driver trying to access the resources will not load
* - lax (default) (1)
* -> further driver trying to access the resources will load, but you
* get a system message that something might go wrong...
*
* - no (0)
* -> ACPI Operation Region resources will not be registered
*
*/
#define ENFORCE_RESOURCES_STRICT 2
#define ENFORCE_RESOURCES_LAX 1
#define ENFORCE_RESOURCES_NO 0
static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
static int __init acpi_enforce_resources_setup(char *str)
{
if (str == NULL || *str == '\0')
return 0;
if (!strcmp("strict", str))
acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
else if (!strcmp("lax", str))
acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
else if (!strcmp("no", str))
acpi_enforce_resources = ENFORCE_RESOURCES_NO;
return 1;
}
__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
/* Check for resource conflicts between ACPI OperationRegions and native
* drivers */
int acpi_check_resource_conflict(struct resource *res)
{
struct acpi_res_list *res_list_elem;
int ioport;
int clash = 0;
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
return 0;
if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
return 0;
ioport = res->flags & IORESOURCE_IO;
spin_lock(&acpi_res_lock);
list_for_each_entry(res_list_elem, &resource_list_head,
resource_list) {
if (ioport && (res_list_elem->resource_type
!= ACPI_ADR_SPACE_SYSTEM_IO))
continue;
if (!ioport && (res_list_elem->resource_type
!= ACPI_ADR_SPACE_SYSTEM_MEMORY))
continue;
if (res->end < res_list_elem->start
|| res_list_elem->end < res->start)
continue;
clash = 1;
break;
}
spin_unlock(&acpi_res_lock);
if (clash) {
if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
printk(KERN_INFO "%sACPI: %s resource %s [0x%llx-0x%llx]"
" conflicts with ACPI region %s"
" [0x%llx-0x%llx]\n",
acpi_enforce_resources == ENFORCE_RESOURCES_LAX
? KERN_WARNING : KERN_ERR,
ioport ? "I/O" : "Memory", res->name,
(long long) res->start, (long long) res->end,
res_list_elem->name,
(long long) res_list_elem->start,
(long long) res_list_elem->end);
printk(KERN_INFO "ACPI: Device needs an ACPI driver\n");
}
if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
return -EBUSY;
}
return 0;
}
EXPORT_SYMBOL(acpi_check_resource_conflict);
int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name)
{
struct resource res = {
.start = start,
.end = start + n - 1,
.name = name,
.flags = IORESOURCE_IO,
};
return acpi_check_resource_conflict(&res);
}
EXPORT_SYMBOL(acpi_check_region);
int acpi_check_mem_region(resource_size_t start, resource_size_t n,
const char *name)
{
struct resource res = {
.start = start,
.end = start + n - 1,
.name = name,
.flags = IORESOURCE_MEM,
};
return acpi_check_resource_conflict(&res);
}
EXPORT_SYMBOL(acpi_check_mem_region);
/* /*
* Acquire a spinlock. * Acquire a spinlock.
* *
@ -1213,24 +1409,24 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
* *
* Returns 0 on success * Returns 0 on success
*/ */
int acpi_dmi_dump(void) static int acpi_dmi_dump(void)
{ {
if (!dmi_available) if (!dmi_available)
return -1; return -1;
printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n", printk(KERN_NOTICE PREFIX "DMI System Vendor: %s\n",
dmi_get_slot(DMI_SYS_VENDOR)); dmi_get_system_info(DMI_SYS_VENDOR));
printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n", printk(KERN_NOTICE PREFIX "DMI Product Name: %s\n",
dmi_get_slot(DMI_PRODUCT_NAME)); dmi_get_system_info(DMI_PRODUCT_NAME));
printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n", printk(KERN_NOTICE PREFIX "DMI Product Version: %s\n",
dmi_get_slot(DMI_PRODUCT_VERSION)); dmi_get_system_info(DMI_PRODUCT_VERSION));
printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n", printk(KERN_NOTICE PREFIX "DMI Board Name: %s\n",
dmi_get_slot(DMI_BOARD_NAME)); dmi_get_system_info(DMI_BOARD_NAME));
printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n", printk(KERN_NOTICE PREFIX "DMI BIOS Vendor: %s\n",
dmi_get_slot(DMI_BIOS_VENDOR)); dmi_get_system_info(DMI_BIOS_VENDOR));
printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n", printk(KERN_NOTICE PREFIX "DMI BIOS Date: %s\n",
dmi_get_slot(DMI_BIOS_DATE)); dmi_get_system_info(DMI_BIOS_DATE));
return 0; return 0;
} }
@ -1303,10 +1499,46 @@ acpi_status
acpi_os_validate_address ( acpi_os_validate_address (
u8 space_id, u8 space_id,
acpi_physical_address address, acpi_physical_address address,
acpi_size length) acpi_size length,
char *name)
{ {
struct acpi_res_list *res;
if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
return AE_OK;
return AE_OK; switch (space_id) {
case ACPI_ADR_SPACE_SYSTEM_IO:
case ACPI_ADR_SPACE_SYSTEM_MEMORY:
/* Only interference checks against SystemIO and SytemMemory
are needed */
res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
if (!res)
return AE_OK;
/* ACPI names are fixed to 4 bytes, still better use strlcpy */
strlcpy(res->name, name, 5);
res->start = address;
res->end = address + length - 1;
res->resource_type = space_id;
spin_lock(&acpi_res_lock);
list_add(&res->resource_list, &resource_list_head);
spin_unlock(&acpi_res_lock);
pr_debug("Added %s resource: start: 0x%llx, end: 0x%llx, "
"name: %s\n", (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
? "SystemIO" : "System Memory",
(unsigned long long)res->start,
(unsigned long long)res->end,
res->name);
break;
case ACPI_ADR_SPACE_PCI_CONFIG:
case ACPI_ADR_SPACE_EC:
case ACPI_ADR_SPACE_SMBUS:
case ACPI_ADR_SPACE_CMOS:
case ACPI_ADR_SPACE_PCI_BAR_TARGET:
case ACPI_ADR_SPACE_DATA_TABLE:
case ACPI_ADR_SPACE_FIXED_HARDWARE:
break;
}
return AE_OK;
} }
#endif #endif

View File

@ -44,6 +44,8 @@ struct acpi_pci_data {
struct pci_dev *dev; struct pci_dev *dev;
}; };
static int acpi_pci_unbind(struct acpi_device *device);
static void acpi_pci_data_handler(acpi_handle handle, u32 function, static void acpi_pci_data_handler(acpi_handle handle, u32 function,
void *context) void *context)
{ {
@ -267,7 +269,7 @@ int acpi_pci_bind(struct acpi_device *device)
return result; return result;
} }
int acpi_pci_unbind(struct acpi_device *device) static int acpi_pci_unbind(struct acpi_device *device)
{ {
int result = 0; int result = 0;
acpi_status status = AE_OK; acpi_status status = AE_OK;

View File

@ -51,10 +51,8 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
int bus, int bus,
int device, int pin) int device, int pin)
{ {
struct list_head *node = NULL;
struct acpi_prt_entry *entry = NULL; struct acpi_prt_entry *entry = NULL;
if (!acpi_prt.count) if (!acpi_prt.count)
return NULL; return NULL;
@ -64,8 +62,7 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
* *
*/ */
spin_lock(&acpi_prt_lock); spin_lock(&acpi_prt_lock);
list_for_each(node, &acpi_prt.entries) { list_for_each_entry(entry, &acpi_prt.entries, node) {
entry = list_entry(node, struct acpi_prt_entry, node);
if ((segment == entry->id.segment) if ((segment == entry->id.segment)
&& (bus == entry->id.bus) && (bus == entry->id.bus)
&& (device == entry->id.device) && (device == entry->id.device)
@ -478,8 +475,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
return 0; return 0;
} }
EXPORT_SYMBOL(acpi_pci_irq_enable);
/* FIXME: implement x86/x86_64 version */ /* FIXME: implement x86/x86_64 version */
void __attribute__ ((weak)) acpi_unregister_gsi(u32 i) void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
{ {

View File

@ -95,7 +95,7 @@ static struct {
int count; int count;
struct list_head entries; struct list_head entries;
} acpi_link; } acpi_link;
DEFINE_MUTEX(acpi_link_lock); static DEFINE_MUTEX(acpi_link_lock);
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
PCI Link Device Management PCI Link Device Management

View File

@ -458,11 +458,9 @@ int acpi_power_transition(struct acpi_device *device, int state)
} }
end: end:
if (result) { if (result)
device->power.state = ACPI_STATE_UNKNOWN; device->power.state = ACPI_STATE_UNKNOWN;
printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n", else {
device->pnp.bus_id, state);
} else {
/* We shouldn't change the state till all above operations succeed */ /* We shouldn't change the state till all above operations succeed */
device->power.state = state; device->power.state = state;
} }

View File

@ -668,6 +668,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
acpi_processor_power_init(pr, device); acpi_processor_power_init(pr, device);
pr->cdev = thermal_cooling_device_register("Processor", device,
&processor_cooling_ops);
if (pr->cdev)
printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n",
device->dev.bus_id, pr->cdev->id);
else
goto end;
result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj,
"thermal_cooling");
if (result)
return result;
result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj,
"device");
if (result)
return result;
if (pr->flags.throttling) { if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports", printk(KERN_INFO PREFIX "%s [%s] (supports",
acpi_device_name(device), acpi_device_bid(device)); acpi_device_name(device), acpi_device_bid(device));
@ -791,6 +809,11 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
acpi_processor_remove_fs(device); acpi_processor_remove_fs(device);
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&pr->cdev->device.kobj, "device");
thermal_cooling_device_unregister(pr->cdev);
pr->cdev = NULL;
processors[pr->id] = NULL; processors[pr->id] = NULL;
kfree(pr); kfree(pr);
@ -812,11 +835,18 @@ static int is_processor_present(acpi_handle handle)
status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_PRESENT)) { /*
ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present")); * if a processor object does not have an _STA object,
return 0; * OSPM assumes that the processor is present.
} */
return 1; if (status == AE_NOT_FOUND)
return 1;
if (ACPI_SUCCESS(status) && (sta & ACPI_STA_DEVICE_PRESENT))
return 1;
ACPI_EXCEPTION((AE_INFO, status, "Processor Device is not present"));
return 0;
} }
static static
@ -1061,6 +1091,8 @@ static int __init acpi_processor_init(void)
acpi_processor_ppc_init(); acpi_processor_ppc_init();
acpi_processor_throttling_init();
return 0; return 0;
out_cpuidle: out_cpuidle:

View File

@ -98,6 +98,9 @@ module_param(bm_history, uint, 0644);
static int acpi_processor_set_power_policy(struct acpi_processor *pr); static int acpi_processor_set_power_policy(struct acpi_processor *pr);
#else /* CONFIG_CPU_IDLE */
static unsigned int latency_factor __read_mostly = 2;
module_param(latency_factor, uint, 0644);
#endif #endif
/* /*
@ -201,6 +204,10 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2); return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
} }
/*
* Callers should disable interrupts before the call and enable
* interrupts after return.
*/
static void acpi_safe_halt(void) static void acpi_safe_halt(void)
{ {
current_thread_info()->status &= ~TS_POLLING; current_thread_info()->status &= ~TS_POLLING;
@ -261,7 +268,7 @@ static atomic_t c3_cpu_count;
/* Common C-state entry for C2, C3, .. */ /* Common C-state entry for C2, C3, .. */
static void acpi_cstate_enter(struct acpi_processor_cx *cstate) static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
{ {
if (cstate->space_id == ACPI_CSTATE_FFH) { if (cstate->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */ /* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cstate); acpi_processor_ffh_cstate_enter(cstate);
} else { } else {
@ -413,6 +420,8 @@ static void acpi_processor_idle(void)
pm_idle_save(); pm_idle_save();
else else
acpi_safe_halt(); acpi_safe_halt();
local_irq_enable();
return; return;
} }
@ -521,6 +530,7 @@ static void acpi_processor_idle(void)
* skew otherwise. * skew otherwise.
*/ */
sleep_ticks = 0xFFFFFFFF; sleep_ticks = 0xFFFFFFFF;
local_irq_enable();
break; break;
case ACPI_STATE_C2: case ACPI_STATE_C2:
@ -922,20 +932,20 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
cx.address = reg->address; cx.address = reg->address;
cx.index = current_count + 1; cx.index = current_count + 1;
cx.space_id = ACPI_CSTATE_SYSTEMIO; cx.entry_method = ACPI_CSTATE_SYSTEMIO;
if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) { if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
if (acpi_processor_ffh_cstate_probe if (acpi_processor_ffh_cstate_probe
(pr->id, &cx, reg) == 0) { (pr->id, &cx, reg) == 0) {
cx.space_id = ACPI_CSTATE_FFH; cx.entry_method = ACPI_CSTATE_FFH;
} else if (cx.type != ACPI_STATE_C1) { } else if (cx.type == ACPI_STATE_C1) {
/* /*
* C1 is a special case where FIXED_HARDWARE * C1 is a special case where FIXED_HARDWARE
* can be handled in non-MWAIT way as well. * can be handled in non-MWAIT way as well.
* In that case, save this _CST entry info. * In that case, save this _CST entry info.
* That is, we retain space_id of SYSTEM_IO for
* halt based C1.
* Otherwise, ignore this info and continue. * Otherwise, ignore this info and continue.
*/ */
cx.entry_method = ACPI_CSTATE_HALT;
} else {
continue; continue;
} }
} }
@ -1369,12 +1379,16 @@ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
/** /**
* acpi_idle_do_entry - a helper function that does C2 and C3 type entry * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
* @cx: cstate data * @cx: cstate data
*
* Caller disables interrupt before call and enables interrupt after return.
*/ */
static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx) static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
{ {
if (cx->space_id == ACPI_CSTATE_FFH) { if (cx->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */ /* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cx); acpi_processor_ffh_cstate_enter(cx);
} else if (cx->entry_method == ACPI_CSTATE_HALT) {
acpi_safe_halt();
} else { } else {
int unused; int unused;
/* IO port based C-state */ /* IO port based C-state */
@ -1396,21 +1410,27 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
static int acpi_idle_enter_c1(struct cpuidle_device *dev, static int acpi_idle_enter_c1(struct cpuidle_device *dev,
struct cpuidle_state *state) struct cpuidle_state *state)
{ {
u32 t1, t2;
struct acpi_processor *pr; struct acpi_processor *pr;
struct acpi_processor_cx *cx = cpuidle_get_statedata(state); struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
pr = processors[smp_processor_id()]; pr = processors[smp_processor_id()];
if (unlikely(!pr)) if (unlikely(!pr))
return 0; return 0;
local_irq_disable();
if (pr->flags.bm_check) if (pr->flags.bm_check)
acpi_idle_update_bm_rld(pr, cx); acpi_idle_update_bm_rld(pr, cx);
acpi_safe_halt(); t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
acpi_idle_do_entry(cx);
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
local_irq_enable();
cx->usage++; cx->usage++;
return 0; return ticks_elapsed_in_us(t1, t2);
} }
/** /**
@ -1517,7 +1537,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
if (dev->safe_state) { if (dev->safe_state) {
return dev->safe_state->enter(dev, dev->safe_state); return dev->safe_state->enter(dev, dev->safe_state);
} else { } else {
local_irq_disable();
acpi_safe_halt(); acpi_safe_halt();
local_irq_enable();
return 0; return 0;
} }
} }
@ -1609,7 +1631,7 @@ struct cpuidle_driver acpi_idle_driver = {
*/ */
static int acpi_processor_setup_cpuidle(struct acpi_processor *pr) static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
{ {
int i, count = 0; int i, count = CPUIDLE_DRIVER_STATE_START;
struct acpi_processor_cx *cx; struct acpi_processor_cx *cx;
struct cpuidle_state *state; struct cpuidle_state *state;
struct cpuidle_device *dev = &pr->power.dev; struct cpuidle_device *dev = &pr->power.dev;
@ -1638,13 +1660,14 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i); snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
state->exit_latency = cx->latency; state->exit_latency = cx->latency;
state->target_residency = cx->latency * 6; state->target_residency = cx->latency * latency_factor;
state->power_usage = cx->power; state->power_usage = cx->power;
state->flags = 0; state->flags = 0;
switch (cx->type) { switch (cx->type) {
case ACPI_STATE_C1: case ACPI_STATE_C1:
state->flags |= CPUIDLE_FLAG_SHALLOW; state->flags |= CPUIDLE_FLAG_SHALLOW;
state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_c1; state->enter = acpi_idle_enter_c1;
dev->safe_state = state; dev->safe_state = state;
break; break;
@ -1667,6 +1690,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
} }
count++; count++;
if (count == CPUIDLE_STATE_MAX)
break;
} }
dev->state_count = count; dev->state_count = count;

View File

@ -60,6 +60,11 @@ static DEFINE_MUTEX(performance_mutex);
* policy is adjusted accordingly. * policy is adjusted accordingly.
*/ */
static unsigned int ignore_ppc = 0;
module_param(ignore_ppc, uint, 0644);
MODULE_PARM_DESC(ignore_ppc, "If the frequency of your machine gets wrongly" \
"limited by BIOS, this should help");
#define PPC_REGISTERED 1 #define PPC_REGISTERED 1
#define PPC_IN_USE 2 #define PPC_IN_USE 2
@ -72,6 +77,9 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
struct acpi_processor *pr; struct acpi_processor *pr;
unsigned int ppc = 0; unsigned int ppc = 0;
if (ignore_ppc)
return 0;
mutex_lock(&performance_mutex); mutex_lock(&performance_mutex);
if (event != CPUFREQ_INCOMPATIBLE) if (event != CPUFREQ_INCOMPATIBLE)
@ -130,7 +138,13 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
int acpi_processor_ppc_has_changed(struct acpi_processor *pr) int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
{ {
int ret = acpi_processor_get_platform_limit(pr); int ret;
if (ignore_ppc)
return 0;
ret = acpi_processor_get_platform_limit(pr);
if (ret < 0) if (ret < 0)
return (ret); return (ret);
else else

View File

@ -32,6 +32,7 @@
#include <linux/cpufreq.h> #include <linux/cpufreq.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/sysdev.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -93,6 +94,9 @@ static int acpi_processor_apply_limit(struct acpi_processor *pr)
* _any_ cpufreq driver and not only the acpi-cpufreq driver. * _any_ cpufreq driver and not only the acpi-cpufreq driver.
*/ */
#define CPUFREQ_THERMAL_MIN_STEP 0
#define CPUFREQ_THERMAL_MAX_STEP 3
static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS]; static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
static unsigned int acpi_thermal_cpufreq_is_init = 0; static unsigned int acpi_thermal_cpufreq_is_init = 0;
@ -109,8 +113,9 @@ static int acpi_thermal_cpufreq_increase(unsigned int cpu)
if (!cpu_has_cpufreq(cpu)) if (!cpu_has_cpufreq(cpu))
return -ENODEV; return -ENODEV;
if (cpufreq_thermal_reduction_pctg[cpu] < 60) { if (cpufreq_thermal_reduction_pctg[cpu] <
cpufreq_thermal_reduction_pctg[cpu] += 20; CPUFREQ_THERMAL_MAX_STEP) {
cpufreq_thermal_reduction_pctg[cpu]++;
cpufreq_update_policy(cpu); cpufreq_update_policy(cpu);
return 0; return 0;
} }
@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
if (!cpu_has_cpufreq(cpu)) if (!cpu_has_cpufreq(cpu))
return -ENODEV; return -ENODEV;
if (cpufreq_thermal_reduction_pctg[cpu] > 20) if (cpufreq_thermal_reduction_pctg[cpu] >
cpufreq_thermal_reduction_pctg[cpu] -= 20; (CPUFREQ_THERMAL_MIN_STEP + 1))
cpufreq_thermal_reduction_pctg[cpu]--;
else else
cpufreq_thermal_reduction_pctg[cpu] = 0; cpufreq_thermal_reduction_pctg[cpu] = 0;
cpufreq_update_policy(cpu); cpufreq_update_policy(cpu);
@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
max_freq = max_freq =
(policy->cpuinfo.max_freq * (policy->cpuinfo.max_freq *
(100 - cpufreq_thermal_reduction_pctg[policy->cpu])) / 100; (100 - cpufreq_thermal_reduction_pctg[policy->cpu] * 20)) / 100;
cpufreq_verify_within_limits(policy, 0, max_freq); cpufreq_verify_within_limits(policy, 0, max_freq);
@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
.notifier_call = acpi_thermal_cpufreq_notifier, .notifier_call = acpi_thermal_cpufreq_notifier,
}; };
static int cpufreq_get_max_state(unsigned int cpu)
{
if (!cpu_has_cpufreq(cpu))
return 0;
return CPUFREQ_THERMAL_MAX_STEP;
}
static int cpufreq_get_cur_state(unsigned int cpu)
{
if (!cpu_has_cpufreq(cpu))
return 0;
return cpufreq_thermal_reduction_pctg[cpu];
}
static int cpufreq_set_cur_state(unsigned int cpu, int state)
{
if (!cpu_has_cpufreq(cpu))
return 0;
cpufreq_thermal_reduction_pctg[cpu] = state;
cpufreq_update_policy(cpu);
return 0;
}
void acpi_thermal_cpufreq_init(void) void acpi_thermal_cpufreq_init(void)
{ {
int i; int i;
@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void)
} }
#else /* ! CONFIG_CPU_FREQ */ #else /* ! CONFIG_CPU_FREQ */
static int cpufreq_get_max_state(unsigned int cpu)
{
return 0;
}
static int cpufreq_get_cur_state(unsigned int cpu)
{
return 0;
}
static int cpufreq_set_cur_state(unsigned int cpu, int state)
{
return 0;
}
static int acpi_thermal_cpufreq_increase(unsigned int cpu) static int acpi_thermal_cpufreq_increase(unsigned int cpu)
{ {
@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr)
return 0; return 0;
} }
/* thermal coolign device callbacks */
static int acpi_processor_max_state(struct acpi_processor *pr)
{
int max_state = 0;
/*
* There exists four states according to
* cpufreq_thermal_reduction_ptg. 0, 1, 2, 3
*/
max_state += cpufreq_get_max_state(pr->id);
if (pr->flags.throttling)
max_state += (pr->throttling.state_count -1);
return max_state;
}
static int
processor_get_max_state(struct thermal_cooling_device *cdev, char *buf)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
if (!device || !pr)
return -EINVAL;
return sprintf(buf, "%d\n", acpi_processor_max_state(pr));
}
static int
processor_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
int cur_state;
if (!device || !pr)
return -EINVAL;
cur_state = cpufreq_get_cur_state(pr->id);
if (pr->flags.throttling)
cur_state += pr->throttling.state;
return sprintf(buf, "%d\n", cur_state);
}
static int
processor_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_processor *pr = acpi_driver_data(device);
int result = 0;
int max_pstate;
if (!device || !pr)
return -EINVAL;
max_pstate = cpufreq_get_max_state(pr->id);
if (state > acpi_processor_max_state(pr))
return -EINVAL;
if (state <= max_pstate) {
if (pr->flags.throttling && pr->throttling.state)
result = acpi_processor_set_throttling(pr, 0);
cpufreq_set_cur_state(pr->id, state);
} else {
cpufreq_set_cur_state(pr->id, max_pstate);
result = acpi_processor_set_throttling(pr,
state - max_pstate);
}
return result;
}
struct thermal_cooling_device_ops processor_cooling_ops = {
.get_max_state = processor_get_max_state,
.get_cur_state = processor_get_cur_state,
.set_cur_state = processor_set_cur_state,
};
/* /proc interface */ /* /proc interface */
static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset) static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)

View File

@ -45,9 +45,229 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT #define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_throttling"); ACPI_MODULE_NAME("processor_throttling");
struct throttling_tstate {
unsigned int cpu; /* cpu nr */
int target_state; /* target T-state */
};
#define THROTTLING_PRECHANGE (1)
#define THROTTLING_POSTCHANGE (2)
static int acpi_processor_get_throttling(struct acpi_processor *pr); static int acpi_processor_get_throttling(struct acpi_processor *pr);
int acpi_processor_set_throttling(struct acpi_processor *pr, int state); int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
static int acpi_processor_update_tsd_coord(void)
{
int count, count_target;
int retval = 0;
unsigned int i, j;
cpumask_t covered_cpus;
struct acpi_processor *pr, *match_pr;
struct acpi_tsd_package *pdomain, *match_pdomain;
struct acpi_processor_throttling *pthrottling, *match_pthrottling;
/*
* Now that we have _TSD data from all CPUs, lets setup T-state
* coordination between all CPUs.
*/
for_each_possible_cpu(i) {
pr = processors[i];
if (!pr)
continue;
/* Basic validity check for domain info */
pthrottling = &(pr->throttling);
/*
* If tsd package for one cpu is invalid, the coordination
* among all CPUs is thought as invalid.
* Maybe it is ugly.
*/
if (!pthrottling->tsd_valid_flag) {
retval = -EINVAL;
break;
}
}
if (retval)
goto err_ret;
cpus_clear(covered_cpus);
for_each_possible_cpu(i) {
pr = processors[i];
if (!pr)
continue;
if (cpu_isset(i, covered_cpus))
continue;
pthrottling = &pr->throttling;
pdomain = &(pthrottling->domain_info);
cpu_set(i, pthrottling->shared_cpu_map);
cpu_set(i, covered_cpus);
/*
* If the number of processor in the TSD domain is 1, it is
* unnecessary to parse the coordination for this CPU.
*/
if (pdomain->num_processors <= 1)
continue;
/* Validate the Domain info */
count_target = pdomain->num_processors;
count = 1;
for_each_possible_cpu(j) {
if (i == j)
continue;
match_pr = processors[j];
if (!match_pr)
continue;
match_pthrottling = &(match_pr->throttling);
match_pdomain = &(match_pthrottling->domain_info);
if (match_pdomain->domain != pdomain->domain)
continue;
/* Here i and j are in the same domain.
* If two TSD packages have the same domain, they
* should have the same num_porcessors and
* coordination type. Otherwise it will be regarded
* as illegal.
*/
if (match_pdomain->num_processors != count_target) {
retval = -EINVAL;
goto err_ret;
}
if (pdomain->coord_type != match_pdomain->coord_type) {
retval = -EINVAL;
goto err_ret;
}
cpu_set(j, covered_cpus);
cpu_set(j, pthrottling->shared_cpu_map);
count++;
}
for_each_possible_cpu(j) {
if (i == j)
continue;
match_pr = processors[j];
if (!match_pr)
continue;
match_pthrottling = &(match_pr->throttling);
match_pdomain = &(match_pthrottling->domain_info);
if (match_pdomain->domain != pdomain->domain)
continue;
/*
* If some CPUS have the same domain, they
* will have the same shared_cpu_map.
*/
match_pthrottling->shared_cpu_map =
pthrottling->shared_cpu_map;
}
}
err_ret:
for_each_possible_cpu(i) {
pr = processors[i];
if (!pr)
continue;
/*
* Assume no coordination on any error parsing domain info.
* The coordination type will be forced as SW_ALL.
*/
if (retval) {
pthrottling = &(pr->throttling);
cpus_clear(pthrottling->shared_cpu_map);
cpu_set(i, pthrottling->shared_cpu_map);
pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
}
}
return retval;
}
/*
* Update the T-state coordination after the _TSD
* data for all cpus is obtained.
*/
void acpi_processor_throttling_init(void)
{
if (acpi_processor_update_tsd_coord())
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Assume no T-state coordination\n"));
return;
}
static int acpi_processor_throttling_notifier(unsigned long event, void *data)
{
struct throttling_tstate *p_tstate = data;
struct acpi_processor *pr;
unsigned int cpu ;
int target_state;
struct acpi_processor_limit *p_limit;
struct acpi_processor_throttling *p_throttling;
cpu = p_tstate->cpu;
pr = processors[cpu];
if (!pr) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid pr pointer\n"));
return 0;
}
if (!pr->flags.throttling) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling control is "
"unsupported on CPU %d\n", cpu));
return 0;
}
target_state = p_tstate->target_state;
p_throttling = &(pr->throttling);
switch (event) {
case THROTTLING_PRECHANGE:
/*
* Prechange event is used to choose one proper t-state,
* which meets the limits of thermal, user and _TPC.
*/
p_limit = &pr->limit;
if (p_limit->thermal.tx > target_state)
target_state = p_limit->thermal.tx;
if (p_limit->user.tx > target_state)
target_state = p_limit->user.tx;
if (pr->throttling_platform_limit > target_state)
target_state = pr->throttling_platform_limit;
if (target_state >= p_throttling->state_count) {
printk(KERN_WARNING
"Exceed the limit of T-state \n");
target_state = p_throttling->state_count - 1;
}
p_tstate->target_state = target_state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PreChange Event:"
"target T-state of CPU %d is T%d\n",
cpu, target_state));
break;
case THROTTLING_POSTCHANGE:
/*
* Postchange event is only used to update the
* T-state flag of acpi_processor_throttling.
*/
p_throttling->state = target_state;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PostChange Event:"
"CPU %d is switched to T%d\n",
cpu, target_state));
break;
default:
printk(KERN_WARNING
"Unsupported Throttling notifier event\n");
break;
}
return 0;
}
/* /*
* _TPC - Throttling Present Capabilities * _TPC - Throttling Present Capabilities
*/ */
@ -293,6 +513,10 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
struct acpi_buffer state = { 0, NULL }; struct acpi_buffer state = { 0, NULL };
union acpi_object *tsd = NULL; union acpi_object *tsd = NULL;
struct acpi_tsd_package *pdomain; struct acpi_tsd_package *pdomain;
struct acpi_processor_throttling *pthrottling;
pthrottling = &pr->throttling;
pthrottling->tsd_valid_flag = 0;
status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer); status = acpi_evaluate_object(pr->handle, "_TSD", NULL, &buffer);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
@ -340,6 +564,22 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
goto end; goto end;
} }
pthrottling = &pr->throttling;
pthrottling->tsd_valid_flag = 1;
pthrottling->shared_type = pdomain->coord_type;
cpu_set(pr->id, pthrottling->shared_cpu_map);
/*
* If the coordination type is not defined in ACPI spec,
* the tsd_valid_flag will be clear and coordination type
* will be forecd as DOMAIN_COORD_TYPE_SW_ALL.
*/
if (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL &&
pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY &&
pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL) {
pthrottling->tsd_valid_flag = 0;
pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
}
end: end:
kfree(buffer.pointer); kfree(buffer.pointer);
return result; return result;
@ -589,6 +829,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
cpumask_t saved_mask; cpumask_t saved_mask;
int ret; int ret;
if (!pr)
return -EINVAL;
if (!pr->flags.throttling)
return -ENODEV;
/* /*
* Migrate task to the cpu pointed by pr. * Migrate task to the cpu pointed by pr.
*/ */
@ -742,13 +987,92 @@ static int acpi_processor_set_throttling_ptc(struct acpi_processor *pr,
int acpi_processor_set_throttling(struct acpi_processor *pr, int state) int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
{ {
cpumask_t saved_mask; cpumask_t saved_mask;
int ret; int ret = 0;
/* unsigned int i;
* Migrate task to the cpu pointed by pr. struct acpi_processor *match_pr;
*/ struct acpi_processor_throttling *p_throttling;
struct throttling_tstate t_state;
cpumask_t online_throttling_cpus;
if (!pr)
return -EINVAL;
if (!pr->flags.throttling)
return -ENODEV;
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
return -EINVAL;
saved_mask = current->cpus_allowed; saved_mask = current->cpus_allowed;
set_cpus_allowed(current, cpumask_of_cpu(pr->id)); t_state.target_state = state;
ret = pr->throttling.acpi_processor_set_throttling(pr, state); p_throttling = &(pr->throttling);
cpus_and(online_throttling_cpus, cpu_online_map,
p_throttling->shared_cpu_map);
/*
* The throttling notifier will be called for every
* affected cpu in order to get one proper T-state.
* The notifier event is THROTTLING_PRECHANGE.
*/
for_each_cpu_mask(i, online_throttling_cpus) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_PRECHANGE,
&t_state);
}
/*
* The function of acpi_processor_set_throttling will be called
* to switch T-state. If the coordination type is SW_ALL or HW_ALL,
* it is necessary to call it for every affected cpu. Otherwise
* it can be called only for the cpu pointed by pr.
*/
if (p_throttling->shared_type == DOMAIN_COORD_TYPE_SW_ANY) {
set_cpus_allowed(current, cpumask_of_cpu(pr->id));
ret = p_throttling->acpi_processor_set_throttling(pr,
t_state.target_state);
} else {
/*
* When the T-state coordination is SW_ALL or HW_ALL,
* it is necessary to set T-state for every affected
* cpus.
*/
for_each_cpu_mask(i, online_throttling_cpus) {
match_pr = processors[i];
/*
* If the pointer is invalid, we will report the
* error message and continue.
*/
if (!match_pr) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Invalid Pointer for CPU %d\n", i));
continue;
}
/*
* If the throttling control is unsupported on CPU i,
* we will report the error message and continue.
*/
if (!match_pr->flags.throttling) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Throttling Controll is unsupported "
"on CPU %d\n", i));
continue;
}
t_state.cpu = i;
set_cpus_allowed(current, cpumask_of_cpu(i));
ret = match_pr->throttling.
acpi_processor_set_throttling(
match_pr, t_state.target_state);
}
}
/*
* After the set_throttling is called, the
* throttling notifier is called for every
* affected cpu to update the T-states.
* The notifier event is THROTTLING_POSTCHANGE
*/
for_each_cpu_mask(i, online_throttling_cpus) {
t_state.cpu = i;
acpi_processor_throttling_notifier(THROTTLING_POSTCHANGE,
&t_state);
}
/* restore the previous state */ /* restore the previous state */
set_cpus_allowed(current, saved_mask); set_cpus_allowed(current, saved_mask);
return ret; return ret;
@ -757,6 +1081,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
int acpi_processor_get_throttling_info(struct acpi_processor *pr) int acpi_processor_get_throttling_info(struct acpi_processor *pr)
{ {
int result = 0; int result = 0;
struct acpi_processor_throttling *pthrottling;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n", "pblk_address[0x%08x] duty_offset[%d] duty_width[%d]\n",
@ -788,7 +1113,16 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
&acpi_processor_set_throttling_ptc; &acpi_processor_set_throttling_ptc;
} }
acpi_processor_get_tsd(pr); /*
* If TSD package for one CPU can't be parsed successfully, it means
* that this CPU will have no coordination with other CPUs.
*/
if (acpi_processor_get_tsd(pr)) {
pthrottling = &pr->throttling;
pthrottling->tsd_valid_flag = 0;
cpu_set(pr->id, pthrottling->shared_cpu_map);
pthrottling->shared_type = DOMAIN_COORD_TYPE_SW_ALL;
}
/* /*
* PIIX4 Errata: We don't support throttling on the original PIIX4. * PIIX4 Errata: We don't support throttling on the original PIIX4.

View File

@ -888,7 +888,7 @@ static void acpi_charger_remove(struct acpi_sbs *sbs)
#endif #endif
} }
void acpi_sbs_callback(void *context) static void acpi_sbs_callback(void *context)
{ {
int id; int id;
struct acpi_sbs *sbs = context; struct acpi_sbs *sbs = context;

View File

@ -111,8 +111,8 @@ static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
return -ETIME; return -ETIME;
} }
int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address, static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
u8 command, u8 *data, u8 length) u8 address, u8 command, u8 *data, u8 length)
{ {
int ret = -EFAULT, i; int ret = -EFAULT, i;
u8 temp, sz = 0; u8 temp, sz = 0;

View File

@ -59,7 +59,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
count = snprintf(&modalias[len], size, "%s:", count = snprintf(&modalias[len], size, "%s:",
cid_list->id[i].value); cid_list->id[i].value);
if (count < 0 || count >= size) { if (count < 0 || count >= size) {
printk(KERN_ERR "acpi: %s cid[%i] exceeds event buffer size", printk(KERN_ERR PREFIX "%s cid[%i] exceeds event buffer size",
acpi_dev->pnp.device_name, i); acpi_dev->pnp.device_name, i);
break; break;
} }
@ -453,7 +453,7 @@ static int acpi_device_register(struct acpi_device *device,
device->dev.release = &acpi_device_release; device->dev.release = &acpi_device_release;
result = device_add(&device->dev); result = device_add(&device->dev);
if(result) { if(result) {
printk("Error adding device %s", device->dev.bus_id); printk(KERN_ERR PREFIX "Error adding device %s", device->dev.bus_id);
goto end; goto end;
} }
@ -941,6 +941,15 @@ static int acpi_bay_match(struct acpi_device *device){
return -ENODEV; return -ENODEV;
} }
/*
* acpi_dock_match - see if a device has a _DCK method
*/
static int acpi_dock_match(struct acpi_device *device)
{
acpi_handle tmp;
return acpi_get_handle(device->handle, "_DCK", &tmp);
}
static void acpi_device_set_id(struct acpi_device *device, static void acpi_device_set_id(struct acpi_device *device,
struct acpi_device *parent, acpi_handle handle, struct acpi_device *parent, acpi_handle handle,
int type) int type)
@ -950,13 +959,14 @@ static void acpi_device_set_id(struct acpi_device *device,
char *hid = NULL; char *hid = NULL;
char *uid = NULL; char *uid = NULL;
struct acpi_compatible_id_list *cid_list = NULL; struct acpi_compatible_id_list *cid_list = NULL;
const char *cid_add = NULL;
acpi_status status; acpi_status status;
switch (type) { switch (type) {
case ACPI_BUS_TYPE_DEVICE: case ACPI_BUS_TYPE_DEVICE:
status = acpi_get_object_info(handle, &buffer); status = acpi_get_object_info(handle, &buffer);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
printk("%s: Error reading device info\n", __FUNCTION__); printk(KERN_ERR PREFIX "%s: Error reading device info\n", __FUNCTION__);
return; return;
} }
@ -972,15 +982,18 @@ static void acpi_device_set_id(struct acpi_device *device,
device->flags.bus_address = 1; device->flags.bus_address = 1;
} }
if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){ /* If we have a video/bay/dock device, add our selfdefined
status = acpi_video_bus_match(device); HID to the CID list. Like that the video/bay/dock drivers
if(ACPI_SUCCESS(status)) will get autoloaded and the device might still match
hid = ACPI_VIDEO_HID; against another driver.
*/
if (ACPI_SUCCESS(acpi_video_bus_match(device)))
cid_add = ACPI_VIDEO_HID;
else if (ACPI_SUCCESS(acpi_bay_match(device)))
cid_add = ACPI_BAY_HID;
else if (ACPI_SUCCESS(acpi_dock_match(device)))
cid_add = ACPI_DOCK_HID;
status = acpi_bay_match(device);
if (ACPI_SUCCESS(status))
hid = ACPI_BAY_HID;
}
break; break;
case ACPI_BUS_TYPE_POWER: case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID; hid = ACPI_POWER_HID;
@ -1021,12 +1034,45 @@ static void acpi_device_set_id(struct acpi_device *device,
strcpy(device->pnp.unique_id, uid); strcpy(device->pnp.unique_id, uid);
device->flags.unique_id = 1; device->flags.unique_id = 1;
} }
if (cid_list) { if (cid_list || cid_add) {
device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL); struct acpi_compatible_id_list *list;
if (device->pnp.cid_list) int size = 0;
memcpy(device->pnp.cid_list, cid_list, cid_list->size); int count = 0;
else
printk(KERN_ERR "Memory allocation error\n"); if (cid_list) {
size = cid_list->size;
} else if (cid_add) {
size = sizeof(struct acpi_compatible_id_list);
cid_list = ACPI_ALLOCATE_ZEROED((acpi_size) size);
if (!cid_list) {
printk(KERN_ERR "Memory allocation error\n");
kfree(buffer.pointer);
return;
} else {
cid_list->count = 0;
cid_list->size = size;
}
}
if (cid_add)
size += sizeof(struct acpi_compatible_id);
list = kmalloc(size, GFP_KERNEL);
if (list) {
if (cid_list) {
memcpy(list, cid_list, cid_list->size);
count = cid_list->count;
}
if (cid_add) {
strncpy(list->id[count].value, cid_add,
ACPI_MAX_CID_LENGTH);
count++;
device->flags.compatible_ids = 1;
}
list->size = size;
list->count = count;
device->pnp.cid_list = list;
} else
printk(KERN_ERR PREFIX "Memory allocation error\n");
} }
kfree(buffer.pointer); kfree(buffer.pointer);
@ -1050,7 +1096,7 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
acpi_bus_data_handler, device); acpi_bus_data_handler, device);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
printk("Error attaching device data\n"); printk(KERN_ERR PREFIX "Error attaching device data\n");
result = -ENODEV; result = -ENODEV;
} }
} }
@ -1080,6 +1126,20 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
return 0; return 0;
} }
static int
acpi_is_child_device(struct acpi_device *device,
int (*matcher)(struct acpi_device *))
{
int result = -ENODEV;
do {
if (ACPI_SUCCESS(matcher(device)))
return AE_OK;
} while ((device = device->parent));
return result;
}
static int static int
acpi_add_single_object(struct acpi_device **child, acpi_add_single_object(struct acpi_device **child,
struct acpi_device *parent, acpi_handle handle, int type, struct acpi_device *parent, acpi_handle handle, int type,
@ -1131,10 +1191,20 @@ acpi_add_single_object(struct acpi_device **child,
case ACPI_BUS_TYPE_PROCESSOR: case ACPI_BUS_TYPE_PROCESSOR:
case ACPI_BUS_TYPE_DEVICE: case ACPI_BUS_TYPE_DEVICE:
result = acpi_bus_get_status(device); result = acpi_bus_get_status(device);
if (ACPI_FAILURE(result) || !device->status.present) { if (ACPI_FAILURE(result)) {
result = -ENOENT; result = -ENODEV;
goto end; goto end;
} }
if (!device->status.present) {
/* Bay and dock should be handled even if absent */
if (!ACPI_SUCCESS(
acpi_is_child_device(device, acpi_bay_match)) &&
!ACPI_SUCCESS(
acpi_is_child_device(device, acpi_dock_match))) {
result = -ENODEV;
goto end;
}
}
break; break;
default: default:
STRUCT_TO_INT(device->status) = STRUCT_TO_INT(device->status) =

View File

@ -170,7 +170,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
/* Reprogram control registers and execute _BFS */ /* Reprogram control registers and execute _BFS */
acpi_leave_sleep_state_prep(acpi_state); acpi_leave_sleep_state_prep(acpi_state);
/* ACPI 3.0 specs (P62) says that it's the responsabilty /* ACPI 3.0 specs (P62) says that it's the responsibility
* of the OSPM to clear the status bit [ implying that the * of the OSPM to clear the status bit [ implying that the
* POWER_BUTTON event should not reach userspace ] * POWER_BUTTON event should not reach userspace ]
*/ */
@ -472,11 +472,20 @@ int acpi_pm_device_sleep_state(struct device *dev, int wake, int *d_min_p)
if (acpi_target_sleep_state == ACPI_STATE_S0 || if (acpi_target_sleep_state == ACPI_STATE_S0 ||
(wake && adev->wakeup.state.enabled && (wake && adev->wakeup.state.enabled &&
adev->wakeup.sleep_state <= acpi_target_sleep_state)) { adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
acpi_status status;
acpi_method[3] = 'W'; acpi_method[3] = 'W';
acpi_evaluate_integer(handle, acpi_method, NULL, &d_max); status = acpi_evaluate_integer(handle, acpi_method, NULL,
/* Sanity check */ &d_max);
if (d_max < d_min) if (ACPI_FAILURE(status)) {
d_max = d_min;
} else if (d_max < d_min) {
/* Warn the user of the broken DSDT */
printk(KERN_WARNING "ACPI: Wrong value from %s\n",
acpi_method);
/* Sanitize it */
d_min = d_max; d_min = d_max;
}
} }
if (d_min_p) if (d_min_p)

View File

@ -178,6 +178,9 @@ static int get_date_field(char **p, u32 * value)
* Try to find delimeter, only to insert null. The end of the * Try to find delimeter, only to insert null. The end of the
* string won't have one, but is still valid. * string won't have one, but is still valid.
*/ */
if (*p == NULL)
return result;
next = strpbrk(*p, "- :"); next = strpbrk(*p, "- :");
if (next) if (next)
*next++ = '\0'; *next++ = '\0';
@ -190,6 +193,8 @@ static int get_date_field(char **p, u32 * value)
if (next) if (next)
*p = next; *p = next;
else
*p = NULL;
return result; return result;
} }
@ -251,27 +256,6 @@ acpi_system_write_alarm(struct file *file,
if ((result = get_date_field(&p, &sec))) if ((result = get_date_field(&p, &sec)))
goto end; goto end;
if (sec > 59) {
min += 1;
sec -= 60;
}
if (min > 59) {
hr += 1;
min -= 60;
}
if (hr > 23) {
day += 1;
hr -= 24;
}
if (day > 31) {
mo += 1;
day -= 31;
}
if (mo > 12) {
yr += 1;
mo -= 12;
}
spin_lock_irq(&rtc_lock); spin_lock_irq(&rtc_lock);
rtc_control = CMOS_READ(RTC_CONTROL); rtc_control = CMOS_READ(RTC_CONTROL);
@ -288,24 +272,24 @@ acpi_system_write_alarm(struct file *file,
spin_unlock_irq(&rtc_lock); spin_unlock_irq(&rtc_lock);
if (sec > 59) { if (sec > 59) {
min++; min += sec/60;
sec -= 60; sec = sec%60;
} }
if (min > 59) { if (min > 59) {
hr++; hr += min/60;
min -= 60; min = min%60;
} }
if (hr > 23) { if (hr > 23) {
day++; day += hr/24;
hr -= 24; hr = hr%24;
} }
if (day > 31) { if (day > 31) {
mo++; mo += day/32;
day -= 31; day = day%32;
} }
if (mo > 12) { if (mo > 12) {
yr++; yr += mo/13;
mo -= 12; mo = mo%13;
} }
spin_lock_irq(&rtc_lock); spin_lock_irq(&rtc_lock);

View File

@ -40,6 +40,8 @@ ACPI_MODULE_NAME("system");
#define ACPI_SYSTEM_CLASS "system" #define ACPI_SYSTEM_CLASS "system"
#define ACPI_SYSTEM_DEVICE_NAME "System" #define ACPI_SYSTEM_DEVICE_NAME "System"
u32 acpi_irq_handled;
/* /*
* Make ACPICA version work as module param * Make ACPICA version work as module param
*/ */
@ -166,6 +168,212 @@ static int acpi_system_sysfs_init(void)
return 0; return 0;
} }
/*
* Detailed ACPI IRQ counters in /sys/firmware/acpi/interrupts/
* See Documentation/ABI/testing/sysfs-firmware-acpi
*/
#define COUNT_GPE 0
#define COUNT_SCI 1 /* acpi_irq_handled */
#define COUNT_ERROR 2 /* other */
#define NUM_COUNTERS_EXTRA 3
static u32 *all_counters;
static u32 num_gpes;
static u32 num_counters;
static struct attribute **all_attrs;
static u32 acpi_gpe_count;
static struct attribute_group interrupt_stats_attr_group = {
.name = "interrupts",
};
static struct kobj_attribute *counter_attrs;
static int count_num_gpes(void)
{
int count = 0;
struct acpi_gpe_xrupt_info *gpe_xrupt_info;
struct acpi_gpe_block_info *gpe_block;
acpi_cpu_flags flags;
flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
while (gpe_xrupt_info) {
gpe_block = gpe_xrupt_info->gpe_block_list_head;
while (gpe_block) {
count += gpe_block->register_count *
ACPI_GPE_REGISTER_WIDTH;
gpe_block = gpe_block->next;
}
gpe_xrupt_info = gpe_xrupt_info->next;
}
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
return count;
}
static void delete_gpe_attr_array(void)
{
u32 *tmp = all_counters;
all_counters = NULL;
kfree(tmp);
if (counter_attrs) {
int i;
for (i = 0; i < num_gpes; i++)
kfree(counter_attrs[i].attr.name);
kfree(counter_attrs);
}
kfree(all_attrs);
return;
}
void acpi_os_gpe_count(u32 gpe_number)
{
acpi_gpe_count++;
if (!all_counters)
return;
if (gpe_number < num_gpes)
all_counters[gpe_number]++;
else
all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
return;
}
void acpi_os_fixed_event_count(u32 event_number)
{
if (!all_counters)
return;
if (event_number < ACPI_NUM_FIXED_EVENTS)
all_counters[num_gpes + event_number]++;
else
all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR]++;
return;
}
static ssize_t counter_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI] =
acpi_irq_handled;
all_counters[num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE] =
acpi_gpe_count;
return sprintf(buf, "%d\n", all_counters[attr - counter_attrs]);
}
/*
* counter_set() sets the specified counter.
* setting the total "sci" file to any value clears all counters.
*/
static ssize_t counter_set(struct kobject *kobj,
struct kobj_attribute *attr, const char *buf, size_t size)
{
int index = attr - counter_attrs;
if (index == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI) {
int i;
for (i = 0; i < num_counters; ++i)
all_counters[i] = 0;
acpi_gpe_count = 0;
acpi_irq_handled = 0;
} else
all_counters[index] = strtoul(buf, NULL, 0);
return size;
}
void acpi_irq_stats_init(void)
{
int i;
if (all_counters)
return;
num_gpes = count_num_gpes();
num_counters = num_gpes + ACPI_NUM_FIXED_EVENTS + NUM_COUNTERS_EXTRA;
all_attrs = kzalloc(sizeof(struct attribute *) * (num_counters + 1),
GFP_KERNEL);
if (all_attrs == NULL)
return;
all_counters = kzalloc(sizeof(u32) * (num_counters), GFP_KERNEL);
if (all_counters == NULL)
goto fail;
counter_attrs = kzalloc(sizeof(struct kobj_attribute) * (num_counters),
GFP_KERNEL);
if (counter_attrs == NULL)
goto fail;
for (i = 0; i < num_counters; ++i) {
char buffer[10];
char *name;
if (i < num_gpes)
sprintf(buffer, "gpe%02X", i);
else if (i == num_gpes + ACPI_EVENT_PMTIMER)
sprintf(buffer, "ff_pmtimer");
else if (i == num_gpes + ACPI_EVENT_GLOBAL)
sprintf(buffer, "ff_gbl_lock");
else if (i == num_gpes + ACPI_EVENT_POWER_BUTTON)
sprintf(buffer, "ff_pwr_btn");
else if (i == num_gpes + ACPI_EVENT_SLEEP_BUTTON)
sprintf(buffer, "ff_slp_btn");
else if (i == num_gpes + ACPI_EVENT_RTC)
sprintf(buffer, "ff_rt_clk");
else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_GPE)
sprintf(buffer, "gpe_all");
else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_SCI)
sprintf(buffer, "sci");
else if (i == num_gpes + ACPI_NUM_FIXED_EVENTS + COUNT_ERROR)
sprintf(buffer, "error");
else
sprintf(buffer, "bug%02X", i);
name = kzalloc(strlen(buffer) + 1, GFP_KERNEL);
if (name == NULL)
goto fail;
strncpy(name, buffer, strlen(buffer) + 1);
counter_attrs[i].attr.name = name;
counter_attrs[i].attr.mode = 0644;
counter_attrs[i].show = counter_show;
counter_attrs[i].store = counter_set;
all_attrs[i] = &counter_attrs[i].attr;
}
interrupt_stats_attr_group.attrs = all_attrs;
if (!sysfs_create_group(acpi_kobj, &interrupt_stats_attr_group))
return;
fail:
delete_gpe_attr_array();
return;
}
static void __exit interrupt_stats_exit(void)
{
sysfs_remove_group(acpi_kobj, &interrupt_stats_attr_group);
delete_gpe_attr_array();
return;
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
FS Interface (/proc) FS Interface (/proc)
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */

View File

@ -2,6 +2,6 @@
# Makefile for all Linux ACPI interpreter subdirectories # Makefile for all Linux ACPI interpreter subdirectories
# #
obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o obj-y := tbxface.o tbinstal.o tbutils.o tbfind.o tbfadt.o tbxfroot.o
EXTRA_CFLAGS += $(ACPI_CFLAGS) EXTRA_CFLAGS += $(ACPI_CFLAGS)

View File

@ -100,7 +100,7 @@ static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_tb_find_rsdp * FUNCTION: acpi_find_root_pointer
* *
* PARAMETERS: table_address - Where the table pointer is returned * PARAMETERS: table_address - Where the table pointer is returned
* *
@ -219,8 +219,6 @@ acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
return_ACPI_STATUS(AE_NOT_FOUND); return_ACPI_STATUS(AE_NOT_FOUND);
} }
ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
/******************************************************************************* /*******************************************************************************
* *
* FUNCTION: acpi_tb_scan_memory_for_rsdp * FUNCTION: acpi_tb_scan_memory_for_rsdp

View File

@ -43,7 +43,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h> #include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h> #include <acpi/acpi_drivers.h>
@ -65,9 +65,6 @@
#define ACPI_THERMAL_MAX_ACTIVE 10 #define ACPI_THERMAL_MAX_ACTIVE 10
#define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732>=0) ? ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
#define CELSIUS_TO_KELVIN(t) ((t+273)*10)
#define _COMPONENT ACPI_THERMAL_COMPONENT #define _COMPONENT ACPI_THERMAL_COMPONENT
ACPI_MODULE_NAME("thermal"); ACPI_MODULE_NAME("thermal");
@ -195,6 +192,8 @@ struct acpi_thermal {
struct acpi_thermal_trips trips; struct acpi_thermal_trips trips;
struct acpi_handle_list devices; struct acpi_handle_list devices;
struct timer_list timer; struct timer_list timer;
struct thermal_zone_device *thermal_zone;
int tz_enabled;
struct mutex lock; struct mutex lock;
}; };
@ -321,178 +320,226 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
return 0; return 0;
} }
static int acpi_thermal_get_trip_points(struct acpi_thermal *tz) #define ACPI_TRIPS_CRITICAL 0x01
#define ACPI_TRIPS_HOT 0x02
#define ACPI_TRIPS_PASSIVE 0x04
#define ACPI_TRIPS_ACTIVE 0x08
#define ACPI_TRIPS_DEVICES 0x10
#define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
#define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
#define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
ACPI_TRIPS_DEVICES)
/*
* This exception is thrown out in two cases:
* 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
* when re-evaluating the AML code.
* 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
* We need to re-bind the cooling devices of a thermal zone when this occurs.
*/
#define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \
do { \
if (flags != ACPI_TRIPS_INIT) \
ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
"ACPI thermal trip point %s changed\n" \
"Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
} while (0)
static int acpi_thermal_trips_update(struct acpi_thermal *tz, int flag)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
int i = 0; struct acpi_handle_list devices;
int valid = 0;
int i;
if (!tz)
return -EINVAL;
/* Critical Shutdown (required) */ /* Critical Shutdown (required) */
if (flag & ACPI_TRIPS_CRITICAL) {
status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL, status = acpi_evaluate_integer(tz->device->handle,
&tz->trips.critical.temperature); "_CRT", NULL, &tz->trips.critical.temperature);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
tz->trips.critical.flags.valid = 0;
ACPI_EXCEPTION((AE_INFO, status, "No critical threshold"));
return -ENODEV;
} else {
tz->trips.critical.flags.valid = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found critical threshold [%lu]\n",
tz->trips.critical.temperature));
}
if (tz->trips.critical.flags.valid == 1) {
if (crt == -1) {
tz->trips.critical.flags.valid = 0; tz->trips.critical.flags.valid = 0;
} else if (crt > 0) { ACPI_EXCEPTION((AE_INFO, status,
unsigned long crt_k = CELSIUS_TO_KELVIN(crt); "No critical threshold"));
return -ENODEV;
/* } else {
* Allow override to lower critical threshold tz->trips.critical.flags.valid = 1;
*/ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
if (crt_k < tz->trips.critical.temperature) "Found critical threshold [%lu]\n",
tz->trips.critical.temperature = crt_k; tz->trips.critical.temperature));
}
if (tz->trips.critical.flags.valid == 1) {
if (crt == -1) {
tz->trips.critical.flags.valid = 0;
} else if (crt > 0) {
unsigned long crt_k = CELSIUS_TO_KELVIN(crt);
/*
* Allow override to lower critical threshold
*/
if (crt_k < tz->trips.critical.temperature)
tz->trips.critical.temperature = crt_k;
}
} }
} }
/* Critical Sleep (optional) */ /* Critical Sleep (optional) */
if (flag & ACPI_TRIPS_HOT) {
status =
acpi_evaluate_integer(tz->device->handle, "_HOT", NULL,
&tz->trips.hot.temperature);
if (ACPI_FAILURE(status)) {
tz->trips.hot.flags.valid = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No hot threshold\n"));
} else {
tz->trips.hot.flags.valid = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found hot threshold [%lu]\n",
tz->trips.hot.temperature));
}
/* Passive: Processors (optional) */
if (psv == -1) {
status = AE_SUPPORT;
} else if (psv > 0) {
tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
status = AE_OK;
} else {
status = acpi_evaluate_integer(tz->device->handle, status = acpi_evaluate_integer(tz->device->handle,
"_PSV", NULL, &tz->trips.passive.temperature); "_HOT", NULL, &tz->trips.hot.temperature);
} if (ACPI_FAILURE(status)) {
tz->trips.hot.flags.valid = 0;
if (ACPI_FAILURE(status)) {
tz->trips.passive.flags.valid = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No passive threshold\n"));
} else {
tz->trips.passive.flags.valid = 1;
status =
acpi_evaluate_integer(tz->device->handle, "_TC1", NULL,
&tz->trips.passive.tc1);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status =
acpi_evaluate_integer(tz->device->handle, "_TC2", NULL,
&tz->trips.passive.tc2);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status =
acpi_evaluate_integer(tz->device->handle, "_TSP", NULL,
&tz->trips.passive.tsp);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status =
acpi_evaluate_reference(tz->device->handle, "_PSL", NULL,
&tz->trips.passive.devices);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
if (!tz->trips.passive.flags.valid)
printk(KERN_WARNING PREFIX "Invalid passive threshold\n");
else
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found passive threshold [%lu]\n", "No hot threshold\n"));
tz->trips.passive.temperature)); } else {
tz->trips.hot.flags.valid = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found hot threshold [%lu]\n",
tz->trips.critical.temperature));
}
} }
/* Active: Fans, etc. (optional) */ /* Passive (optional) */
if (flag & ACPI_TRIPS_PASSIVE) {
valid = tz->trips.passive.flags.valid;
if (psv == -1) {
status = AE_SUPPORT;
} else if (psv > 0) {
tz->trips.passive.temperature = CELSIUS_TO_KELVIN(psv);
status = AE_OK;
} else {
status = acpi_evaluate_integer(tz->device->handle,
"_PSV", NULL, &tz->trips.passive.temperature);
}
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
else {
tz->trips.passive.flags.valid = 1;
if (flag == ACPI_TRIPS_INIT) {
status = acpi_evaluate_integer(
tz->device->handle, "_TC1",
NULL, &tz->trips.passive.tc1);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status = acpi_evaluate_integer(
tz->device->handle, "_TC2",
NULL, &tz->trips.passive.tc2);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
status = acpi_evaluate_integer(
tz->device->handle, "_TSP",
NULL, &tz->trips.passive.tsp);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
}
}
}
if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.passive.flags.valid) {
memset(&devices, 0, sizeof(struct acpi_handle_list));
status = acpi_evaluate_reference(tz->device->handle, "_PSL",
NULL, &devices);
if (ACPI_FAILURE(status))
tz->trips.passive.flags.valid = 0;
else
tz->trips.passive.flags.valid = 1;
if (memcmp(&tz->trips.passive.devices, &devices,
sizeof(struct acpi_handle_list))) {
memcpy(&tz->trips.passive.devices, &devices,
sizeof(struct acpi_handle_list));
ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
}
}
if ((flag & ACPI_TRIPS_PASSIVE) || (flag & ACPI_TRIPS_DEVICES)) {
if (valid != tz->trips.passive.flags.valid)
ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
}
/* Active (optional) */
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' }; char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
valid = tz->trips.active[i].flags.valid;
if (act == -1) if (act == -1)
break; /* disable all active trip points */ break; /* disable all active trip points */
status = acpi_evaluate_integer(tz->device->handle, if (flag & ACPI_TRIPS_ACTIVE) {
name, NULL, &tz->trips.active[i].temperature); status = acpi_evaluate_integer(tz->device->handle,
name, NULL, &tz->trips.active[i].temperature);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
if (i == 0) /* no active trip points */ tz->trips.active[i].flags.valid = 0;
if (i == 0)
break;
if (act <= 0)
break;
if (i == 1)
tz->trips.active[0].temperature =
CELSIUS_TO_KELVIN(act);
else
/*
* Don't allow override higher than
* the next higher trip point
*/
tz->trips.active[i - 1].temperature =
(tz->trips.active[i - 2].temperature <
CELSIUS_TO_KELVIN(act) ?
tz->trips.active[i - 2].temperature :
CELSIUS_TO_KELVIN(act));
break; break;
if (act <= 0) /* no override requested */ } else
break; tz->trips.active[i].flags.valid = 1;
if (i == 1) { /* 1 trip point */
tz->trips.active[0].temperature =
CELSIUS_TO_KELVIN(act);
} else { /* multiple trips */
/*
* Don't allow override higher than
* the next higher trip point
*/
tz->trips.active[i - 1].temperature =
(tz->trips.active[i - 2].temperature <
CELSIUS_TO_KELVIN(act) ?
tz->trips.active[i - 2].temperature :
CELSIUS_TO_KELVIN(act));
}
break;
} }
name[2] = 'L'; name[2] = 'L';
status = if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
acpi_evaluate_reference(tz->device->handle, name, NULL, memset(&devices, 0, sizeof(struct acpi_handle_list));
&tz->trips.active[i].devices); status = acpi_evaluate_reference(tz->device->handle,
if (ACPI_SUCCESS(status)) { name, NULL, &devices);
tz->trips.active[i].flags.valid = 1; if (ACPI_FAILURE(status))
ACPI_DEBUG_PRINT((ACPI_DB_INFO, tz->trips.active[i].flags.valid = 0;
"Found active threshold [%d]:[%lu]\n", else
i, tz->trips.active[i].temperature)); tz->trips.active[i].flags.valid = 1;
} else
ACPI_EXCEPTION((AE_INFO, status, if (memcmp(&tz->trips.active[i].devices, &devices,
"Invalid active threshold [%d]", i)); sizeof(struct acpi_handle_list))) {
memcpy(&tz->trips.active[i].devices, &devices,
sizeof(struct acpi_handle_list));
ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
}
}
if ((flag & ACPI_TRIPS_ACTIVE) || (flag & ACPI_TRIPS_DEVICES))
if (valid != tz->trips.active[i].flags.valid)
ACPI_THERMAL_TRIPS_EXCEPTION(flag, "state");
if (!tz->trips.active[i].flags.valid)
break;
}
if (flag & ACPI_TRIPS_DEVICES) {
memset(&devices, 0, sizeof(struct acpi_handle_list));
status = acpi_evaluate_reference(tz->device->handle, "_TZD",
NULL, &devices);
if (memcmp(&tz->devices, &devices,
sizeof(struct acpi_handle_list))) {
memcpy(&tz->devices, &devices,
sizeof(struct acpi_handle_list));
ACPI_THERMAL_TRIPS_EXCEPTION(flag, "device");
}
} }
return 0; return 0;
} }
static int acpi_thermal_get_devices(struct acpi_thermal *tz) static int acpi_thermal_get_trip_points(struct acpi_thermal *tz)
{ {
acpi_status status = AE_OK; return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
if (!tz)
return -EINVAL;
status =
acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
} }
static int acpi_thermal_critical(struct acpi_thermal *tz) static int acpi_thermal_critical(struct acpi_thermal *tz)
{ {
if (!tz || !tz->trips.critical.flags.valid || nocrt) if (!tz || !tz->trips.critical.flags.valid)
return -EINVAL; return -EINVAL;
if (tz->temperature >= tz->trips.critical.temperature) { if (tz->temperature >= tz->trips.critical.temperature) {
@ -501,9 +548,6 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
} else if (tz->trips.critical.flags.enabled) } else if (tz->trips.critical.flags.enabled)
tz->trips.critical.flags.enabled = 0; tz->trips.critical.flags.enabled = 0;
printk(KERN_EMERG
"Critical temperature reached (%ld C), shutting down.\n",
KELVIN_TO_CELSIUS(tz->temperature));
acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL, acpi_bus_generate_proc_event(tz->device, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled); tz->trips.critical.flags.enabled);
acpi_bus_generate_netlink_event(tz->device->pnp.device_class, acpi_bus_generate_netlink_event(tz->device->pnp.device_class,
@ -511,14 +555,20 @@ static int acpi_thermal_critical(struct acpi_thermal *tz)
ACPI_THERMAL_NOTIFY_CRITICAL, ACPI_THERMAL_NOTIFY_CRITICAL,
tz->trips.critical.flags.enabled); tz->trips.critical.flags.enabled);
orderly_poweroff(true); /* take no action if nocrt is set */
if(!nocrt) {
printk(KERN_EMERG
"Critical temperature reached (%ld C), shutting down.\n",
KELVIN_TO_CELSIUS(tz->temperature));
orderly_poweroff(true);
}
return 0; return 0;
} }
static int acpi_thermal_hot(struct acpi_thermal *tz) static int acpi_thermal_hot(struct acpi_thermal *tz)
{ {
if (!tz || !tz->trips.hot.flags.valid || nocrt) if (!tz || !tz->trips.hot.flags.valid)
return -EINVAL; return -EINVAL;
if (tz->temperature >= tz->trips.hot.temperature) { if (tz->temperature >= tz->trips.hot.temperature) {
@ -534,7 +584,7 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
ACPI_THERMAL_NOTIFY_HOT, ACPI_THERMAL_NOTIFY_HOT,
tz->trips.hot.flags.enabled); tz->trips.hot.flags.enabled);
/* TBD: Call user-mode "sleep(S4)" function */ /* TBD: Call user-mode "sleep(S4)" function if nocrt is cleared */
return 0; return 0;
} }
@ -732,6 +782,9 @@ static void acpi_thermal_check(void *data)
if (result) if (result)
goto unlock; goto unlock;
if (!tz->tz_enabled)
goto unlock;
memset(&tz->state, 0, sizeof(tz->state)); memset(&tz->state, 0, sizeof(tz->state));
/* /*
@ -825,6 +878,290 @@ static void acpi_thermal_check(void *data)
mutex_unlock(&tz->lock); mutex_unlock(&tz->lock);
} }
/* sys I/F for generic thermal sysfs support */
static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
if (!tz)
return -EINVAL;
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature));
}
static const char enabled[] = "kernel";
static const char disabled[] = "user";
static int thermal_get_mode(struct thermal_zone_device *thermal,
char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
if (!tz)
return -EINVAL;
return sprintf(buf, "%s\n", tz->tz_enabled ?
enabled : disabled);
}
static int thermal_set_mode(struct thermal_zone_device *thermal,
const char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
int enable;
if (!tz)
return -EINVAL;
/*
* enable/disable thermal management from ACPI thermal driver
*/
if (!strncmp(buf, enabled, sizeof enabled - 1))
enable = 1;
else if (!strncmp(buf, disabled, sizeof disabled - 1))
enable = 0;
else
return -EINVAL;
if (enable != tz->tz_enabled) {
tz->tz_enabled = enable;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"%s ACPI thermal control\n",
tz->tz_enabled ? enabled : disabled));
acpi_thermal_check(tz);
}
return 0;
}
static int thermal_get_trip_type(struct thermal_zone_device *thermal,
int trip, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
if (!tz || trip < 0)
return -EINVAL;
if (tz->trips.critical.flags.valid) {
if (!trip)
return sprintf(buf, "critical\n");
trip--;
}
if (tz->trips.hot.flags.valid) {
if (!trip)
return sprintf(buf, "hot\n");
trip--;
}
if (tz->trips.passive.flags.valid) {
if (!trip)
return sprintf(buf, "passive\n");
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
if (!trip)
return sprintf(buf, "active%d\n", i);
trip--;
}
return -EINVAL;
}
static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
int trip, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
if (!tz || trip < 0)
return -EINVAL;
if (tz->trips.critical.flags.valid) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.critical.temperature));
trip--;
}
if (tz->trips.hot.flags.valid) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.hot.temperature));
trip--;
}
if (tz->trips.passive.flags.valid) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.passive.temperature));
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.active[i].temperature));
trip--;
}
return -EINVAL;
}
typedef int (*cb)(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev,
cb action)
{
struct acpi_device *device = cdev->devdata;
struct acpi_thermal *tz = thermal->devdata;
struct acpi_device *dev;
acpi_status status;
acpi_handle handle;
int i;
int j;
int trip = -1;
int result = 0;
if (tz->trips.critical.flags.valid)
trip++;
if (tz->trips.hot.flags.valid)
trip++;
if (tz->trips.passive.flags.valid) {
trip++;
for (i = 0; i < tz->trips.passive.devices.count;
i++) {
handle = tz->trips.passive.devices.handles[i];
status = acpi_bus_get_device(handle, &dev);
if (ACPI_SUCCESS(status) && (dev == device)) {
result = action(thermal, trip, cdev);
if (result)
goto failed;
}
}
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
if (!tz->trips.active[i].flags.valid)
break;
trip++;
for (j = 0;
j < tz->trips.active[i].devices.count;
j++) {
handle = tz->trips.active[i].devices.handles[j];
status = acpi_bus_get_device(handle, &dev);
if (ACPI_SUCCESS(status) && (dev == device)) {
result = action(thermal, trip, cdev);
if (result)
goto failed;
}
}
}
for (i = 0; i < tz->devices.count; i++) {
handle = tz->devices.handles[i];
status = acpi_bus_get_device(handle, &dev);
if (ACPI_SUCCESS(status) && (dev == device)) {
result = action(thermal, -1, cdev);
if (result)
goto failed;
}
}
failed:
return result;
}
static int
acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
return acpi_thermal_cooling_device_cb(thermal, cdev,
thermal_zone_bind_cooling_device);
}
static int
acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
return acpi_thermal_cooling_device_cb(thermal, cdev,
thermal_zone_unbind_cooling_device);
}
static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.bind = acpi_thermal_bind_cooling_device,
.unbind = acpi_thermal_unbind_cooling_device,
.get_temp = thermal_get_temp,
.get_mode = thermal_get_mode,
.set_mode = thermal_set_mode,
.get_trip_type = thermal_get_trip_type,
.get_trip_temp = thermal_get_trip_temp,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
{
int trips = 0;
int result;
acpi_status status;
int i;
if (tz->trips.critical.flags.valid)
trips++;
if (tz->trips.hot.flags.valid)
trips++;
if (tz->trips.passive.flags.valid)
trips++;
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++, trips++);
tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
trips, tz, &acpi_thermal_zone_ops);
if (!tz->thermal_zone)
return -ENODEV;
result = sysfs_create_link(&tz->device->dev.kobj,
&tz->thermal_zone->device.kobj, "thermal_zone");
if (result)
return result;
result = sysfs_create_link(&tz->thermal_zone->device.kobj,
&tz->device->dev.kobj, "device");
if (result)
return result;
status = acpi_attach_data(tz->device->handle,
acpi_bus_private_data_handler,
tz->thermal_zone);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error attaching device data\n"));
return -ENODEV;
}
tz->tz_enabled = 1;
printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
tz->device->dev.bus_id, tz->thermal_zone->id);
return 0;
}
static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
{
sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
thermal_zone_device_unregister(tz->thermal_zone);
tz->thermal_zone = NULL;
acpi_detach_data(tz->device->handle, acpi_bus_private_data_handler);
}
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
FS Interface (/proc) FS Interface (/proc)
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
@ -1181,15 +1518,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
acpi_thermal_check(tz); acpi_thermal_check(tz);
break; break;
case ACPI_THERMAL_NOTIFY_THRESHOLDS: case ACPI_THERMAL_NOTIFY_THRESHOLDS:
acpi_thermal_get_trip_points(tz); acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_THRESHOLDS);
acpi_thermal_check(tz); acpi_thermal_check(tz);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class, acpi_bus_generate_netlink_event(device->pnp.device_class,
device->dev.bus_id, event, 0); device->dev.bus_id, event, 0);
break; break;
case ACPI_THERMAL_NOTIFY_DEVICES: case ACPI_THERMAL_NOTIFY_DEVICES:
if (tz->flags.devices) acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
acpi_thermal_get_devices(tz); acpi_thermal_check(tz);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
acpi_bus_generate_netlink_event(device->pnp.device_class, acpi_bus_generate_netlink_event(device->pnp.device_class,
device->dev.bus_id, event, 0); device->dev.bus_id, event, 0);
@ -1232,11 +1569,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
else else
acpi_thermal_get_polling_frequency(tz); acpi_thermal_get_polling_frequency(tz);
/* Get devices in this thermal zone [_TZD] (optional) */
result = acpi_thermal_get_devices(tz);
if (!result)
tz->flags.devices = 1;
return 0; return 0;
} }
@ -1260,13 +1592,19 @@ static int acpi_thermal_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_driver_data(device) = tz; acpi_driver_data(device) = tz;
mutex_init(&tz->lock); mutex_init(&tz->lock);
result = acpi_thermal_get_info(tz); result = acpi_thermal_get_info(tz);
if (result) if (result)
goto end; goto free_memory;
result = acpi_thermal_register_thermal_zone(tz);
if (result)
goto free_memory;
result = acpi_thermal_add_fs(device); result = acpi_thermal_add_fs(device);
if (result) if (result)
goto end; goto unregister_thermal_zone;
init_timer(&tz->timer); init_timer(&tz->timer);
@ -1277,19 +1615,21 @@ static int acpi_thermal_add(struct acpi_device *device)
acpi_thermal_notify, tz); acpi_thermal_notify, tz);
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
result = -ENODEV; result = -ENODEV;
goto end; goto remove_fs;
} }
printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
acpi_device_name(device), acpi_device_bid(device), acpi_device_name(device), acpi_device_bid(device),
KELVIN_TO_CELSIUS(tz->temperature)); KELVIN_TO_CELSIUS(tz->temperature));
goto end;
end: remove_fs:
if (result) { acpi_thermal_remove_fs(device);
acpi_thermal_remove_fs(device); unregister_thermal_zone:
kfree(tz); thermal_zone_device_unregister(tz->thermal_zone);
} free_memory:
kfree(tz);
end:
return result; return result;
} }
@ -1329,6 +1669,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
} }
acpi_thermal_remove_fs(device); acpi_thermal_remove_fs(device);
acpi_thermal_unregister_thermal_zone(tz);
mutex_destroy(&tz->lock); mutex_destroy(&tz->lock);
kfree(tz); kfree(tz);
return 0; return 0;

View File

@ -671,7 +671,6 @@ void acpi_ut_init_globals(void)
/* GPE support */ /* GPE support */
acpi_gpe_count = 0;
acpi_gbl_gpe_xrupt_list_head = NULL; acpi_gbl_gpe_xrupt_list_head = NULL;
acpi_gbl_gpe_fadt_blocks[0] = NULL; acpi_gbl_gpe_fadt_blocks[0] = NULL;
acpi_gbl_gpe_fadt_blocks[1] = NULL; acpi_gbl_gpe_fadt_blocks[1] = NULL;
@ -735,4 +734,3 @@ void acpi_ut_init_globals(void)
ACPI_EXPORT_SYMBOL(acpi_dbg_level) ACPI_EXPORT_SYMBOL(acpi_dbg_level)
ACPI_EXPORT_SYMBOL(acpi_dbg_layer) ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
ACPI_EXPORT_SYMBOL(acpi_gpe_count)

View File

@ -34,6 +34,7 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/input.h> #include <linux/input.h>
#include <linux/backlight.h> #include <linux/backlight.h>
#include <linux/thermal.h>
#include <linux/video_output.h> #include <linux/video_output.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
@ -72,8 +73,12 @@ MODULE_AUTHOR("Bruno Ducrot");
MODULE_DESCRIPTION("ACPI Video Driver"); MODULE_DESCRIPTION("ACPI Video Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
static int brightness_switch_enabled = 1;
module_param(brightness_switch_enabled, bool, 0644);
static int acpi_video_bus_add(struct acpi_device *device); static int acpi_video_bus_add(struct acpi_device *device);
static int acpi_video_bus_remove(struct acpi_device *device, int type); static int acpi_video_bus_remove(struct acpi_device *device, int type);
static int acpi_video_resume(struct acpi_device *device);
static const struct acpi_device_id video_device_ids[] = { static const struct acpi_device_id video_device_ids[] = {
{ACPI_VIDEO_HID, 0}, {ACPI_VIDEO_HID, 0},
@ -88,6 +93,7 @@ static struct acpi_driver acpi_video_bus = {
.ops = { .ops = {
.add = acpi_video_bus_add, .add = acpi_video_bus_add,
.remove = acpi_video_bus_remove, .remove = acpi_video_bus_remove,
.resume = acpi_video_resume,
}, },
}; };
@ -179,6 +185,7 @@ struct acpi_video_device {
struct acpi_device *dev; struct acpi_device *dev;
struct acpi_video_device_brightness *brightness; struct acpi_video_device_brightness *brightness;
struct backlight_device *backlight; struct backlight_device *backlight;
struct thermal_cooling_device *cdev;
struct output_device *output_dev; struct output_device *output_dev;
}; };
@ -273,7 +280,6 @@ static void acpi_video_device_rebind(struct acpi_video_bus *video);
static void acpi_video_device_bind(struct acpi_video_bus *video, static void acpi_video_device_bind(struct acpi_video_bus *video,
struct acpi_video_device *device); struct acpi_video_device *device);
static int acpi_video_device_enumerate(struct acpi_video_bus *video); static int acpi_video_device_enumerate(struct acpi_video_bus *video);
static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
static int acpi_video_device_lcd_set_level(struct acpi_video_device *device, static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
int level); int level);
static int acpi_video_device_lcd_get_level_current( static int acpi_video_device_lcd_get_level_current(
@ -292,18 +298,26 @@ static int acpi_video_device_set_state(struct acpi_video_device *device, int sta
static int acpi_video_get_brightness(struct backlight_device *bd) static int acpi_video_get_brightness(struct backlight_device *bd)
{ {
unsigned long cur_level; unsigned long cur_level;
int i;
struct acpi_video_device *vd = struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd); (struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_get_level_current(vd, &cur_level); acpi_video_device_lcd_get_level_current(vd, &cur_level);
return (int) cur_level; for (i = 2; i < vd->brightness->count; i++) {
if (vd->brightness->levels[i] == cur_level)
/* The first two entries are special - see page 575
of the ACPI spec 3.0 */
return i-2;
}
return 0;
} }
static int acpi_video_set_brightness(struct backlight_device *bd) static int acpi_video_set_brightness(struct backlight_device *bd)
{ {
int request_level = bd->props.brightness; int request_level = bd->props.brightness+2;
struct acpi_video_device *vd = struct acpi_video_device *vd =
(struct acpi_video_device *)bl_get_data(bd); (struct acpi_video_device *)bl_get_data(bd);
acpi_video_device_lcd_set_level(vd, request_level); acpi_video_device_lcd_set_level(vd,
vd->brightness->levels[request_level]);
return 0; return 0;
} }
@ -334,6 +348,54 @@ static struct output_properties acpi_output_properties = {
.set_state = acpi_video_output_set, .set_state = acpi_video_output_set,
.get_status = acpi_video_output_get, .get_status = acpi_video_output_get,
}; };
/* thermal cooling device callbacks */
static int video_get_max_state(struct thermal_cooling_device *cdev, char *buf)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
return sprintf(buf, "%d\n", video->brightness->count - 3);
}
static int video_get_cur_state(struct thermal_cooling_device *cdev, char *buf)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
unsigned long level;
int state;
acpi_video_device_lcd_get_level_current(video, &level);
for (state = 2; state < video->brightness->count; state++)
if (level == video->brightness->levels[state])
return sprintf(buf, "%d\n",
video->brightness->count - state - 1);
return -EINVAL;
}
static int
video_set_cur_state(struct thermal_cooling_device *cdev, unsigned int state)
{
struct acpi_device *device = cdev->devdata;
struct acpi_video_device *video = acpi_driver_data(device);
int level;
if ( state >= video->brightness->count - 2)
return -EINVAL;
state = video->brightness->count - state;
level = video->brightness->levels[state -1];
return acpi_video_device_lcd_set_level(video, level);
}
static struct thermal_cooling_device_ops video_cooling_ops = {
.get_max_state = video_get_max_state,
.get_cur_state = video_get_cur_state,
.set_cur_state = video_set_cur_state,
};
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Video Management Video Management
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
@ -652,7 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
kfree(obj); kfree(obj);
if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){ if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
unsigned long tmp; int result;
static int count = 0; static int count = 0;
char *name; char *name;
name = kzalloc(MAX_NAME_LEN, GFP_KERNEL); name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
@ -660,14 +722,30 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
return; return;
sprintf(name, "acpi_video%d", count++); sprintf(name, "acpi_video%d", count++);
acpi_video_device_lcd_get_level_current(device, &tmp);
device->backlight = backlight_device_register(name, device->backlight = backlight_device_register(name,
NULL, device, &acpi_backlight_ops); NULL, device, &acpi_backlight_ops);
device->backlight->props.max_brightness = max_level; device->backlight->props.max_brightness = device->brightness->count-3;
device->backlight->props.brightness = (int)tmp; device->backlight->props.brightness = acpi_video_get_brightness(device->backlight);
backlight_update_status(device->backlight); backlight_update_status(device->backlight);
kfree(name); kfree(name);
device->cdev = thermal_cooling_device_register("LCD",
device->dev, &video_cooling_ops);
if (device->cdev) {
printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n",
device->dev->dev.bus_id, device->cdev->id);
result = sysfs_create_link(&device->dev->dev.kobj,
&device->cdev->device.kobj,
"thermal_cooling");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
result = sysfs_create_link(&device->cdev->device.kobj,
&device->dev->dev.kobj,
"device");
if (result)
printk(KERN_ERR PREFIX "Create sysfs link\n");
}
} }
if (device->cap._DCS && device->cap._DSS){ if (device->cap._DCS && device->cap._DSS){
static int count = 0; static int count = 0;
@ -726,11 +804,40 @@ static void acpi_video_bus_find_cap(struct acpi_video_bus *video)
static int acpi_video_bus_check(struct acpi_video_bus *video) static int acpi_video_bus_check(struct acpi_video_bus *video)
{ {
acpi_status status = -ENOENT; acpi_status status = -ENOENT;
long device_id;
struct device *dev;
struct acpi_device *device;
if (!video) if (!video)
return -EINVAL; return -EINVAL;
device = video->device;
status =
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
if (!ACPI_SUCCESS(status))
return -ENODEV;
/* We need to attempt to determine whether the _ADR refers to a
PCI device or not. There's no terribly good way to do this,
so the best we can hope for is to assume that there'll never
be a video device in the host bridge */
if (device_id >= 0x10000) {
/* It looks like a PCI device. Does it exist? */
dev = acpi_get_physical_device(device->handle);
} else {
/* It doesn't look like a PCI device. Does its parent
exist? */
acpi_handle phandle;
if (acpi_get_parent(device->handle, &phandle))
return -ENODEV;
dev = acpi_get_physical_device(phandle);
}
if (!dev)
return -ENODEV;
put_device(dev);
/* Since there is no HID, CID and so on for VGA driver, we have /* Since there is no HID, CID and so on for VGA driver, we have
* to check well known required nodes. * to check well known required nodes.
*/ */
@ -1256,8 +1363,37 @@ acpi_video_bus_write_DOS(struct file *file,
static int acpi_video_bus_add_fs(struct acpi_device *device) static int acpi_video_bus_add_fs(struct acpi_device *device)
{ {
long device_id;
int status;
struct proc_dir_entry *entry = NULL; struct proc_dir_entry *entry = NULL;
struct acpi_video_bus *video; struct acpi_video_bus *video;
struct device *dev;
status =
acpi_evaluate_integer(device->handle, "_ADR", NULL, &device_id);
if (!ACPI_SUCCESS(status))
return -ENODEV;
/* We need to attempt to determine whether the _ADR refers to a
PCI device or not. There's no terribly good way to do this,
so the best we can hope for is to assume that there'll never
be a video device in the host bridge */
if (device_id >= 0x10000) {
/* It looks like a PCI device. Does it exist? */
dev = acpi_get_physical_device(device->handle);
} else {
/* It doesn't look like a PCI device. Does its parent
exist? */
acpi_handle phandle;
if (acpi_get_parent(device->handle, &phandle))
return -ENODEV;
dev = acpi_get_physical_device(phandle);
}
if (!dev)
return -ENODEV;
put_device(dev);
video = acpi_driver_data(device); video = acpi_driver_data(device);
@ -1580,64 +1716,6 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
return status; return status;
} }
/*
* Arg:
* video : video bus device
* event : notify event
*
* Return:
* < 0 : error
*
* 1. Find out the current active output device.
* 2. Identify the next output device to switch to.
* 3. call _DSS to do actual switch.
*/
static int acpi_video_switch_output(struct acpi_video_bus *video, int event)
{
struct list_head *node;
struct acpi_video_device *dev = NULL;
struct acpi_video_device *dev_next = NULL;
struct acpi_video_device *dev_prev = NULL;
unsigned long state;
int status = 0;
mutex_lock(&video->device_list_lock);
list_for_each(node, &video->video_device_list) {
dev = container_of(node, struct acpi_video_device, entry);
status = acpi_video_device_get_state(dev, &state);
if (state & 0x2) {
dev_next = container_of(node->next,
struct acpi_video_device, entry);
dev_prev = container_of(node->prev,
struct acpi_video_device, entry);
goto out;
}
}
dev_next = container_of(node->next, struct acpi_video_device, entry);
dev_prev = container_of(node->prev, struct acpi_video_device, entry);
out:
mutex_unlock(&video->device_list_lock);
switch (event) {
case ACPI_VIDEO_NOTIFY_CYCLE:
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT:
acpi_video_device_set_state(dev, 0);
acpi_video_device_set_state(dev_next, 0x80000001);
break;
case ACPI_VIDEO_NOTIFY_PREV_OUTPUT:
acpi_video_device_set_state(dev, 0);
acpi_video_device_set_state(dev_prev, 0x80000001);
default:
break;
}
return status;
}
static int static int
acpi_video_get_next_level(struct acpi_video_device *device, acpi_video_get_next_level(struct acpi_video_device *device,
u32 level_current, u32 event) u32 level_current, u32 event)
@ -1729,6 +1807,14 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
ACPI_DEVICE_NOTIFY, ACPI_DEVICE_NOTIFY,
acpi_video_device_notify); acpi_video_device_notify);
backlight_device_unregister(device->backlight); backlight_device_unregister(device->backlight);
if (device->cdev) {
sysfs_remove_link(&device->dev->dev.kobj,
"thermal_cooling");
sysfs_remove_link(&device->cdev->device.kobj,
"device");
thermal_cooling_device_unregister(device->cdev);
device->cdev = NULL;
}
video_output_unregister(device->output_dev); video_output_unregister(device->output_dev);
return 0; return 0;
@ -1797,23 +1883,19 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
* connector. */ * connector. */
acpi_video_device_enumerate(video); acpi_video_device_enumerate(video);
acpi_video_device_rebind(video); acpi_video_device_rebind(video);
acpi_video_switch_output(video, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_SWITCHVIDEOMODE; keycode = KEY_SWITCHVIDEOMODE;
break; break;
case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */ case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
acpi_video_switch_output(video, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_SWITCHVIDEOMODE; keycode = KEY_SWITCHVIDEOMODE;
break; break;
case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */ case ACPI_VIDEO_NOTIFY_NEXT_OUTPUT: /* Next Display output hotkey pressed. */
acpi_video_switch_output(video, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_VIDEO_NEXT; keycode = KEY_VIDEO_NEXT;
break; break;
case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */ case ACPI_VIDEO_NOTIFY_PREV_OUTPUT: /* previous Display output hotkey pressed. */
acpi_video_switch_output(video, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_VIDEO_PREV; keycode = KEY_VIDEO_PREV;
break; break;
@ -1825,6 +1907,7 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
break; break;
} }
acpi_notifier_call_chain(device, event, 0);
input_report_key(input, keycode, 1); input_report_key(input, keycode, 1);
input_sync(input); input_sync(input);
input_report_key(input, keycode, 0); input_report_key(input, keycode, 0);
@ -1850,27 +1933,32 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
switch (event) { switch (event) {
case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */ case ACPI_VIDEO_NOTIFY_CYCLE_BRIGHTNESS: /* Cycle brightness */
acpi_video_switch_brightness(video_device, event); if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESS_CYCLE; keycode = KEY_BRIGHTNESS_CYCLE;
break; break;
case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */ case ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS: /* Increase brightness */
acpi_video_switch_brightness(video_device, event); if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESSUP; keycode = KEY_BRIGHTNESSUP;
break; break;
case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */ case ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS: /* Decrease brightness */
acpi_video_switch_brightness(video_device, event); if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESSDOWN; keycode = KEY_BRIGHTNESSDOWN;
break; break;
case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */ case ACPI_VIDEO_NOTIFY_ZERO_BRIGHTNESS: /* zero brightnesss */
acpi_video_switch_brightness(video_device, event); if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_BRIGHTNESS_ZERO; keycode = KEY_BRIGHTNESS_ZERO;
break; break;
case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */ case ACPI_VIDEO_NOTIFY_DISPLAY_OFF: /* display device off */
acpi_video_switch_brightness(video_device, event); if (brightness_switch_enabled)
acpi_video_switch_brightness(video_device, event);
acpi_bus_generate_proc_event(device, event, 0); acpi_bus_generate_proc_event(device, event, 0);
keycode = KEY_DISPLAY_OFF; keycode = KEY_DISPLAY_OFF;
break; break;
@ -1881,6 +1969,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
break; break;
} }
acpi_notifier_call_chain(device, event, 0);
input_report_key(input, keycode, 1); input_report_key(input, keycode, 1);
input_sync(input); input_sync(input);
input_report_key(input, keycode, 0); input_report_key(input, keycode, 0);
@ -1890,6 +1979,25 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
} }
static int instance; static int instance;
static int acpi_video_resume(struct acpi_device *device)
{
struct acpi_video_bus *video;
struct acpi_video_device *video_device;
int i;
if (!device || !acpi_driver_data(device))
return -EINVAL;
video = acpi_driver_data(device);
for (i = 0; i < video->attached_count; i++) {
video_device = video->attached_array[i].bind_info;
if (video_device && video_device->backlight)
acpi_video_set_brightness(video_device->backlight);
}
return AE_OK;
}
static int acpi_video_bus_add(struct acpi_device *device) static int acpi_video_bus_add(struct acpi_device *device)
{ {
acpi_status status; acpi_status status;

710
drivers/acpi/wmi.c Normal file
View File

@ -0,0 +1,710 @@
/*
* ACPI-WMI mapping driver
*
* Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
*
* GUID parsing code from ldm.c is:
* Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
* Copyright (c) 2001-2007 Anton Altaparmakov
* Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/list.h>
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
ACPI_MODULE_NAME("wmi");
MODULE_AUTHOR("Carlos Corbacho");
MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
MODULE_LICENSE("GPL");
#define ACPI_WMI_CLASS "wmi"
#undef PREFIX
#define PREFIX "ACPI: WMI: "
static DEFINE_MUTEX(wmi_data_lock);
struct guid_block {
char guid[16];
union {
char object_id[2];
struct {
unsigned char notify_id;
unsigned char reserved;
};
};
u8 instance_count;
u8 flags;
};
struct wmi_block {
struct list_head list;
struct guid_block gblock;
acpi_handle handle;
wmi_notify_handler handler;
void *handler_data;
};
static struct wmi_block wmi_blocks;
/*
* If the GUID data block is marked as expensive, we must enable and
* explicitily disable data collection.
*/
#define ACPI_WMI_EXPENSIVE 0x1
#define ACPI_WMI_METHOD 0x2 /* GUID is a method */
#define ACPI_WMI_STRING 0x4 /* GUID takes & returns a string */
#define ACPI_WMI_EVENT 0x8 /* GUID is an event */
static int acpi_wmi_remove(struct acpi_device *device, int type);
static int acpi_wmi_add(struct acpi_device *device);
static const struct acpi_device_id wmi_device_ids[] = {
{"PNP0C14", 0},
{"pnp0c14", 0},
{"", 0},
};
MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
static struct acpi_driver acpi_wmi_driver = {
.name = "wmi",
.class = ACPI_WMI_CLASS,
.ids = wmi_device_ids,
.ops = {
.add = acpi_wmi_add,
.remove = acpi_wmi_remove,
},
};
/*
* GUID parsing functions
*/
/**
* wmi_parse_hexbyte - Convert a ASCII hex number to a byte
* @src: Pointer to at least 2 characters to convert.
*
* Convert a two character ASCII hex string to a number.
*
* Return: 0-255 Success, the byte was parsed correctly
* -1 Error, an invalid character was supplied
*/
static int wmi_parse_hexbyte(const u8 *src)
{
unsigned int x; /* For correct wrapping */
int h;
/* high part */
x = src[0];
if (x - '0' <= '9' - '0') {
h = x - '0';
} else if (x - 'a' <= 'f' - 'a') {
h = x - 'a' + 10;
} else if (x - 'A' <= 'F' - 'A') {
h = x - 'A' + 10;
} else {
return -1;
}
h <<= 4;
/* low part */
x = src[1];
if (x - '0' <= '9' - '0')
return h | (x - '0');
if (x - 'a' <= 'f' - 'a')
return h | (x - 'a' + 10);
if (x - 'A' <= 'F' - 'A')
return h | (x - 'A' + 10);
return -1;
}
/**
* wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
* @src: Memory block holding binary GUID (16 bytes)
* @dest: Memory block to hold byte swapped binary GUID (16 bytes)
*
* Byte swap a binary GUID to match it's real GUID value
*/
static void wmi_swap_bytes(u8 *src, u8 *dest)
{
int i;
for (i = 0; i <= 3; i++)
memcpy(dest + i, src + (3 - i), 1);
for (i = 0; i <= 1; i++)
memcpy(dest + 4 + i, src + (5 - i), 1);
for (i = 0; i <= 1; i++)
memcpy(dest + 6 + i, src + (7 - i), 1);
memcpy(dest + 8, src + 8, 8);
}
/**
* wmi_parse_guid - Convert GUID from ASCII to binary
* @src: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
* @dest: Memory block to hold binary GUID (16 bytes)
*
* N.B. The GUID need not be NULL terminated.
*
* Return: 'true' @dest contains binary GUID
* 'false' @dest contents are undefined
*/
static bool wmi_parse_guid(const u8 *src, u8 *dest)
{
static const int size[] = { 4, 2, 2, 2, 6 };
int i, j, v;
if (src[8] != '-' || src[13] != '-' ||
src[18] != '-' || src[23] != '-')
return false;
for (j = 0; j < 5; j++, src++) {
for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
v = wmi_parse_hexbyte(src);
if (v < 0)
return false;
}
}
return true;
}
static bool find_guid(const char *guid_string, struct wmi_block **out)
{
char tmp[16], guid_input[16];
struct wmi_block *wblock;
struct guid_block *block;
struct list_head *p;
wmi_parse_guid(guid_string, tmp);
wmi_swap_bytes(tmp, guid_input);
list_for_each(p, &wmi_blocks.list) {
wblock = list_entry(p, struct wmi_block, list);
block = &wblock->gblock;
if (memcmp(block->guid, guid_input, 16) == 0) {
if (out)
*out = wblock;
return 1;
}
}
return 0;
}
/*
* Exported WMI functions
*/
/**
* wmi_evaluate_method - Evaluate a WMI method
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
* @instance: Instance index
* @method_id: Method ID to call
* &in: Buffer containing input for the method call
* &out: Empty buffer to return the method results
*
* Call an ACPI-WMI method
*/
acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
{
struct guid_block *block = NULL;
struct wmi_block *wblock = NULL;
acpi_handle handle;
acpi_status status;
struct acpi_object_list input;
union acpi_object params[3];
char method[4] = "WM";
if (!find_guid(guid_string, &wblock))
return AE_BAD_ADDRESS;
block = &wblock->gblock;
handle = wblock->handle;
if (!block->flags & ACPI_WMI_METHOD)
return AE_BAD_DATA;
if (block->instance_count < instance)
return AE_BAD_PARAMETER;
input.count = 2;
input.pointer = params;
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = instance;
params[1].type = ACPI_TYPE_INTEGER;
params[1].integer.value = method_id;
if (in) {
input.count = 3;
if (block->flags & ACPI_WMI_STRING) {
params[2].type = ACPI_TYPE_STRING;
} else {
params[2].type = ACPI_TYPE_BUFFER;
}
params[2].buffer.length = in->length;
params[2].buffer.pointer = in->pointer;
}
strncat(method, block->object_id, 2);
status = acpi_evaluate_object(handle, method, &input, out);
return status;
}
EXPORT_SYMBOL_GPL(wmi_evaluate_method);
/**
* wmi_query_block - Return contents of a WMI block
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
* @instance: Instance index
* &out: Empty buffer to return the contents of the data block to
*
* Return the contents of an ACPI-WMI data block to a buffer
*/
acpi_status wmi_query_block(const char *guid_string, u8 instance,
struct acpi_buffer *out)
{
struct guid_block *block = NULL;
struct wmi_block *wblock = NULL;
acpi_handle handle;
acpi_status status, wc_status = AE_ERROR;
struct acpi_object_list input, wc_input;
union acpi_object wc_params[1], wq_params[1];
char method[4];
char wc_method[4] = "WC";
if (!guid_string || !out)
return AE_BAD_PARAMETER;
if (!find_guid(guid_string, &wblock))
return AE_BAD_ADDRESS;
block = &wblock->gblock;
handle = wblock->handle;
if (block->instance_count < instance)
return AE_BAD_PARAMETER;
/* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
return AE_BAD_ADDRESS;
input.count = 1;
input.pointer = wq_params;
wq_params[0].type = ACPI_TYPE_INTEGER;
wq_params[0].integer.value = instance;
/*
* If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
* enable collection.
*/
if (block->flags & ACPI_WMI_EXPENSIVE) {
wc_input.count = 1;
wc_input.pointer = wc_params;
wc_params[0].type = ACPI_TYPE_INTEGER;
wc_params[0].integer.value = 1;
strncat(wc_method, block->object_id, 2);
/*
* Some GUIDs break the specification by declaring themselves
* expensive, but have no corresponding WCxx method. So we
* should not fail if this happens.
*/
wc_status = acpi_evaluate_object(handle, wc_method,
&wc_input, NULL);
}
strcpy(method, "WQ");
strncat(method, block->object_id, 2);
status = acpi_evaluate_object(handle, method, NULL, out);
/*
* If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
* the WQxx method failed - we should disable collection anyway.
*/
if ((block->flags & ACPI_WMI_EXPENSIVE) && wc_status) {
wc_params[0].integer.value = 0;
status = acpi_evaluate_object(handle,
wc_method, &wc_input, NULL);
}
return status;
}
EXPORT_SYMBOL_GPL(wmi_query_block);
/**
* wmi_set_block - Write to a WMI block
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
* @instance: Instance index
* &in: Buffer containing new values for the data block
*
* Write the contents of the input buffer to an ACPI-WMI data block
*/
acpi_status wmi_set_block(const char *guid_string, u8 instance,
const struct acpi_buffer *in)
{
struct guid_block *block = NULL;
struct wmi_block *wblock = NULL;
acpi_handle handle;
struct acpi_object_list input;
union acpi_object params[2];
char method[4] = "WS";
if (!guid_string || !in)
return AE_BAD_DATA;
if (!find_guid(guid_string, &wblock))
return AE_BAD_ADDRESS;
block = &wblock->gblock;
handle = wblock->handle;
if (block->instance_count < instance)
return AE_BAD_PARAMETER;
/* Check GUID is a data block */
if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
return AE_BAD_ADDRESS;
input.count = 2;
input.pointer = params;
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = instance;
if (block->flags & ACPI_WMI_STRING) {
params[1].type = ACPI_TYPE_STRING;
} else {
params[1].type = ACPI_TYPE_BUFFER;
}
params[1].buffer.length = in->length;
params[1].buffer.pointer = in->pointer;
strncat(method, block->object_id, 2);
return acpi_evaluate_object(handle, method, &input, NULL);
}
EXPORT_SYMBOL_GPL(wmi_set_block);
/**
* wmi_install_notify_handler - Register handler for WMI events
* @handler: Function to handle notifications
* @data: Data to be returned to handler when event is fired
*
* Register a handler for events sent to the ACPI-WMI mapper device.
*/
acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data)
{
struct wmi_block *block;
if (!guid || !handler)
return AE_BAD_PARAMETER;
find_guid(guid, &block);
if (!block)
return AE_NOT_EXIST;
if (block->handler)
return AE_ALREADY_ACQUIRED;
block->handler = handler;
block->handler_data = data;
return AE_OK;
}
EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
/**
* wmi_uninstall_notify_handler - Unregister handler for WMI events
*
* Unregister handler for events sent to the ACPI-WMI mapper device.
*/
acpi_status wmi_remove_notify_handler(const char *guid)
{
struct wmi_block *block;
if (!guid)
return AE_BAD_PARAMETER;
find_guid(guid, &block);
if (!block)
return AE_NOT_EXIST;
if (!block->handler)
return AE_NULL_ENTRY;
block->handler = NULL;
block->handler_data = NULL;
return AE_OK;
}
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
/**
* wmi_get_event_data - Get WMI data associated with an event
*
* @event - Event to find
* &out - Buffer to hold event data
*
* Returns extra data associated with an event in WMI.
*/
acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
{
struct acpi_object_list input;
union acpi_object params[1];
struct guid_block *gblock;
struct wmi_block *wblock;
struct list_head *p;
input.count = 1;
input.pointer = params;
params[0].type = ACPI_TYPE_INTEGER;
params[0].integer.value = event;
list_for_each(p, &wmi_blocks.list) {
wblock = list_entry(p, struct wmi_block, list);
gblock = &wblock->gblock;
if ((gblock->flags & ACPI_WMI_EVENT) &&
(gblock->notify_id == event))
return acpi_evaluate_object(wblock->handle, "_WED",
&input, out);
}
return AE_NOT_FOUND;
}
EXPORT_SYMBOL_GPL(wmi_get_event_data);
/**
* wmi_has_guid - Check if a GUID is available
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
*
* Check if a given GUID is defined by _WDG
*/
bool wmi_has_guid(const char *guid_string)
{
return find_guid(guid_string, NULL);
}
EXPORT_SYMBOL_GPL(wmi_has_guid);
/*
* Parse the _WDG method for the GUID data blocks
*/
static __init acpi_status parse_wdg(acpi_handle handle)
{
struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *obj;
struct guid_block *gblock;
struct wmi_block *wblock;
acpi_status status;
u32 i, total;
status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
if (ACPI_FAILURE(status))
return status;
obj = (union acpi_object *) out.pointer;
if (obj->type != ACPI_TYPE_BUFFER)
return AE_ERROR;
total = obj->buffer.length / sizeof(struct guid_block);
gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
if (!gblock)
return AE_NO_MEMORY;
memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
for (i = 0; i < total; i++) {
wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
if (!wblock)
return AE_NO_MEMORY;
wblock->gblock = gblock[i];
wblock->handle = handle;
list_add_tail(&wblock->list, &wmi_blocks.list);
}
kfree(out.pointer);
kfree(gblock);
return status;
}
/*
* WMI can have EmbeddedControl access regions. In which case, we just want to
* hand these off to the EC driver.
*/
static acpi_status
acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
u32 bits, acpi_integer * value,
void *handler_context, void *region_context)
{
int result = 0, i = 0;
u8 temp = 0;
if ((address > 0xFF) || !value)
return AE_BAD_PARAMETER;
if (function != ACPI_READ && function != ACPI_WRITE)
return AE_BAD_PARAMETER;
if (bits != 8)
return AE_BAD_PARAMETER;
if (function == ACPI_READ) {
result = ec_read(address, &temp);
(*value) |= ((acpi_integer)temp) << i;
} else {
temp = 0xff & ((*value) >> i);
result = ec_write(address, temp);
}
switch (result) {
case -EINVAL:
return AE_BAD_PARAMETER;
break;
case -ENODEV:
return AE_NOT_FOUND;
break;
case -ETIME:
return AE_TIME;
break;
default:
return AE_OK;
}
}
static void acpi_wmi_notify(acpi_handle handle, u32 event, void *data)
{
struct guid_block *block;
struct wmi_block *wblock;
struct list_head *p;
struct acpi_device *device = data;
list_for_each(p, &wmi_blocks.list) {
wblock = list_entry(p, struct wmi_block, list);
block = &wblock->gblock;
if ((block->flags & ACPI_WMI_EVENT) &&
(block->notify_id == event)) {
if (wblock->handler)
wblock->handler(event, wblock->handler_data);
acpi_bus_generate_netlink_event(
device->pnp.device_class, device->dev.bus_id,
event, 0);
break;
}
}
}
static int acpi_wmi_remove(struct acpi_device *device, int type)
{
acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
acpi_wmi_notify);
acpi_remove_address_space_handler(device->handle,
ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
return 0;
}
static int __init acpi_wmi_add(struct acpi_device *device)
{
acpi_status status;
int result = 0;
status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
acpi_wmi_notify, device);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "Error installing notify handler\n");
return -ENODEV;
}
status = acpi_install_address_space_handler(device->handle,
ACPI_ADR_SPACE_EC,
&acpi_wmi_ec_space_handler,
NULL, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
status = parse_wdg(device->handle);
if (ACPI_FAILURE(status)) {
printk(KERN_ERR PREFIX "Error installing EC region handler\n");
return -ENODEV;
}
return result;
}
static int __init acpi_wmi_init(void)
{
acpi_status result;
if (acpi_disabled)
return -ENODEV;
INIT_LIST_HEAD(&wmi_blocks.list);
result = acpi_bus_register_driver(&acpi_wmi_driver);
if (result < 0) {
printk(KERN_INFO PREFIX "Error loading mapper\n");
} else {
printk(KERN_INFO PREFIX "Mapper loaded\n");
}
return result;
}
static void __exit acpi_wmi_exit(void)
{
struct list_head *p, *tmp;
struct wmi_block *wblock;
acpi_bus_unregister_driver(&acpi_wmi_driver);
list_for_each_safe(p, tmp, &wmi_blocks.list) {
wblock = list_entry(p, struct wmi_block, list);
list_del(p);
kfree(wblock);
}
printk(KERN_INFO PREFIX "Mapper unloaded\n");
}
subsys_initcall(acpi_wmi_init);
module_exit(acpi_wmi_exit);

View File

@ -1,13 +1,13 @@
config CPU_IDLE config CPU_IDLE
bool "CPU idle PM support" bool "CPU idle PM support"
default ACPI
help help
CPU idle is a generic framework for supporting software-controlled CPU idle is a generic framework for supporting software-controlled
idle processor power management. It includes modular cross-platform idle processor power management. It includes modular cross-platform
governors that can be swapped during runtime. governors that can be swapped during runtime.
If you're using a mobile platform that supports CPU idle PM (e.g. If you're using an ACPI-enabled platform, you should say Y here.
an ACPI-capable notebook), you should say Y here.
config CPU_IDLE_GOV_LADDER config CPU_IDLE_GOV_LADDER
bool bool

View File

@ -15,6 +15,7 @@
#include <linux/pm_qos_params.h> #include <linux/pm_qos_params.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/cpuidle.h> #include <linux/cpuidle.h>
#include <linux/ktime.h>
#include "cpuidle.h" #include "cpuidle.h"
@ -180,6 +181,44 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
EXPORT_SYMBOL_GPL(cpuidle_disable_device); EXPORT_SYMBOL_GPL(cpuidle_disable_device);
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
static int poll_idle(struct cpuidle_device *dev, struct cpuidle_state *st)
{
ktime_t t1, t2;
s64 diff;
int ret;
t1 = ktime_get();
local_irq_enable();
while (!need_resched())
cpu_relax();
t2 = ktime_get();
diff = ktime_to_us(ktime_sub(t2, t1));
if (diff > INT_MAX)
diff = INT_MAX;
ret = (int) diff;
return ret;
}
static void poll_idle_init(struct cpuidle_device *dev)
{
struct cpuidle_state *state = &dev->states[0];
cpuidle_set_statedata(state, NULL);
snprintf(state->name, CPUIDLE_NAME_LEN, "C0 (poll idle)");
state->exit_latency = 0;
state->target_residency = 0;
state->power_usage = -1;
state->flags = CPUIDLE_FLAG_POLL | CPUIDLE_FLAG_TIME_VALID;
state->enter = poll_idle;
}
#else
static void poll_idle_init(struct cpuidle_device *dev) {}
#endif /* CONFIG_ARCH_HAS_CPU_RELAX */
/** /**
* cpuidle_register_device - registers a CPU's idle PM feature * cpuidle_register_device - registers a CPU's idle PM feature
* @dev: the cpu * @dev: the cpu
@ -198,6 +237,8 @@ int cpuidle_register_device(struct cpuidle_device *dev)
mutex_lock(&cpuidle_lock); mutex_lock(&cpuidle_lock);
poll_idle_init(dev);
per_cpu(cpuidle_devices, dev->cpu) = dev; per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices); list_add(&dev->device_list, &cpuidle_detected_devices);
if ((ret = cpuidle_add_sysfs(sys_dev))) { if ((ret = cpuidle_add_sysfs(sys_dev))) {

View File

@ -489,12 +489,3 @@ int dmi_get_year(int field)
return year; return year;
} }
/**
* dmi_get_slot - return dmi_ident[slot]
* @slot: index into dmi_ident[]
*/
char *dmi_get_slot(int slot)
{
return(dmi_ident[slot]);
}

View File

@ -92,6 +92,22 @@ config TIFM_7XX1
To compile this driver as a module, choose M here: the module will To compile this driver as a module, choose M here: the module will
be called tifm_7xx1. be called tifm_7xx1.
config ACER_WMI
tristate "Acer WMI Laptop Extras (EXPERIMENTAL)"
depends on X86
depends on EXPERIMENTAL
depends on ACPI
depends on ACPI_WMI
depends on LEDS_CLASS
depends on BACKLIGHT_CLASS_DEVICE
---help---
This is a driver for newer Acer (and Wistron) laptops. It adds
wireless radio and bluetooth control, and on some laptops,
exposes the mail LED and LCD backlight.
If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M
here.
config ASUS_LAPTOP config ASUS_LAPTOP
tristate "Asus Laptop Extras (EXPERIMENTAL)" tristate "Asus Laptop Extras (EXPERIMENTAL)"
depends on X86 depends on X86
@ -126,6 +142,15 @@ config FUJITSU_LAPTOP
If you have a Fujitsu laptop, say Y or M here. If you have a Fujitsu laptop, say Y or M here.
config TC1100_WMI
tristate "HP Compaq TC1100 Tablet WMI Extras"
depends on X86 && !X86_64
depends on ACPI
depends on ACPI_WMI
---help---
This is a driver for the WMI extensions (wireless and bluetooth power
control) of the HP Compaq TC1100 tablet.
config MSI_LAPTOP config MSI_LAPTOP
tristate "MSI Laptop Extras" tristate "MSI Laptop Extras"
depends on X86 depends on X86
@ -219,6 +244,25 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here. If you are not sure, say Y here.
config THINKPAD_ACPI_HOTKEY_POLL
bool "Suport NVRAM polling for hot keys"
depends on THINKPAD_ACPI
default y
---help---
Some thinkpad models benefit from NVRAM polling to detect a few of
the hot key press events. If you know your ThinkPad model does not
need to do NVRAM polling to support any of the hot keys you use,
unselecting this option will save about 1kB of memory.
ThinkPads T40 and newer, R52 and newer, and X31 and newer are
unlikely to need NVRAM polling in their latest BIOS versions.
NVRAM polling can detect at most the following keys: ThinkPad/Access
IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute,
Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12).
If you are not sure, say Y here. The driver enables polling only if
it is strictly necessary to do so.
config ATMEL_SSC config ATMEL_SSC
tristate "Device driver for Atmel SSC peripheral" tristate "Device driver for Atmel SSC peripheral"
@ -232,4 +276,13 @@ config ATMEL_SSC
If unsure, say N. If unsure, say N.
config INTEL_MENLOW
tristate "Thermal Management driver for Intel menlow platform"
depends on ACPI_THERMAL
---help---
ACPI thermal management enhancement driver on
Intel Menlow platform.
If unsure, say N.
endif # MISC_DEVICES endif # MISC_DEVICES

View File

@ -6,8 +6,10 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
obj-$(CONFIG_IBM_ASM) += ibmasm/ obj-$(CONFIG_IBM_ASM) += ibmasm/
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/ obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
obj-$(CONFIG_LKDTM) += lkdtm.o obj-$(CONFIG_LKDTM) += lkdtm.o
obj-$(CONFIG_TIFM_CORE) += tifm_core.o obj-$(CONFIG_TIFM_CORE) += tifm_core.o
obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o
@ -17,3 +19,4 @@ obj-$(CONFIG_SONY_LAPTOP) += sony-laptop.o
obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o obj-$(CONFIG_THINKPAD_ACPI) += thinkpad_acpi.o
obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o

1109
drivers/misc/acer-wmi.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -254,7 +254,7 @@ ASUS_LED(gled, "gaming");
* method is searched within the scope of the handle, can be NULL. The output * method is searched within the scope of the handle, can be NULL. The output
* of the method is written is output, which can also be NULL * of the method is written is output, which can also be NULL
* *
* returns 1 if write is successful, 0 else. * returns 0 if write is successful, -1 else.
*/ */
static int write_acpi_int(acpi_handle handle, const char *method, int val, static int write_acpi_int(acpi_handle handle, const char *method, int val,
struct acpi_buffer *output) struct acpi_buffer *output)
@ -263,13 +263,19 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val,
union acpi_object in_obj; //the only param we use union acpi_object in_obj; //the only param we use
acpi_status status; acpi_status status;
if (!handle)
return 0;
params.count = 1; params.count = 1;
params.pointer = &in_obj; params.pointer = &in_obj;
in_obj.type = ACPI_TYPE_INTEGER; in_obj.type = ACPI_TYPE_INTEGER;
in_obj.integer.value = val; in_obj.integer.value = val;
status = acpi_evaluate_object(handle, (char *)method, &params, output); status = acpi_evaluate_object(handle, (char *)method, &params, output);
return (status == AE_OK); if (status == AE_OK)
return 0;
else
return -1;
} }
static int read_wireless_status(int mask) static int read_wireless_status(int mask)
@ -321,7 +327,7 @@ static void write_status(acpi_handle handle, int out, int mask)
switch (mask) { switch (mask) {
case MLED_ON: case MLED_ON:
out = !out & 0x1; out = !(out & 0x1);
break; break;
case GLED_ON: case GLED_ON:
out = (out & 0x1) + 1; out = (out & 0x1) + 1;
@ -335,7 +341,7 @@ static void write_status(acpi_handle handle, int out, int mask)
break; break;
} }
if (handle && !write_acpi_int(handle, NULL, out, NULL)) if (write_acpi_int(handle, NULL, out, NULL))
printk(ASUS_WARNING " write failed %x\n", mask); printk(ASUS_WARNING " write failed %x\n", mask);
} }
@ -415,7 +421,7 @@ static int set_brightness(struct backlight_device *bd, int value)
value = (0 < value) ? ((15 < value) ? 15 : value) : 0; value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
/* 0 <= value <= 15 */ /* 0 <= value <= 15 */
if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) { if (write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
printk(ASUS_WARNING "Error changing brightness\n"); printk(ASUS_WARNING "Error changing brightness\n");
ret = -EIO; ret = -EIO;
} }
@ -545,7 +551,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
rv = parse_arg(buf, count, &value); rv = parse_arg(buf, count, &value);
if (rv > 0) { if (rv > 0) {
if (!write_acpi_int(ledd_set_handle, NULL, value, NULL)) if (write_acpi_int(ledd_set_handle, NULL, value, NULL))
printk(ASUS_WARNING "LED display write failed\n"); printk(ASUS_WARNING "LED display write failed\n");
else else
hotk->ledd_status = (u32) value; hotk->ledd_status = (u32) value;
@ -590,7 +596,7 @@ static ssize_t store_bluetooth(struct device *dev,
static void set_display(int value) static void set_display(int value)
{ {
/* no sanity check needed for now */ /* no sanity check needed for now */
if (!write_acpi_int(display_set_handle, NULL, value, NULL)) if (write_acpi_int(display_set_handle, NULL, value, NULL))
printk(ASUS_WARNING "Error setting display\n"); printk(ASUS_WARNING "Error setting display\n");
return; return;
} }
@ -647,7 +653,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
*/ */
static void set_light_sens_switch(int value) static void set_light_sens_switch(int value)
{ {
if (!write_acpi_int(ls_switch_handle, NULL, value, NULL)) if (write_acpi_int(ls_switch_handle, NULL, value, NULL))
printk(ASUS_WARNING "Error setting light sensor switch\n"); printk(ASUS_WARNING "Error setting light sensor switch\n");
hotk->light_switch = value; hotk->light_switch = value;
} }
@ -672,7 +678,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
static void set_light_sens_level(int value) static void set_light_sens_level(int value)
{ {
if (!write_acpi_int(ls_level_handle, NULL, value, NULL)) if (write_acpi_int(ls_level_handle, NULL, value, NULL))
printk(ASUS_WARNING "Error setting light sensor level\n"); printk(ASUS_WARNING "Error setting light sensor level\n");
hotk->light_level = value; hotk->light_level = value;
} }
@ -860,7 +866,7 @@ static int asus_hotk_get_info(void)
printk(ASUS_WARNING "Couldn't get the DSDT table header\n"); printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
/* We have to write 0 on init this far for all ASUS models */ /* We have to write 0 on init this far for all ASUS models */
if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) { if (write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
printk(ASUS_ERR "Hotkey initialization failed\n"); printk(ASUS_ERR "Hotkey initialization failed\n");
return -ENODEV; return -ENODEV;
} }

526
drivers/misc/intel_menlow.c Normal file
View File

@ -0,0 +1,526 @@
/*
* intel_menlow.c - Intel menlow Driver for thermal management extension
*
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This driver creates the sys I/F for programming the sensors.
* It also implements the driver for intel menlow memory controller (hardware
* id is INT0002) which makes use of the platform specific ACPI methods
* to get/set bandwidth.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
MODULE_AUTHOR("Thomas Sujith");
MODULE_AUTHOR("Zhang Rui");
MODULE_DESCRIPTION("Intel Menlow platform specific driver");
MODULE_LICENSE("GPL");
/*
* Memory controller device control
*/
#define MEMORY_GET_BANDWIDTH "GTHS"
#define MEMORY_SET_BANDWIDTH "STHS"
#define MEMORY_ARG_CUR_BANDWIDTH 1
#define MEMORY_ARG_MAX_BANDWIDTH 0
static int memory_get_int_max_bandwidth(struct thermal_cooling_device *cdev,
unsigned long *max_state)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
unsigned long value;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = MEMORY_ARG_MAX_BANDWIDTH;
status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
&arg_list, &value);
if (ACPI_FAILURE(status))
return -EFAULT;
*max_state = value - 1;
return 0;
}
static int memory_get_max_bandwidth(struct thermal_cooling_device *cdev,
char *buf)
{
unsigned long value;
if (memory_get_int_max_bandwidth(cdev, &value))
return -EINVAL;
return sprintf(buf, "%ld\n", value);
}
static int memory_get_cur_bandwidth(struct thermal_cooling_device *cdev,
char *buf)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
unsigned long value;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status = AE_OK;
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = MEMORY_ARG_CUR_BANDWIDTH;
status = acpi_evaluate_integer(handle, MEMORY_GET_BANDWIDTH,
&arg_list, &value);
if (ACPI_FAILURE(status))
return -EFAULT;
return sprintf(buf, "%ld\n", value);
}
static int memory_set_cur_bandwidth(struct thermal_cooling_device *cdev,
unsigned int state)
{
struct acpi_device *device = cdev->devdata;
acpi_handle handle = device->handle;
struct acpi_object_list arg_list;
union acpi_object arg;
acpi_status status;
int temp;
unsigned long max_state;
if (memory_get_int_max_bandwidth(cdev, &max_state))
return -EFAULT;
if (max_state < 0 || state > max_state)
return -EINVAL;
arg_list.count = 1;
arg_list.pointer = &arg;
arg.type = ACPI_TYPE_INTEGER;
arg.integer.value = state;
status =
acpi_evaluate_integer(handle, MEMORY_SET_BANDWIDTH, &arg_list,
(unsigned long *)&temp);
printk(KERN_INFO
"Bandwidth value was %d: status is %d\n", state, status);
if (ACPI_FAILURE(status))
return -EFAULT;
return 0;
}
static struct thermal_cooling_device_ops memory_cooling_ops = {
.get_max_state = memory_get_max_bandwidth,
.get_cur_state = memory_get_cur_bandwidth,
.set_cur_state = memory_set_cur_bandwidth,
};
/*
* Memory Device Management
*/
static int intel_menlow_memory_add(struct acpi_device *device)
{
int result = -ENODEV;
acpi_status status = AE_OK;
acpi_handle dummy;
struct thermal_cooling_device *cdev;
if (!device)
return -EINVAL;
status = acpi_get_handle(device->handle, MEMORY_GET_BANDWIDTH, &dummy);
if (ACPI_FAILURE(status))
goto end;
status = acpi_get_handle(device->handle, MEMORY_SET_BANDWIDTH, &dummy);
if (ACPI_FAILURE(status))
goto end;
cdev = thermal_cooling_device_register("Memory controller", device,
&memory_cooling_ops);
acpi_driver_data(device) = cdev;
if (!cdev)
result = -ENODEV;
else {
result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, "thermal_cooling");
if (result)
goto unregister;
result = sysfs_create_link(&cdev->device.kobj,
&device->dev.kobj, "device");
if (result) {
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
goto unregister;
}
}
end:
return result;
unregister:
thermal_cooling_device_unregister(cdev);
return result;
}
static int intel_menlow_memory_remove(struct acpi_device *device, int type)
{
struct thermal_cooling_device *cdev = acpi_driver_data(device);
if (!device || !cdev)
return -EINVAL;
sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
sysfs_remove_link(&cdev->device.kobj, "device");
thermal_cooling_device_unregister(cdev);
return 0;
}
const static struct acpi_device_id intel_menlow_memory_ids[] = {
{"INT0002", 0},
{"", 0},
};
static struct acpi_driver intel_menlow_memory_driver = {
.name = "intel_menlow_thermal_control",
.ids = intel_menlow_memory_ids,
.ops = {
.add = intel_menlow_memory_add,
.remove = intel_menlow_memory_remove,
},
};
/*
* Sensor control on menlow platform
*/
#define THERMAL_AUX0 0
#define THERMAL_AUX1 1
#define GET_AUX0 "GAX0"
#define GET_AUX1 "GAX1"
#define SET_AUX0 "SAX0"
#define SET_AUX1 "SAX1"
struct intel_menlow_attribute {
struct device_attribute attr;
struct device *device;
acpi_handle handle;
struct list_head node;
};
static LIST_HEAD(intel_menlow_attr_list);
static DEFINE_MUTEX(intel_menlow_attr_lock);
/*
* sensor_get_auxtrip - get the current auxtrip value from sensor
* @name: Thermalzone name
* @auxtype : AUX0/AUX1
* @buf: syfs buffer
*/
static int sensor_get_auxtrip(acpi_handle handle, int index, int *value)
{
acpi_status status;
if ((index != 0 && index != 1) || !value)
return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX1 : GET_AUX0,
NULL, (unsigned long *)value);
if (ACPI_FAILURE(status))
return -EIO;
return 0;
}
/*
* sensor_set_auxtrip - set the new auxtrip value to sensor
* @name: Thermalzone name
* @auxtype : AUX0/AUX1
* @buf: syfs buffer
*/
static int sensor_set_auxtrip(acpi_handle handle, int index, int value)
{
acpi_status status;
union acpi_object arg = {
ACPI_TYPE_INTEGER
};
struct acpi_object_list args = {
1, &arg
};
int temp;
if (index != 0 && index != 1)
return -EINVAL;
status = acpi_evaluate_integer(handle, index ? GET_AUX0 : GET_AUX1,
NULL, (unsigned long *)&temp);
if (ACPI_FAILURE(status))
return -EIO;
if ((index && value < temp) || (!index && value > temp))
return -EINVAL;
arg.integer.value = value;
status = acpi_evaluate_integer(handle, index ? SET_AUX1 : SET_AUX0,
&args, (unsigned long *)&temp);
if (ACPI_FAILURE(status))
return -EIO;
/* do we need to check the return value of SAX0/SAX1 ? */
return 0;
}
#define to_intel_menlow_attr(_attr) \
container_of(_attr, struct intel_menlow_attribute, attr)
static ssize_t aux0_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
int value;
int result;
result = sensor_get_auxtrip(attr->handle, 0, &value);
return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
}
static ssize_t aux1_show(struct device *dev,
struct device_attribute *dev_attr, char *buf)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
int value;
int result;
result = sensor_get_auxtrip(attr->handle, 1, &value);
return result ? result : sprintf(buf, "%lu", KELVIN_TO_CELSIUS(value));
}
static ssize_t aux0_store(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
int value;
int result;
/*Sanity check; should be a positive integer */
if (!sscanf(buf, "%d", &value))
return -EINVAL;
if (value < 0)
return -EINVAL;
result = sensor_set_auxtrip(attr->handle, 0, CELSIUS_TO_KELVIN(value));
return result ? result : count;
}
static ssize_t aux1_store(struct device *dev,
struct device_attribute *dev_attr,
const char *buf, size_t count)
{
struct intel_menlow_attribute *attr = to_intel_menlow_attr(dev_attr);
int value;
int result;
/*Sanity check; should be a positive integer */
if (!sscanf(buf, "%d", &value))
return -EINVAL;
if (value < 0)
return -EINVAL;
result = sensor_set_auxtrip(attr->handle, 1, CELSIUS_TO_KELVIN(value));
return result ? result : count;
}
/* BIOS can enable/disable the thermal user application in dabney platform */
#define BIOS_ENABLED "\\_TZ.GSTS"
static ssize_t bios_enabled_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
acpi_status status;
unsigned long bios_enabled;
status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &bios_enabled);
if (ACPI_FAILURE(status))
return -ENODEV;
return sprintf(buf, "%s\n", bios_enabled ? "enabled" : "disabled");
}
static int intel_menlow_add_one_attribute(char *name, int mode, void *show,
void *store, struct device *dev,
acpi_handle handle)
{
struct intel_menlow_attribute *attr;
int result;
attr = kzalloc(sizeof(struct intel_menlow_attribute), GFP_KERNEL);
if (!attr)
return -ENOMEM;
attr->attr.attr.name = name;
attr->attr.attr.mode = mode;
attr->attr.show = show;
attr->attr.store = store;
attr->device = dev;
attr->handle = handle;
result = device_create_file(dev, &attr->attr);
if (result)
return result;
mutex_lock(&intel_menlow_attr_lock);
list_add_tail(&attr->node, &intel_menlow_attr_list);
mutex_unlock(&intel_menlow_attr_lock);
return 0;
}
static acpi_status intel_menlow_register_sensor(acpi_handle handle, u32 lvl,
void *context, void **rv)
{
acpi_status status;
acpi_handle dummy;
struct thermal_zone_device *thermal;
int result;
result = acpi_bus_get_private_data(handle, (void **)&thermal);
if (result)
return 0;
/* _TZ must have the AUX0/1 methods */
status = acpi_get_handle(handle, GET_AUX0, &dummy);
if (ACPI_FAILURE(status))
goto not_found;
status = acpi_get_handle(handle, SET_AUX0, &dummy);
if (ACPI_FAILURE(status))
goto not_found;
result = intel_menlow_add_one_attribute("aux0", 0644,
aux0_show, aux0_store,
&thermal->device, handle);
if (result)
return AE_ERROR;
status = acpi_get_handle(handle, GET_AUX1, &dummy);
if (ACPI_FAILURE(status))
goto not_found;
status = acpi_get_handle(handle, SET_AUX1, &dummy);
if (ACPI_FAILURE(status))
goto not_found;
result = intel_menlow_add_one_attribute("aux1", 0644,
aux1_show, aux1_store,
&thermal->device, handle);
if (result)
return AE_ERROR;
/*
* create the "dabney_enabled" attribute which means the user app
* should be loaded or not
*/
result = intel_menlow_add_one_attribute("bios_enabled", 0444,
bios_enabled_show, NULL,
&thermal->device, handle);
if (result)
return AE_ERROR;
not_found:
if (status == AE_NOT_FOUND)
return AE_OK;
else
return status;
}
static void intel_menlow_unregister_sensor(void)
{
struct intel_menlow_attribute *pos, *next;
mutex_lock(&intel_menlow_attr_lock);
list_for_each_entry_safe(pos, next, &intel_menlow_attr_list, node) {
list_del(&pos->node);
device_remove_file(pos->device, &pos->attr);
kfree(pos);
}
mutex_unlock(&intel_menlow_attr_lock);
return;
}
static int __init intel_menlow_module_init(void)
{
int result = -ENODEV;
acpi_status status;
unsigned long enable;
if (acpi_disabled)
return result;
/* Looking for the \_TZ.GSTS method */
status = acpi_evaluate_integer(NULL, BIOS_ENABLED, NULL, &enable);
if (ACPI_FAILURE(status) || !enable)
return -ENODEV;
/* Looking for ACPI device MEM0 with hardware id INT0002 */
result = acpi_bus_register_driver(&intel_menlow_memory_driver);
if (result)
return result;
/* Looking for sensors in each ACPI thermal zone */
status = acpi_walk_namespace(ACPI_TYPE_THERMAL, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX,
intel_menlow_register_sensor, NULL, NULL);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
}
static void __exit intel_menlow_module_exit(void)
{
acpi_bus_unregister_driver(&intel_menlow_memory_driver);
intel_menlow_unregister_sensor();
}
module_init(intel_menlow_module_init);
module_exit(intel_menlow_module_exit);

View File

@ -73,7 +73,7 @@
if (debug) printk(KERN_WARNING DRV_PFX msg); \ if (debug) printk(KERN_WARNING DRV_PFX msg); \
} while (0) } while (0)
#define SONY_LAPTOP_DRIVER_VERSION "0.5" #define SONY_LAPTOP_DRIVER_VERSION "0.6"
#define SONY_NC_CLASS "sony-nc" #define SONY_NC_CLASS "sony-nc"
#define SONY_NC_HID "SNY5001" #define SONY_NC_HID "SNY5001"
@ -146,68 +146,70 @@ struct sony_laptop_keypress {
* and input layer indexes in the keymap * and input layer indexes in the keymap
*/ */
static int sony_laptop_input_index[] = { static int sony_laptop_input_index[] = {
-1, /* no event */ -1, /* 0 no event */
-1, /* SONYPI_EVENT_JOGDIAL_DOWN */ -1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */
-1, /* SONYPI_EVENT_JOGDIAL_UP */ -1, /* 2 SONYPI_EVENT_JOGDIAL_UP */
-1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */ -1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
-1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */ -1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
-1, /* SONYPI_EVENT_JOGDIAL_PRESSED */ -1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */
-1, /* SONYPI_EVENT_JOGDIAL_RELEASED */ -1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */
0, /* SONYPI_EVENT_CAPTURE_PRESSED */ 0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */
1, /* SONYPI_EVENT_CAPTURE_RELEASED */ 1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */
2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */ 2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */ 3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
4, /* SONYPI_EVENT_FNKEY_ESC */ 4, /* 11 SONYPI_EVENT_FNKEY_ESC */
5, /* SONYPI_EVENT_FNKEY_F1 */ 5, /* 12 SONYPI_EVENT_FNKEY_F1 */
6, /* SONYPI_EVENT_FNKEY_F2 */ 6, /* 13 SONYPI_EVENT_FNKEY_F2 */
7, /* SONYPI_EVENT_FNKEY_F3 */ 7, /* 14 SONYPI_EVENT_FNKEY_F3 */
8, /* SONYPI_EVENT_FNKEY_F4 */ 8, /* 15 SONYPI_EVENT_FNKEY_F4 */
9, /* SONYPI_EVENT_FNKEY_F5 */ 9, /* 16 SONYPI_EVENT_FNKEY_F5 */
10, /* SONYPI_EVENT_FNKEY_F6 */ 10, /* 17 SONYPI_EVENT_FNKEY_F6 */
11, /* SONYPI_EVENT_FNKEY_F7 */ 11, /* 18 SONYPI_EVENT_FNKEY_F7 */
12, /* SONYPI_EVENT_FNKEY_F8 */ 12, /* 19 SONYPI_EVENT_FNKEY_F8 */
13, /* SONYPI_EVENT_FNKEY_F9 */ 13, /* 20 SONYPI_EVENT_FNKEY_F9 */
14, /* SONYPI_EVENT_FNKEY_F10 */ 14, /* 21 SONYPI_EVENT_FNKEY_F10 */
15, /* SONYPI_EVENT_FNKEY_F11 */ 15, /* 22 SONYPI_EVENT_FNKEY_F11 */
16, /* SONYPI_EVENT_FNKEY_F12 */ 16, /* 23 SONYPI_EVENT_FNKEY_F12 */
17, /* SONYPI_EVENT_FNKEY_1 */ 17, /* 24 SONYPI_EVENT_FNKEY_1 */
18, /* SONYPI_EVENT_FNKEY_2 */ 18, /* 25 SONYPI_EVENT_FNKEY_2 */
19, /* SONYPI_EVENT_FNKEY_D */ 19, /* 26 SONYPI_EVENT_FNKEY_D */
20, /* SONYPI_EVENT_FNKEY_E */ 20, /* 27 SONYPI_EVENT_FNKEY_E */
21, /* SONYPI_EVENT_FNKEY_F */ 21, /* 28 SONYPI_EVENT_FNKEY_F */
22, /* SONYPI_EVENT_FNKEY_S */ 22, /* 29 SONYPI_EVENT_FNKEY_S */
23, /* SONYPI_EVENT_FNKEY_B */ 23, /* 30 SONYPI_EVENT_FNKEY_B */
24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */ 24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
25, /* SONYPI_EVENT_PKEY_P1 */ 25, /* 32 SONYPI_EVENT_PKEY_P1 */
26, /* SONYPI_EVENT_PKEY_P2 */ 26, /* 33 SONYPI_EVENT_PKEY_P2 */
27, /* SONYPI_EVENT_PKEY_P3 */ 27, /* 34 SONYPI_EVENT_PKEY_P3 */
28, /* SONYPI_EVENT_BACK_PRESSED */ 28, /* 35 SONYPI_EVENT_BACK_PRESSED */
-1, /* SONYPI_EVENT_LID_CLOSED */ -1, /* 36 SONYPI_EVENT_LID_CLOSED */
-1, /* SONYPI_EVENT_LID_OPENED */ -1, /* 37 SONYPI_EVENT_LID_OPENED */
29, /* SONYPI_EVENT_BLUETOOTH_ON */ 29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */
30, /* SONYPI_EVENT_BLUETOOTH_OFF */ 30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
31, /* SONYPI_EVENT_HELP_PRESSED */ 31, /* 40 SONYPI_EVENT_HELP_PRESSED */
32, /* SONYPI_EVENT_FNKEY_ONLY */ 32, /* 41 SONYPI_EVENT_FNKEY_ONLY */
33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */ 33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */ 34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */ 35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */ 36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */ 37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */ 38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */ 39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */ 40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
41, /* SONYPI_EVENT_ZOOM_PRESSED */ 41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */
42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */ 42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
43, /* SONYPI_EVENT_MEYE_FACE */ 43, /* 52 SONYPI_EVENT_MEYE_FACE */
44, /* SONYPI_EVENT_MEYE_OPPOSITE */ 44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */ 45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */ 46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
-1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */ -1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
-1, /* SONYPI_EVENT_BATTERY_INSERT */ -1, /* 57 SONYPI_EVENT_BATTERY_INSERT */
-1, /* SONYPI_EVENT_BATTERY_REMOVE */ -1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */
-1, /* SONYPI_EVENT_FNKEY_RELEASED */ -1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */
47, /* SONYPI_EVENT_WIRELESS_ON */ 47, /* 60 SONYPI_EVENT_WIRELESS_ON */
48, /* SONYPI_EVENT_WIRELESS_OFF */ 48, /* 61 SONYPI_EVENT_WIRELESS_OFF */
49, /* 62 SONYPI_EVENT_ZOOM_IN_PRESSED */
50, /* 63 SONYPI_EVENT_ZOOM_OUT_PRESSED */
}; };
static int sony_laptop_input_keycode_map[] = { static int sony_laptop_input_keycode_map[] = {
@ -260,6 +262,8 @@ static int sony_laptop_input_keycode_map[] = {
KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */ KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */ KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */ KEY_WLAN, /* 48 SONYPI_EVENT_WIRELESS_OFF */
KEY_ZOOMIN, /* 49 SONYPI_EVENT_ZOOM_IN_PRESSED */
KEY_ZOOMOUT /* 50 SONYPI_EVENT_ZOOM_OUT_PRESSED */
}; };
/* release buttons after a short delay if pressed */ /* release buttons after a short delay if pressed */
@ -311,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event)
break; break;
default: default:
if (event > ARRAY_SIZE (sony_laptop_input_keycode_map)) { if (event > ARRAY_SIZE(sony_laptop_input_index)) {
dprintk("sony_laptop_report_input_event, event not known: %d\n", event); dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
break; break;
} }
@ -875,6 +879,15 @@ static const struct dmi_system_id sony_nc_ids[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"),
}, },
}, },
{
.ident = "Sony Vaio N 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-N"),
},
},
{ } { }
}; };
@ -1169,10 +1182,12 @@ static struct acpi_driver sony_nc_driver = {
#define SONYPI_DEVICE_TYPE1 0x00000001 #define SONYPI_DEVICE_TYPE1 0x00000001
#define SONYPI_DEVICE_TYPE2 0x00000002 #define SONYPI_DEVICE_TYPE2 0x00000002
#define SONYPI_DEVICE_TYPE3 0x00000004 #define SONYPI_DEVICE_TYPE3 0x00000004
#define SONYPI_DEVICE_TYPE4 0x00000008
#define SONYPI_TYPE1_OFFSET 0x04 #define SONYPI_TYPE1_OFFSET 0x04
#define SONYPI_TYPE2_OFFSET 0x12 #define SONYPI_TYPE2_OFFSET 0x12
#define SONYPI_TYPE3_OFFSET 0x12 #define SONYPI_TYPE3_OFFSET 0x12
#define SONYPI_TYPE4_OFFSET 0x12
struct sony_pic_ioport { struct sony_pic_ioport {
struct acpi_resource_io io1; struct acpi_resource_io io1;
@ -1185,18 +1200,33 @@ struct sony_pic_irq {
struct list_head list; struct list_head list;
}; };
struct sonypi_eventtypes {
u8 data;
unsigned long mask;
struct sonypi_event *events;
};
struct device_ctrl {
int model;
int (*handle_irq)(const u8, const u8);
u16 evport_offset;
u8 has_camera;
u8 has_bluetooth;
u8 has_wwan;
struct sonypi_eventtypes *event_types;
};
struct sony_pic_dev { struct sony_pic_dev {
int model; struct device_ctrl *control;
u16 evport_offset;
u8 camera_power;
u8 bluetooth_power;
u8 wwan_power;
struct acpi_device *acpi_dev; struct acpi_device *acpi_dev;
struct sony_pic_irq *cur_irq; struct sony_pic_irq *cur_irq;
struct sony_pic_ioport *cur_ioport; struct sony_pic_ioport *cur_ioport;
struct list_head interrupts; struct list_head interrupts;
struct list_head ioports; struct list_head ioports;
struct mutex lock; struct mutex lock;
u8 camera_power;
u8 bluetooth_power;
u8 wwan_power;
}; };
static struct sony_pic_dev spic_dev = { static struct sony_pic_dev spic_dev = {
@ -1253,6 +1283,7 @@ static struct sonypi_event sonypi_joggerev[] = {
static struct sonypi_event sonypi_captureev[] = { static struct sonypi_event sonypi_captureev[] = {
{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED }, { 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED }, { 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
{ 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED }, { 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
{ 0, 0 } { 0, 0 }
}; };
@ -1289,7 +1320,6 @@ static struct sonypi_event sonypi_pkeyev[] = {
{ 0x01, SONYPI_EVENT_PKEY_P1 }, { 0x01, SONYPI_EVENT_PKEY_P1 },
{ 0x02, SONYPI_EVENT_PKEY_P2 }, { 0x02, SONYPI_EVENT_PKEY_P2 },
{ 0x04, SONYPI_EVENT_PKEY_P3 }, { 0x04, SONYPI_EVENT_PKEY_P3 },
{ 0x5c, SONYPI_EVENT_PKEY_P1 },
{ 0, 0 } { 0, 0 }
}; };
@ -1331,6 +1361,8 @@ static struct sonypi_event sonypi_lidev[] = {
/* The set of possible zoom events */ /* The set of possible zoom events */
static struct sonypi_event sonypi_zoomev[] = { static struct sonypi_event sonypi_zoomev[] = {
{ 0x39, SONYPI_EVENT_ZOOM_PRESSED }, { 0x39, SONYPI_EVENT_ZOOM_PRESSED },
{ 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
{ 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
{ 0, 0 } { 0, 0 }
}; };
@ -1361,76 +1393,58 @@ static struct sonypi_event sonypi_batteryev[] = {
{ 0, 0 } { 0, 0 }
}; };
static struct sonypi_eventtypes { static struct sonypi_eventtypes type1_events[] = {
int model; { 0, 0xffffffff, sonypi_releaseev },
u8 data; { 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
unsigned long mask; { 0x30, SONYPI_LID_MASK, sonypi_lidev },
struct sonypi_event * events; { 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
} sony_pic_eventtypes[] = { { 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
{ SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev }, { 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
{ SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev }, { 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev }, { 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev }, { 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
{ SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev }, { 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
{ SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, { 0 },
{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, };
{ SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev }, static struct sonypi_eventtypes type2_events[] = {
{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, { 0, 0xffffffff, sonypi_releaseev },
{ SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev }, { 0x38, SONYPI_LID_MASK, sonypi_lidev },
{ 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
{ SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev }, { 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
{ SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev }, { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
{ SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev }, { 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
{ SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev }, { 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, { 0x11, SONYPI_BACK_MASK, sonypi_backev },
{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev }, { 0x21, SONYPI_HELP_MASK, sonypi_helpev },
{ SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev }, { 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
{ SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev }, { 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev }, { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev }, { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
{ SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev }, { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, { 0 },
{ SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, };
{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, static struct sonypi_eventtypes type3_events[] = {
{ 0, 0xffffffff, sonypi_releaseev },
{ SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev }, { 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
{ SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev }, { 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev }, { 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev }, { 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
{ SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev }, { 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev }, { 0 },
{ 0 } };
static struct sonypi_eventtypes type4_events[] = {
{ 0, 0xffffffff, sonypi_releaseev },
{ 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
{ 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
{ 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
{ 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
{ 0x05, SONYPI_PKEY_MASK, sonypi_pkeyev },
{ 0x05, SONYPI_ZOOM_MASK, sonypi_zoomev },
{ 0x05, SONYPI_CAPTURE_MASK, sonypi_captureev },
{ 0 },
}; };
static int sony_pic_detect_device_type(void) /* low level spic calls */
{
struct pci_dev *pcidev;
int model = 0;
if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3, NULL)))
model = SONYPI_DEVICE_TYPE1;
else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_ICH6_1, NULL)))
model = SONYPI_DEVICE_TYPE3;
else if ((pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_ICH7_1, NULL)))
model = SONYPI_DEVICE_TYPE3;
else
model = SONYPI_DEVICE_TYPE2;
if (pcidev)
pci_dev_put(pcidev);
printk(KERN_INFO DRV_PFX "detected Type%d model\n",
model == SONYPI_DEVICE_TYPE1 ? 1 :
model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
return model;
}
#define ITERATIONS_LONG 10000 #define ITERATIONS_LONG 10000
#define ITERATIONS_SHORT 10 #define ITERATIONS_SHORT 10
#define wait_on_command(command, iterations) { \ #define wait_on_command(command, iterations) { \
@ -1451,7 +1465,7 @@ static u8 sony_pic_call1(u8 dev)
outb(dev, spic_dev.cur_ioport->io1.minimum + 4); outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4); v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
v2 = inb_p(spic_dev.cur_ioport->io1.minimum); v2 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call1: 0x%.4x\n", (v2 << 8) | v1); dprintk("sony_pic_call1(0x%.2x): 0x%.4x\n", dev, (v2 << 8) | v1);
return v2; return v2;
} }
@ -1466,7 +1480,7 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
ITERATIONS_LONG); ITERATIONS_LONG);
outb(fn, spic_dev.cur_ioport->io1.minimum); outb(fn, spic_dev.cur_ioport->io1.minimum);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum); v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call2: 0x%.4x\n", v1); dprintk("sony_pic_call2(0x%.2x - 0x%.2x): 0x%.4x\n", dev, fn, v1);
return v1; return v1;
} }
@ -1481,10 +1495,105 @@ static u8 sony_pic_call3(u8 dev, u8 fn, u8 v)
wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG); wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
outb(v, spic_dev.cur_ioport->io1.minimum); outb(v, spic_dev.cur_ioport->io1.minimum);
v1 = inb_p(spic_dev.cur_ioport->io1.minimum); v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
dprintk("sony_pic_call3: 0x%.4x\n", v1); dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
dev, fn, v, v1);
return v1; return v1;
} }
/*
* minidrivers for SPIC models
*/
static int type4_handle_irq(const u8 data_mask, const u8 ev)
{
/*
* 0x31 could mean we have to take some extra action and wait for
* the next irq for some Type4 models, it will generate a new
* irq and we can read new data from the device:
* - 0x5c and 0x5f requires 0xA0
* - 0x61 requires 0xB3
*/
if (data_mask == 0x31) {
if (ev == 0x5c || ev == 0x5f)
sony_pic_call1(0xA0);
else if (ev == 0x61)
sony_pic_call1(0xB3);
return 0;
}
return 1;
}
static struct device_ctrl spic_types[] = {
{
.model = SONYPI_DEVICE_TYPE1,
.handle_irq = NULL,
.evport_offset = SONYPI_TYPE1_OFFSET,
.event_types = type1_events,
},
{
.model = SONYPI_DEVICE_TYPE2,
.handle_irq = NULL,
.evport_offset = SONYPI_TYPE2_OFFSET,
.event_types = type2_events,
},
{
.model = SONYPI_DEVICE_TYPE3,
.handle_irq = NULL,
.evport_offset = SONYPI_TYPE3_OFFSET,
.event_types = type3_events,
},
{
.model = SONYPI_DEVICE_TYPE4,
.handle_irq = type4_handle_irq,
.evport_offset = SONYPI_TYPE4_OFFSET,
.event_types = type4_events,
},
};
static void sony_pic_detect_device_type(struct sony_pic_dev *dev)
{
struct pci_dev *pcidev;
pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3, NULL);
if (pcidev) {
dev->control = &spic_types[0];
goto out;
}
pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_ICH6_1, NULL);
if (pcidev) {
dev->control = &spic_types[2];
goto out;
}
pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_ICH7_1, NULL);
if (pcidev) {
dev->control = &spic_types[3];
goto out;
}
pcidev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_ICH8_4, NULL);
if (pcidev) {
dev->control = &spic_types[3];
goto out;
}
/* default */
dev->control = &spic_types[1];
out:
if (pcidev)
pci_dev_put(pcidev);
printk(KERN_INFO DRV_PFX "detected Type%d model\n",
dev->control->model == SONYPI_DEVICE_TYPE1 ? 1 :
dev->control->model == SONYPI_DEVICE_TYPE2 ? 2 :
dev->control->model == SONYPI_DEVICE_TYPE3 ? 3 : 4);
}
/* camera tests and poweron/poweroff */ /* camera tests and poweron/poweroff */
#define SONYPI_CAMERA_PICTURE 5 #define SONYPI_CAMERA_PICTURE 5
#define SONYPI_CAMERA_CONTROL 0x10 #define SONYPI_CAMERA_CONTROL 0x10
@ -2253,7 +2362,7 @@ static int sony_pic_enable(struct acpi_device *device,
buffer.pointer = resource; buffer.pointer = resource;
/* setup Type 1 resources */ /* setup Type 1 resources */
if (spic_dev.model == SONYPI_DEVICE_TYPE1) { if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
/* setup io resources */ /* setup io resources */
resource->res1.type = ACPI_RESOURCE_TYPE_IO; resource->res1.type = ACPI_RESOURCE_TYPE_IO;
@ -2335,39 +2444,49 @@ static irqreturn_t sony_pic_irq(int irq, void *dev_id)
if (dev->cur_ioport->io2.minimum) if (dev->cur_ioport->io2.minimum)
data_mask = inb_p(dev->cur_ioport->io2.minimum); data_mask = inb_p(dev->cur_ioport->io2.minimum);
else else
data_mask = inb_p(dev->cur_ioport->io1.minimum + dev->evport_offset); data_mask = inb_p(dev->cur_ioport->io1.minimum +
dev->control->evport_offset);
dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n", dprintk("event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
ev, data_mask, dev->cur_ioport->io1.minimum, dev->evport_offset); ev, data_mask, dev->cur_ioport->io1.minimum,
dev->control->evport_offset);
if (ev == 0x00 || ev == 0xff) if (ev == 0x00 || ev == 0xff)
return IRQ_HANDLED; return IRQ_HANDLED;
for (i = 0; sony_pic_eventtypes[i].model; i++) { for (i = 0; dev->control->event_types[i].mask; i++) {
if (spic_dev.model != sony_pic_eventtypes[i].model) if ((data_mask & dev->control->event_types[i].data) !=
dev->control->event_types[i].data)
continue; continue;
if ((data_mask & sony_pic_eventtypes[i].data) != if (!(mask & dev->control->event_types[i].mask))
sony_pic_eventtypes[i].data)
continue; continue;
if (!(mask & sony_pic_eventtypes[i].mask)) for (j = 0; dev->control->event_types[i].events[j].event; j++) {
continue; if (ev == dev->control->event_types[i].events[j].data) {
for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
if (ev == sony_pic_eventtypes[i].events[j].data) {
device_event = device_event =
sony_pic_eventtypes[i].events[j].event; dev->control->
event_types[i].events[j].event;
goto found; goto found;
} }
} }
} }
/* Still not able to decode the event try to pass
* it over to the minidriver
*/
if (dev->control->handle_irq &&
dev->control->handle_irq(data_mask, ev) == 0)
return IRQ_HANDLED;
dprintk("unknown event ([%.2x] [%.2x]) at port 0x%.4x(+0x%.2x)\n",
ev, data_mask, dev->cur_ioport->io1.minimum,
dev->control->evport_offset);
return IRQ_HANDLED; return IRQ_HANDLED;
found: found:
sony_laptop_report_input_event(device_event); sony_laptop_report_input_event(device_event);
acpi_bus_generate_proc_event(spic_dev.acpi_dev, 1, device_event); acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
sonypi_compat_report_event(device_event); sonypi_compat_report_event(device_event);
return IRQ_HANDLED; return IRQ_HANDLED;
@ -2429,23 +2548,9 @@ static int sony_pic_add(struct acpi_device *device)
spic_dev.acpi_dev = device; spic_dev.acpi_dev = device;
strcpy(acpi_device_class(device), "sony/hotkey"); strcpy(acpi_device_class(device), "sony/hotkey");
spic_dev.model = sony_pic_detect_device_type(); sony_pic_detect_device_type(&spic_dev);
mutex_init(&spic_dev.lock); 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 */ /* read _PRS resources */
result = sony_pic_possible_resources(device); result = sony_pic_possible_resources(device);
if (result) { if (result) {

290
drivers/misc/tc1100-wmi.c Normal file
View File

@ -0,0 +1,290 @@
/*
* HP Compaq TC1100 Tablet WMI Extras Driver
*
* Copyright (C) 2007 Carlos Corbacho <carlos@strangeworlds.co.uk>
* Copyright (C) 2004 Jamey Hicks <jamey.hicks@hp.com>
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <acpi/acpi.h>
#include <acpi/actypes.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include <linux/platform_device.h>
#define GUID "C364AC71-36DB-495A-8494-B439D472A505"
#define TC1100_INSTANCE_WIRELESS 1
#define TC1100_INSTANCE_JOGDIAL 2
#define TC1100_LOGPREFIX "tc1100-wmi: "
#define TC1100_INFO KERN_INFO TC1100_LOGPREFIX
MODULE_AUTHOR("Jamey Hicks, Carlos Corbacho");
MODULE_DESCRIPTION("HP Compaq TC1100 Tablet WMI Extras");
MODULE_LICENSE("GPL");
MODULE_ALIAS("wmi:C364AC71-36DB-495A-8494-B439D472A505");
static int tc1100_probe(struct platform_device *device);
static int tc1100_remove(struct platform_device *device);
static int tc1100_suspend(struct platform_device *device, pm_message_t state);
static int tc1100_resume(struct platform_device *device);
static struct platform_driver tc1100_driver = {
.driver = {
.name = "tc1100-wmi",
.owner = THIS_MODULE,
},
.probe = tc1100_probe,
.remove = tc1100_remove,
.suspend = tc1100_suspend,
.resume = tc1100_resume,
};
static struct platform_device *tc1100_device;
struct tc1100_data {
u32 wireless;
u32 jogdial;
};
static struct tc1100_data suspend_data;
/* --------------------------------------------------------------------------
Device Management
-------------------------------------------------------------------------- */
static int get_state(u32 *out, u8 instance)
{
u32 tmp;
acpi_status status;
struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj;
if (!out)
return -EINVAL;
if (instance > 2)
return -ENODEV;
status = wmi_query_block(GUID, instance, &result);
if (ACPI_FAILURE(status))
return -ENODEV;
obj = (union acpi_object *) result.pointer;
if (obj && obj->type == ACPI_TYPE_BUFFER &&
obj->buffer.length == sizeof(u32)) {
tmp = *((u32 *) obj->buffer.pointer);
} else {
tmp = 0;
}
if (result.length > 0 && result.pointer)
kfree(result.pointer);
switch (instance) {
case TC1100_INSTANCE_WIRELESS:
*out = (tmp == 3) ? 1 : 0;
return 0;
case TC1100_INSTANCE_JOGDIAL:
*out = (tmp == 1) ? 1 : 0;
return 0;
default:
return -ENODEV;
}
}
static int set_state(u32 *in, u8 instance)
{
u32 value;
acpi_status status;
struct acpi_buffer input;
if (!in)
return -EINVAL;
if (instance > 2)
return -ENODEV;
switch (instance) {
case TC1100_INSTANCE_WIRELESS:
value = (*in) ? 1 : 2;
break;
case TC1100_INSTANCE_JOGDIAL:
value = (*in) ? 0 : 1;
break;
default:
return -ENODEV;
}
input.length = sizeof(u32);
input.pointer = &value;
status = wmi_set_block(GUID, instance, &input);
if (ACPI_FAILURE(status))
return -ENODEV;
return 0;
}
/* --------------------------------------------------------------------------
FS Interface (/sys)
-------------------------------------------------------------------------- */
/*
* Read/ write bool sysfs macro
*/
#define show_set_bool(value, instance) \
static ssize_t \
show_bool_##value(struct device *dev, struct device_attribute *attr, \
char *buf) \
{ \
u32 result; \
acpi_status status = get_state(&result, instance); \
if (ACPI_SUCCESS(status)) \
return sprintf(buf, "%d\n", result); \
return sprintf(buf, "Read error\n"); \
} \
\
static ssize_t \
set_bool_##value(struct device *dev, struct device_attribute *attr, \
const char *buf, size_t count) \
{ \
u32 tmp = simple_strtoul(buf, NULL, 10); \
acpi_status status = set_state(&tmp, instance); \
if (ACPI_FAILURE(status)) \
return -EINVAL; \
return count; \
} \
static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
show_bool_##value, set_bool_##value);
show_set_bool(wireless, TC1100_INSTANCE_WIRELESS);
show_set_bool(jogdial, TC1100_INSTANCE_JOGDIAL);
static void remove_fs(void)
{
device_remove_file(&tc1100_device->dev, &dev_attr_wireless);
device_remove_file(&tc1100_device->dev, &dev_attr_jogdial);
}
static int add_fs(void)
{
int ret;
ret = device_create_file(&tc1100_device->dev, &dev_attr_wireless);
if (ret)
goto add_sysfs_error;
ret = device_create_file(&tc1100_device->dev, &dev_attr_jogdial);
if (ret)
goto add_sysfs_error;
return ret;
add_sysfs_error:
remove_fs();
return ret;
}
/* --------------------------------------------------------------------------
Driver Model
-------------------------------------------------------------------------- */
static int tc1100_probe(struct platform_device *device)
{
int result = 0;
result = add_fs();
return result;
}
static int tc1100_remove(struct platform_device *device)
{
remove_fs();
return 0;
}
static int tc1100_suspend(struct platform_device *dev, pm_message_t state)
{
int ret;
ret = get_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
if (ret)
return ret;
ret = get_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
if (ret)
return ret;
return ret;
}
static int tc1100_resume(struct platform_device *dev)
{
int ret;
ret = set_state(&suspend_data.wireless, TC1100_INSTANCE_WIRELESS);
if (ret)
return ret;
ret = set_state(&suspend_data.jogdial, TC1100_INSTANCE_JOGDIAL);
if (ret)
return ret;
return ret;
}
static int __init tc1100_init(void)
{
int result = 0;
if (!wmi_has_guid(GUID))
return -ENODEV;
result = platform_driver_register(&tc1100_driver);
if (result)
return result;
tc1100_device = platform_device_alloc("tc1100-wmi", -1);
platform_device_add(tc1100_device);
printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras loaded\n");
return result;
}
static void __exit tc1100_exit(void)
{
platform_device_del(tc1100_device);
platform_driver_unregister(&tc1100_driver);
printk(TC1100_INFO "HP Compaq TC1100 Tablet WMI Extras unloaded\n");
}
module_init(tc1100_init);
module_exit(tc1100_exit);

File diff suppressed because it is too large Load Diff

View File

@ -1,606 +0,0 @@
/*
* thinkpad_acpi.h - ThinkPad ACPI Extras
*
*
* Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net>
* Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*/
#ifndef __THINKPAD_ACPI_H__
#define __THINKPAD_ACPI_H__
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/string.h>
#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>
#include <linux/fb.h>
#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>
#include <linux/jiffies.h>
#include <linux/workqueue.h>
#include <acpi/acpi_drivers.h>
#include <acpi/acnamesp.h>
#include <linux/pci_ids.h>
/****************************************************************************
* Main driver
*/
#define IBM_NAME "thinkpad"
#define IBM_DESC "ThinkPad ACPI Extras"
#define IBM_FILE IBM_NAME "_acpi"
#define IBM_URL "http://ibm-acpi.sf.net/"
#define IBM_MAIL "ibm-acpi-devel@lists.sourceforge.net"
#define IBM_PROC_DIR "ibm"
#define IBM_ACPI_EVENT_PREFIX "ibm"
#define IBM_DRVR_NAME IBM_FILE
#define IBM_HWMON_DRVR_NAME IBM_NAME "_hwmon"
#define IBM_LOG IBM_FILE ": "
#define IBM_ERR KERN_ERR IBM_LOG
#define IBM_NOTICE KERN_NOTICE IBM_LOG
#define IBM_INFO KERN_INFO IBM_LOG
#define IBM_DEBUG KERN_DEBUG IBM_LOG
#define IBM_MAX_ACPI_ARGS 3
/* ThinkPad CMOS commands */
#define TP_CMOS_VOLUME_DOWN 0
#define TP_CMOS_VOLUME_UP 1
#define TP_CMOS_VOLUME_MUTE 2
#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 0x0f
#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)))
/* Debugging */
#define TPACPI_DBG_ALL 0xffff
#define TPACPI_DBG_ALL 0xffff
#define TPACPI_DBG_INIT 0x0001
#define TPACPI_DBG_EXIT 0x0002
#define dbg_printk(a_dbg_level, format, arg...) \
do { if (dbg_level & a_dbg_level) \
printk(IBM_DEBUG "%s: " format, __func__ , ## arg); } while (0)
#ifdef CONFIG_THINKPAD_ACPI_DEBUG
#define vdbg_printk(a_dbg_level, format, arg...) \
dbg_printk(a_dbg_level, format, ## arg)
static const char *str_supported(int is_supported);
#else
#define vdbg_printk(a_dbg_level, format, arg...)
#endif
/* 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"
/* ACPI helpers */
static int __must_check acpi_evalf(acpi_handle handle,
void *res, char *method, char *fmt, ...);
static int __must_check acpi_ec_read(int i, u8 * p);
static int __must_check acpi_ec_write(int i, u8 v);
static int __must_check _sta(acpi_handle handle);
/* ACPI handles */
static acpi_handle root_handle; /* root namespace */
static acpi_handle ec_handle; /* EC */
static acpi_handle ecrd_handle, ecwr_handle; /* 570 EC access */
static acpi_handle cmos_handle, hkey_handle; /* basic thinkpad handles */
static void drv_acpi_handle_init(char *name,
acpi_handle *handle, acpi_handle parent,
char **paths, int num_paths, char **path);
#define IBM_ACPIHANDLE_INIT(object) \
drv_acpi_handle_init(#object, &object##_handle, *object##_parent, \
object##_paths, ARRAY_SIZE(object##_paths), &object##_path)
/* ThinkPad ACPI helpers */
static int issue_thinkpad_cmos_command(int cmos_cmd);
/* procfs support */
static struct proc_dir_entry *proc_dir;
/* procfs helpers */
static int dispatch_procfs_read(char *page, char **start, off_t off,
int count, int *eof, void *data);
static int dispatch_procfs_write(struct file *file,
const char __user * userbuf,
unsigned long count, void *data);
static char *next_cmd(char **cmds);
/* sysfs support */
struct attribute_set {
unsigned int members, max_members;
struct attribute_group group;
};
static struct attribute_set *create_attr_set(unsigned int max_members,
const char* name);
#define destroy_attr_set(_set) \
kfree(_set);
static int add_to_attr_set(struct attribute_set* s, struct attribute *attr);
static int add_many_to_attr_set(struct attribute_set* s,
struct attribute **attr,
unsigned int count);
#define register_attr_set_with_sysfs(_attr_set, _kobj) \
sysfs_create_group(_kobj, &_attr_set->group)
static void delete_attr_set(struct attribute_set* s, struct kobject *kobj);
static int parse_strtoul(const char *buf, unsigned long max,
unsigned long *value);
/* Device model */
static struct platform_device *tpacpi_pdev;
static struct platform_device *tpacpi_sensors_pdev;
static struct 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);
/* Module */
static int experimental;
static u32 dbg_level;
static int force_load;
static unsigned int hotkey_report_mode;
static int thinkpad_acpi_module_init(void);
static void thinkpad_acpi_module_exit(void);
/****************************************************************************
* Subdrivers
*/
struct ibm_struct;
struct tp_acpi_drv_struct {
const struct acpi_device_id *hid;
struct acpi_driver *driver;
void (*notify) (struct ibm_struct *, u32);
acpi_handle *handle;
u32 type;
struct acpi_device *device;
};
struct ibm_struct {
char *name;
int (*read) (char *);
int (*write) (char *);
void (*exit) (void);
void (*resume) (void);
struct list_head all_drivers;
struct tp_acpi_drv_struct *acpi;
struct {
u8 acpi_driver_registered:1;
u8 acpi_notify_installed:1;
u8 proc_created:1;
u8 init_called:1;
u8 experimental:1;
} flags;
};
struct ibm_init_struct {
char param[32];
int (*init) (struct ibm_init_struct *);
struct ibm_struct *data;
};
static struct {
#ifdef CONFIG_THINKPAD_ACPI_BAY
u32 bay_status:1;
u32 bay_eject:1;
u32 bay_status2:1;
u32 bay_eject2:1;
#endif
u32 bluetooth:1;
u32 hotkey:1;
u32 hotkey_mask:1;
u32 hotkey_wlsw:1;
u32 light:1;
u32 light_status:1;
u32 bright_16levels:1;
u32 wan:1;
u32 fan_ctrl_status_undef:1;
u32 input_device_registered:1;
u32 platform_drv_registered:1;
u32 platform_drv_attrs_registered:1;
u32 sensors_pdrv_registered:1;
u32 sensors_pdrv_attrs_registered:1;
u32 sensors_pdev_attrs_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[];
static int set_ibm_param(const char *val, struct kernel_param *kp);
static int ibm_init(struct ibm_init_struct *iibm);
static void ibm_exit(struct ibm_struct *ibm);
/*
* procfs master subdriver
*/
static int thinkpad_acpi_driver_init(struct ibm_init_struct *iibm);
static int thinkpad_acpi_driver_read(char *p);
/*
* Bay subdriver
*/
#ifdef CONFIG_THINKPAD_ACPI_BAY
static acpi_handle bay_handle, bay_ej_handle;
static acpi_handle bay2_handle, bay2_ej_handle;
static int bay_init(struct ibm_init_struct *iibm);
static void bay_notify(struct ibm_struct *ibm, u32 event);
static int bay_read(char *p);
static int bay_write(char *buf);
#endif /* CONFIG_THINKPAD_ACPI_BAY */
/*
* Beep subdriver
*/
static acpi_handle beep_handle;
static int beep_read(char *p);
static int beep_write(char *buf);
/*
* Bluetooth subdriver
*/
enum {
/* ACPI GBDC/SBDC bits */
TP_ACPI_BLUETOOTH_HWPRESENT = 0x01, /* Bluetooth hw available */
TP_ACPI_BLUETOOTH_RADIOSSW = 0x02, /* Bluetooth radio enabled */
TP_ACPI_BLUETOOTH_UNK = 0x04, /* unknown function */
};
static int bluetooth_init(struct ibm_init_struct *iibm);
static int bluetooth_get_radiosw(void);
static int bluetooth_set_radiosw(int radio_on);
static int bluetooth_read(char *p);
static int bluetooth_write(char *buf);
/*
* Brightness (backlight) subdriver
*/
#define TPACPI_BACKLIGHT_DEV_NAME "thinkpad_screen"
static struct backlight_device *ibm_backlight_device;
static int brightness_offset = 0x31;
static int brightness_mode;
static unsigned int brightness_enable; /* 0 = no, 1 = yes, 2 = auto */
static int brightness_init(struct ibm_init_struct *iibm);
static void brightness_exit(void);
static int brightness_get(struct backlight_device *bd);
static int brightness_set(int value);
static int brightness_update_status(struct backlight_device *bd);
static int brightness_read(char *p);
static int brightness_write(char *buf);
/*
* CMOS subdriver
*/
static int cmos_read(char *p);
static int cmos_write(char *buf);
/*
* Dock subdriver
*/
#ifdef CONFIG_THINKPAD_ACPI_DOCK
static acpi_handle pci_handle;
static acpi_handle dock_handle;
static void dock_notify(struct ibm_struct *ibm, u32 event);
static int dock_read(char *p);
static int dock_write(char *buf);
#endif /* CONFIG_THINKPAD_ACPI_DOCK */
/*
* EC dump subdriver
*/
static int ecdump_read(char *p) ;
static int ecdump_write(char *buf);
/*
* Fan subdriver
*/
enum { /* Fan control constants */
fan_status_offset = 0x2f, /* EC register 0x2f */
fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
* 0x84 must be read before 0x85 */
TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
TPACPI_FAN_LAST_LEVEL = 0x100, /* Use cached last-seen fan level */
};
enum fan_status_access_mode {
TPACPI_FAN_NONE = 0, /* No fan status or control */
TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
};
enum fan_control_access_mode {
TPACPI_FAN_WR_NONE = 0, /* No fan control */
TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
};
enum fan_control_commands {
TPACPI_FAN_CMD_SPEED = 0x0001, /* speed command */
TPACPI_FAN_CMD_LEVEL = 0x0002, /* level command */
TPACPI_FAN_CMD_ENABLE = 0x0004, /* enable/disable cmd,
* and also watchdog cmd */
};
static int fan_control_allowed;
static enum fan_status_access_mode fan_status_access_mode;
static enum fan_control_access_mode fan_control_access_mode;
static enum fan_control_commands fan_control_commands;
static u8 fan_control_initial_status;
static u8 fan_control_desired_level;
static int fan_watchdog_maxinterval;
static struct mutex fan_mutex;
static acpi_handle fans_handle, gfan_handle, sfan_handle;
static int fan_init(struct ibm_init_struct *iibm);
static void fan_exit(void);
static int fan_get_status(u8 *status);
static int fan_get_status_safe(u8 *status);
static int fan_get_speed(unsigned int *speed);
static void fan_update_desired_level(u8 status);
static void fan_watchdog_fire(struct work_struct *ignored);
static void fan_watchdog_reset(void);
static int fan_set_level(int level);
static int fan_set_level_safe(int level);
static int fan_set_enable(void);
static int fan_set_disable(void);
static int fan_set_speed(int speed);
static int fan_read(char *p);
static int fan_write(char *buf);
static int fan_write_cmd_level(const char *cmd, int *rc);
static int fan_write_cmd_enable(const char *cmd, int *rc);
static int fan_write_cmd_disable(const char *cmd, int *rc);
static int fan_write_cmd_speed(const char *cmd, int *rc);
static int fan_write_cmd_watchdog(const char *cmd, int *rc);
/*
* Hotkey subdriver
*/
static int hotkey_orig_status;
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, 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);
/*
* LED subdriver
*/
enum led_access_mode {
TPACPI_LED_NONE = 0,
TPACPI_LED_570, /* 570 */
TPACPI_LED_OLD, /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20-21 */
TPACPI_LED_NEW, /* all others */
};
enum { /* For TPACPI_LED_OLD */
TPACPI_LED_EC_HLCL = 0x0c, /* EC reg to get led to power on */
TPACPI_LED_EC_HLBL = 0x0d, /* EC reg to blink a lit led */
TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
};
static enum led_access_mode led_supported;
static acpi_handle led_handle;
static int led_init(struct ibm_init_struct *iibm);
static int led_read(char *p);
static int led_write(char *buf);
/*
* Light (thinklight) subdriver
*/
static acpi_handle lght_handle, ledb_handle;
static int light_init(struct ibm_init_struct *iibm);
static int light_read(char *p);
static int light_write(char *buf);
/*
* Thermal subdriver
*/
enum thermal_access_mode {
TPACPI_THERMAL_NONE = 0, /* No thermal support */
TPACPI_THERMAL_ACPI_TMP07, /* Use ACPI TMP0-7 */
TPACPI_THERMAL_ACPI_UPDT, /* Use ACPI TMP0-7 with UPDT */
TPACPI_THERMAL_TPEC_8, /* Use ACPI EC regs, 8 sensors */
TPACPI_THERMAL_TPEC_16, /* Use ACPI EC regs, 16 sensors */
};
enum { /* TPACPI_THERMAL_TPEC_* */
TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */
TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */
TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */
};
#define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */
struct ibm_thermal_sensors_struct {
s32 temp[TPACPI_MAX_THERMAL_SENSORS];
};
static enum thermal_access_mode thermal_read_mode;
static int thermal_init(struct ibm_init_struct *iibm);
static int thermal_get_sensor(int idx, s32 *value);
static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s);
static int thermal_read(char *p);
/*
* Video subdriver
*/
enum video_access_mode {
TPACPI_VIDEO_NONE = 0,
TPACPI_VIDEO_570, /* 570 */
TPACPI_VIDEO_770, /* 600e/x, 770e, 770x */
TPACPI_VIDEO_NEW, /* all others */
};
enum { /* video status flags, based on VIDEO_570 */
TP_ACPI_VIDEO_S_LCD = 0x01, /* LCD output enabled */
TP_ACPI_VIDEO_S_CRT = 0x02, /* CRT output enabled */
TP_ACPI_VIDEO_S_DVI = 0x08, /* DVI output enabled */
};
enum { /* TPACPI_VIDEO_570 constants */
TP_ACPI_VIDEO_570_PHSCMD = 0x87, /* unknown magic constant :( */
TP_ACPI_VIDEO_570_PHSMASK = 0x03, /* PHS bits that map to
* video_status_flags */
TP_ACPI_VIDEO_570_PHS2CMD = 0x8b, /* unknown magic constant :( */
TP_ACPI_VIDEO_570_PHS2SET = 0x80, /* unknown magic constant :( */
};
static enum video_access_mode video_supported;
static int video_orig_autosw;
static acpi_handle vid_handle, vid2_handle;
static int video_init(struct ibm_init_struct *iibm);
static void video_exit(void);
static int video_outputsw_get(void);
static int video_outputsw_set(int status);
static int video_autosw_get(void);
static int video_autosw_set(int enable);
static int video_outputsw_cycle(void);
static int video_expand_toggle(void);
static int video_read(char *p);
static int video_write(char *buf);
/*
* Volume subdriver
*/
static int volume_offset = 0x30;
static int volume_read(char *p);
static int volume_write(char *buf);
/*
* Wan subdriver
*/
enum {
/* ACPI GWAN/SWAN bits */
TP_ACPI_WANCARD_HWPRESENT = 0x01, /* Wan hw available */
TP_ACPI_WANCARD_RADIOSSW = 0x02, /* Wan radio enabled */
TP_ACPI_WANCARD_UNK = 0x04, /* unknown function */
};
static int wan_init(struct ibm_init_struct *iibm);
static int wan_get_radiosw(void);
static int wan_set_radiosw(int radio_on);
static int wan_read(char *p);
static int wan_write(char *buf);
#endif /* __THINKPAD_ACPI_H */

View File

@ -183,7 +183,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
if (ACPI_SUCCESS(status)) if (ACPI_SUCCESS(status))
dev->capabilities |= PNP_CONFIGURABLE; dev->capabilities |= PNP_CONFIGURABLE;
dev->capabilities |= PNP_READ; dev->capabilities |= PNP_READ;
if (device->flags.dynamic_status) if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
dev->capabilities |= PNP_WRITE; dev->capabilities |= PNP_WRITE;
if (device->flags.removable) if (device->flags.removable)
dev->capabilities |= PNP_REMOVABLE; dev->capabilities |= PNP_REMOVABLE;

View File

@ -115,6 +115,7 @@ static struct device_attribute power_supply_attrs[] = {
/* Properties of type `const char *' */ /* Properties of type `const char *' */
POWER_SUPPLY_ATTR(model_name), POWER_SUPPLY_ATTR(model_name),
POWER_SUPPLY_ATTR(manufacturer), POWER_SUPPLY_ATTR(manufacturer),
POWER_SUPPLY_ATTR(serial_number),
}; };
static ssize_t power_supply_show_static_attrs(struct device *dev, static ssize_t power_supply_show_static_attrs(struct device *dev,

15
drivers/thermal/Kconfig Normal file
View File

@ -0,0 +1,15 @@
#
# Generic thermal sysfs drivers configuration
#
menuconfig THERMAL
bool "Generic Thermal sysfs driver"
default y
help
Generic Thermal Sysfs driver offers a generic mechanism for
thermal management. Usually it's made up of one or more thermal
zone and cooling device.
each thermal zone contains its own temperature, trip points,
cooling devices.
All platforms with ACPI thermal support can use this driver.
If you want this support, you should say Y here

5
drivers/thermal/Makefile Normal file
View File

@ -0,0 +1,5 @@
#
# Makefile for sensor chip drivers.
#
obj-$(CONFIG_THERMAL) += thermal.o

714
drivers/thermal/thermal.c Normal file
View File

@ -0,0 +1,714 @@
/*
* thermal.c - Generic Thermal Management Sysfs support.
*
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#include <linux/module.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/kdev_t.h>
#include <linux/idr.h>
#include <linux/thermal.h>
#include <linux/spinlock.h>
MODULE_AUTHOR("Zhang Rui")
MODULE_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL");
#define PREFIX "Thermal: "
struct thermal_cooling_device_instance {
int id;
char name[THERMAL_NAME_LENGTH];
struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev;
int trip;
char attr_name[THERMAL_NAME_LENGTH];
struct device_attribute attr;
struct list_head node;
};
static DEFINE_IDR(thermal_tz_idr);
static DEFINE_IDR(thermal_cdev_idr);
static DEFINE_MUTEX(thermal_idr_lock);
static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock);
static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{
int err;
again:
if (unlikely(idr_pre_get(idr, GFP_KERNEL) == 0))
return -ENOMEM;
if (lock)
mutex_lock(lock);
err = idr_get_new(idr, NULL, id);
if (lock)
mutex_unlock(lock);
if (unlikely(err == -EAGAIN))
goto again;
else if (unlikely(err))
return err;
*id = *id & MAX_ID_MASK;
return 0;
}
static void release_idr(struct idr *idr, struct mutex *lock, int id)
{
if (lock)
mutex_lock(lock);
idr_remove(idr, id);
if (lock)
mutex_unlock(lock);
}
/* sys I/F for thermal zone */
#define to_thermal_zone(_dev) \
container_of(_dev, struct thermal_zone_device, device)
static ssize_t
type_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
return sprintf(buf, "%s\n", tz->type);
}
static ssize_t
temp_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
if (!tz->ops->get_temp)
return -EPERM;
return tz->ops->get_temp(tz, buf);
}
static ssize_t
mode_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
if (!tz->ops->get_mode)
return -EPERM;
return tz->ops->get_mode(tz, buf);
}
static ssize_t
mode_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int result;
if (!tz->ops->set_mode)
return -EPERM;
result = tz->ops->set_mode(tz, buf);
if (result)
return result;
return count;
}
static ssize_t
trip_point_type_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int trip;
if (!tz->ops->get_trip_type)
return -EPERM;
if (!sscanf(attr->attr.name, "trip_point_%d_type", &trip))
return -EINVAL;
return tz->ops->get_trip_type(tz, trip, buf);
}
static ssize_t
trip_point_temp_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct thermal_zone_device *tz = to_thermal_zone(dev);
int trip;
if (!tz->ops->get_trip_temp)
return -EPERM;
if (!sscanf(attr->attr.name, "trip_point_%d_temp", &trip))
return -EINVAL;
return tz->ops->get_trip_temp(tz, trip, buf);
}
static DEVICE_ATTR(type, 0444, type_show, NULL);
static DEVICE_ATTR(temp, 0444, temp_show, NULL);
static DEVICE_ATTR(mode, 0644, mode_show, mode_store);
static struct device_attribute trip_point_attrs[] = {
__ATTR(trip_point_0_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_0_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_1_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_1_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_2_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_2_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_3_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_3_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_4_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_4_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_5_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_5_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_6_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_6_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_7_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_7_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_8_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_8_temp, 0444, trip_point_temp_show, NULL),
__ATTR(trip_point_9_type, 0444, trip_point_type_show, NULL),
__ATTR(trip_point_9_temp, 0444, trip_point_temp_show, NULL),
};
#define TRIP_POINT_ATTR_ADD(_dev, _index, result) \
do { \
result = device_create_file(_dev, \
&trip_point_attrs[_index * 2]); \
if (result) \
break; \
result = device_create_file(_dev, \
&trip_point_attrs[_index * 2 + 1]); \
} while (0)
#define TRIP_POINT_ATTR_REMOVE(_dev, _index) \
do { \
device_remove_file(_dev, &trip_point_attrs[_index * 2]); \
device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \
} while (0)
/* sys I/F for cooling device */
#define to_cooling_device(_dev) \
container_of(_dev, struct thermal_cooling_device, device)
static ssize_t
thermal_cooling_device_type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
return sprintf(buf, "%s\n", cdev->type);
}
static ssize_t
thermal_cooling_device_max_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
return cdev->ops->get_max_state(cdev, buf);
}
static ssize_t
thermal_cooling_device_cur_state_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
return cdev->ops->get_cur_state(cdev, buf);
}
static ssize_t
thermal_cooling_device_cur_state_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct thermal_cooling_device *cdev = to_cooling_device(dev);
int state;
int result;
if (!sscanf(buf, "%d\n", &state))
return -EINVAL;
if (state < 0)
return -EINVAL;
result = cdev->ops->set_cur_state(cdev, state);
if (result)
return result;
return count;
}
static struct device_attribute dev_attr_cdev_type =
__ATTR(type, 0444, thermal_cooling_device_type_show, NULL);
static DEVICE_ATTR(max_state, 0444,
thermal_cooling_device_max_state_show, NULL);
static DEVICE_ATTR(cur_state, 0644,
thermal_cooling_device_cur_state_show,
thermal_cooling_device_cur_state_store);
static ssize_t
thermal_cooling_device_trip_point_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct thermal_cooling_device_instance *instance;
instance =
container_of(attr, struct thermal_cooling_device_instance, attr);
if (instance->trip == THERMAL_TRIPS_NONE)
return sprintf(buf, "-1\n");
else
return sprintf(buf, "%d\n", instance->trip);
}
/* Device management */
/**
* thermal_zone_bind_cooling_device - bind a cooling device to a thermal zone
* this function is usually called in the thermal zone device .bind callback.
* @tz: thermal zone device
* @trip: indicates which trip point the cooling devices is
* associated with in this thermal zone.
* @cdev: thermal cooling device
*/
int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
int trip,
struct thermal_cooling_device *cdev)
{
struct thermal_cooling_device_instance *dev;
struct thermal_cooling_device_instance *pos;
int result;
if (trip >= tz->trips ||
(trip < 0 && trip != THERMAL_TRIPS_NONE))
return -EINVAL;
if (!tz || !cdev)
return -EINVAL;
dev =
kzalloc(sizeof(struct thermal_cooling_device_instance), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->tz = tz;
dev->cdev = cdev;
dev->trip = trip;
result = get_idr(&tz->idr, &tz->lock, &dev->id);
if (result)
goto free_mem;
sprintf(dev->name, "cdev%d", dev->id);
result =
sysfs_create_link(&tz->device.kobj, &cdev->device.kobj, dev->name);
if (result)
goto release_idr;
sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
dev->attr.attr.name = dev->attr_name;
dev->attr.attr.mode = 0444;
dev->attr.show = thermal_cooling_device_trip_point_show;
result = device_create_file(&tz->device, &dev->attr);
if (result)
goto remove_symbol_link;
mutex_lock(&tz->lock);
list_for_each_entry(pos, &tz->cooling_devices, node)
if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
result = -EEXIST;
break;
}
if (!result)
list_add_tail(&dev->node, &tz->cooling_devices);
mutex_unlock(&tz->lock);
if (!result)
return 0;
device_remove_file(&tz->device, &dev->attr);
remove_symbol_link:
sysfs_remove_link(&tz->device.kobj, dev->name);
release_idr:
release_idr(&tz->idr, &tz->lock, dev->id);
free_mem:
kfree(dev);
return result;
}
EXPORT_SYMBOL(thermal_zone_bind_cooling_device);
/**
* thermal_zone_unbind_cooling_device - unbind a cooling device from a thermal zone
* this function is usually called in the thermal zone device .unbind callback.
* @tz: thermal zone device
* @trip: indicates which trip point the cooling devices is
* associated with in this thermal zone.
* @cdev: thermal cooling device
*/
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
int trip,
struct thermal_cooling_device *cdev)
{
struct thermal_cooling_device_instance *pos, *next;
mutex_lock(&tz->lock);
list_for_each_entry_safe(pos, next, &tz->cooling_devices, node) {
if (pos->tz == tz && pos->trip == trip
&& pos->cdev == cdev) {
list_del(&pos->node);
mutex_unlock(&tz->lock);
goto unbind;
}
}
mutex_unlock(&tz->lock);
return -ENODEV;
unbind:
device_remove_file(&tz->device, &pos->attr);
sysfs_remove_link(&tz->device.kobj, pos->name);
release_idr(&tz->idr, &tz->lock, pos->id);
kfree(pos);
return 0;
}
EXPORT_SYMBOL(thermal_zone_unbind_cooling_device);
static void thermal_release(struct device *dev)
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *cdev;
if (!strncmp(dev->bus_id, "thermal_zone", sizeof "thermal_zone" - 1)) {
tz = to_thermal_zone(dev);
kfree(tz);
} else {
cdev = to_cooling_device(dev);
kfree(cdev);
}
}
static struct class thermal_class = {
.name = "thermal",
.dev_release = thermal_release,
};
/**
* thermal_cooling_device_register - register a new thermal cooling device
* @type: the thermal cooling device type.
* @devdata: device private data.
* @ops: standard thermal cooling devices callbacks.
*/
struct thermal_cooling_device *thermal_cooling_device_register(char *type,
void *devdata, struct thermal_cooling_device_ops *ops)
{
struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos;
int result;
if (strlen(type) >= THERMAL_NAME_LENGTH)
return NULL;
if (!ops || !ops->get_max_state || !ops->get_cur_state ||
!ops->set_cur_state)
return NULL;
cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
if (!cdev)
return NULL;
result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
if (result) {
kfree(cdev);
return NULL;
}
strcpy(cdev->type, type);
cdev->ops = ops;
cdev->device.class = &thermal_class;
cdev->devdata = devdata;
sprintf(cdev->device.bus_id, "cooling_device%d", cdev->id);
result = device_register(&cdev->device);
if (result) {
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
kfree(cdev);
return NULL;
}
/* sys I/F */
if (type) {
result = device_create_file(&cdev->device,
&dev_attr_cdev_type);
if (result)
goto unregister;
}
result = device_create_file(&cdev->device, &dev_attr_max_state);
if (result)
goto unregister;
result = device_create_file(&cdev->device, &dev_attr_cur_state);
if (result)
goto unregister;
mutex_lock(&thermal_list_lock);
list_add(&cdev->node, &thermal_cdev_list);
list_for_each_entry(pos, &thermal_tz_list, node) {
if (!pos->ops->bind)
continue;
result = pos->ops->bind(pos, cdev);
if (result)
break;
}
mutex_unlock(&thermal_list_lock);
if (!result)
return cdev;
unregister:
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
device_unregister(&cdev->device);
return NULL;
}
EXPORT_SYMBOL(thermal_cooling_device_register);
/**
* thermal_cooling_device_unregister - removes the registered thermal cooling device
*
* @cdev: the thermal cooling device to remove.
*
* thermal_cooling_device_unregister() must be called when the device is no
* longer needed.
*/
void thermal_cooling_device_unregister(struct
thermal_cooling_device
*cdev)
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos = NULL;
if (!cdev)
return;
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_cdev_list, node)
if (pos == cdev)
break;
if (pos != cdev) {
/* thermal cooling device not found */
mutex_unlock(&thermal_list_lock);
return;
}
list_del(&cdev->node);
list_for_each_entry(tz, &thermal_tz_list, node) {
if (!tz->ops->unbind)
continue;
tz->ops->unbind(tz, cdev);
}
mutex_unlock(&thermal_list_lock);
if (cdev->type[0])
device_remove_file(&cdev->device,
&dev_attr_cdev_type);
device_remove_file(&cdev->device, &dev_attr_max_state);
device_remove_file(&cdev->device, &dev_attr_cur_state);
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
device_unregister(&cdev->device);
return;
}
EXPORT_SYMBOL(thermal_cooling_device_unregister);
/**
* thermal_zone_device_register - register a new thermal zone device
* @type: the thermal zone device type
* @trips: the number of trip points the thermal zone support
* @devdata: private device data
* @ops: standard thermal zone device callbacks
*
* thermal_zone_device_unregister() must be called when the device is no
* longer needed.
*/
struct thermal_zone_device *thermal_zone_device_register(char *type,
int trips, void *devdata,
struct thermal_zone_device_ops *ops)
{
struct thermal_zone_device *tz;
struct thermal_cooling_device *pos;
int result;
int count;
if (strlen(type) >= THERMAL_NAME_LENGTH)
return NULL;
if (trips > THERMAL_MAX_TRIPS || trips < 0)
return NULL;
if (!ops || !ops->get_temp)
return NULL;
tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
if (!tz)
return NULL;
INIT_LIST_HEAD(&tz->cooling_devices);
idr_init(&tz->idr);
mutex_init(&tz->lock);
result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
if (result) {
kfree(tz);
return NULL;
}
strcpy(tz->type, type);
tz->ops = ops;
tz->device.class = &thermal_class;
tz->devdata = devdata;
tz->trips = trips;
sprintf(tz->device.bus_id, "thermal_zone%d", tz->id);
result = device_register(&tz->device);
if (result) {
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
kfree(tz);
return NULL;
}
/* sys I/F */
if (type) {
result = device_create_file(&tz->device, &dev_attr_type);
if (result)
goto unregister;
}
result = device_create_file(&tz->device, &dev_attr_temp);
if (result)
goto unregister;
if (ops->get_mode) {
result = device_create_file(&tz->device, &dev_attr_mode);
if (result)
goto unregister;
}
for (count = 0; count < trips; count++) {
TRIP_POINT_ATTR_ADD(&tz->device, count, result);
if (result)
goto unregister;
}
mutex_lock(&thermal_list_lock);
list_add_tail(&tz->node, &thermal_tz_list);
if (ops->bind)
list_for_each_entry(pos, &thermal_cdev_list, node) {
result = ops->bind(tz, pos);
if (result)
break;
}
mutex_unlock(&thermal_list_lock);
if (!result)
return tz;
unregister:
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
device_unregister(&tz->device);
return NULL;
}
EXPORT_SYMBOL(thermal_zone_device_register);
/**
* thermal_device_unregister - removes the registered thermal zone device
*
* @tz: the thermal zone device to remove
*/
void thermal_zone_device_unregister(struct thermal_zone_device *tz)
{
struct thermal_cooling_device *cdev;
struct thermal_zone_device *pos = NULL;
int count;
if (!tz)
return;
mutex_lock(&thermal_list_lock);
list_for_each_entry(pos, &thermal_tz_list, node)
if (pos == tz)
break;
if (pos != tz) {
/* thermal zone device not found */
mutex_unlock(&thermal_list_lock);
return;
}
list_del(&tz->node);
if (tz->ops->unbind)
list_for_each_entry(cdev, &thermal_cdev_list, node)
tz->ops->unbind(tz, cdev);
mutex_unlock(&thermal_list_lock);
if (tz->type[0])
device_remove_file(&tz->device, &dev_attr_type);
device_remove_file(&tz->device, &dev_attr_temp);
if (tz->ops->get_mode)
device_remove_file(&tz->device, &dev_attr_mode);
for (count = 0; count < tz->trips; count++)
TRIP_POINT_ATTR_REMOVE(&tz->device, count);
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
idr_destroy(&tz->idr);
mutex_destroy(&tz->lock);
device_unregister(&tz->device);
return;
}
EXPORT_SYMBOL(thermal_zone_device_unregister);
static int __init thermal_init(void)
{
int result = 0;
result = class_register(&thermal_class);
if (result) {
idr_destroy(&thermal_tz_idr);
idr_destroy(&thermal_cdev_idr);
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
}
return result;
}
static void __exit thermal_exit(void)
{
class_unregister(&thermal_class);
idr_destroy(&thermal_tz_idr);
idr_destroy(&thermal_cdev_idr);
mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock);
}
subsys_initcall(thermal_init);
module_exit(thermal_exit);

View File

@ -117,10 +117,6 @@ extern u32 acpi_dbg_layer;
extern u32 acpi_gbl_nesting_level; extern u32 acpi_gbl_nesting_level;
/* Event counters */
ACPI_EXTERN u32 acpi_gpe_count;
/* Support for dynamic control method tracing mechanism */ /* Support for dynamic control method tracing mechanism */
ACPI_EXTERN u32 acpi_gbl_original_dbg_level; ACPI_EXTERN u32 acpi_gbl_original_dbg_level;

View File

@ -486,7 +486,7 @@
#define ACPI_FUNCTION_NAME(name) #define ACPI_FUNCTION_NAME(name)
#endif #endif
#ifdef DEBUG_FUNC_TRACE #ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE
#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \ #define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \
acpi_ut_trace(ACPI_DEBUG_PARAMETERS) acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
@ -565,7 +565,7 @@
#endif /* ACPI_SIMPLE_RETURN_MACROS */ #endif /* ACPI_SIMPLE_RETURN_MACROS */
#else /* !DEBUG_FUNC_TRACE */ #else /* !CONFIG_ACPI_DEBUG_FUNC_TRACE */
#define ACPI_FUNCTION_TRACE(a) #define ACPI_FUNCTION_TRACE(a)
#define ACPI_FUNCTION_TRACE_PTR(a,b) #define ACPI_FUNCTION_TRACE_PTR(a,b)
@ -584,7 +584,7 @@
#define return_UINT32(s) return(s) #define return_UINT32(s) return(s)
#define return_PTR(s) return(s) #define return_PTR(s) return(s)
#endif /* DEBUG_FUNC_TRACE */ #endif /* CONFIG_ACPI_DEBUG_FUNC_TRACE */
/* Conditional execution */ /* Conditional execution */

View File

@ -321,6 +321,11 @@ struct acpi_bus_event {
extern struct kobject *acpi_kobj; extern struct kobject *acpi_kobj;
extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int); extern int acpi_bus_generate_netlink_event(const char*, const char*, u8, int);
void acpi_bus_private_data_handler(acpi_handle, u32, void *);
int acpi_bus_get_private_data(acpi_handle, void **);
extern int acpi_notifier_call_chain(struct acpi_device *, u32, u32);
extern int register_acpi_notifier(struct notifier_block *);
extern int unregister_acpi_notifier(struct notifier_block *);
/* /*
* External Functions * External Functions
*/ */

View File

@ -48,6 +48,7 @@
#define ACPI_BUTTON_HID_SLEEPF "LNXSLPBN" #define ACPI_BUTTON_HID_SLEEPF "LNXSLPBN"
#define ACPI_VIDEO_HID "LNXVIDEO" #define ACPI_VIDEO_HID "LNXVIDEO"
#define ACPI_BAY_HID "LNXIOBAY" #define ACPI_BAY_HID "LNXIOBAY"
#define ACPI_DOCK_HID "LNXDOCK"
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
PCI PCI
@ -73,7 +74,6 @@ struct pci_bus;
acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id); acpi_status acpi_get_pci_id(acpi_handle handle, struct acpi_pci_id *id);
int acpi_pci_bind(struct acpi_device *device); int acpi_pci_bind(struct acpi_device *device);
int acpi_pci_unbind(struct acpi_device *device);
int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id, int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id,
struct pci_bus *bus); struct pci_bus *bus);

View File

@ -15,7 +15,6 @@ extern int pxm_to_node(int);
extern int node_to_pxm(int); extern int node_to_pxm(int);
extern void __acpi_map_pxm_to_node(int, int); extern void __acpi_map_pxm_to_node(int, int);
extern int acpi_map_pxm_to_node(int); extern int acpi_map_pxm_to_node(int);
extern void __cpuinit acpi_unmap_pxm_to_node(int);
#endif /* CONFIG_ACPI_NUMA */ #endif /* CONFIG_ACPI_NUMA */
#endif /* __ACP_NUMA_H */ #endif /* __ACP_NUMA_H */

View File

@ -181,6 +181,9 @@ acpi_os_install_interrupt_handler(u32 gsi,
acpi_status acpi_status
acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine); acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler service_routine);
void acpi_os_gpe_count(u32 gpe_number);
void acpi_os_fixed_event_count(u32 fixed_event_number);
/* /*
* Threads and Scheduling * Threads and Scheduling
*/ */
@ -239,8 +242,8 @@ acpi_status acpi_os_validate_interface(char *interface);
acpi_status acpi_osi_invalidate(char* interface); acpi_status acpi_osi_invalidate(char* interface);
acpi_status acpi_status
acpi_os_validate_address(u8 space_id, acpi_os_validate_address(u8 space_id, acpi_physical_address address,
acpi_physical_address address, acpi_size length); acpi_size length, char *name);
u64 acpi_os_get_timer(void); u64 acpi_os_get_timer(void);

View File

@ -4,7 +4,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/cpuidle.h> #include <linux/cpuidle.h>
#include <linux/thermal.h>
#include <asm/acpi.h> #include <asm/acpi.h>
#define ACPI_PROCESSOR_BUSY_METRIC 10 #define ACPI_PROCESSOR_BUSY_METRIC 10
@ -34,6 +34,7 @@
#define ACPI_CSTATE_SYSTEMIO (0) #define ACPI_CSTATE_SYSTEMIO (0)
#define ACPI_CSTATE_FFH (1) #define ACPI_CSTATE_FFH (1)
#define ACPI_CSTATE_HALT (2)
/* Power Management */ /* Power Management */
@ -64,7 +65,7 @@ struct acpi_processor_cx {
u8 valid; u8 valid;
u8 type; u8 type;
u32 address; u32 address;
u8 space_id; u8 entry_method;
u8 index; u8 index;
u32 latency; u32 latency;
u32 latency_ticks; u32 latency_ticks;
@ -176,6 +177,8 @@ struct acpi_processor_throttling {
u32 address; u32 address;
u8 duty_offset; u8 duty_offset;
u8 duty_width; u8 duty_width;
u8 tsd_valid_flag;
unsigned int shared_type;
struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING]; struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING];
}; };
@ -218,7 +221,7 @@ struct acpi_processor {
struct acpi_processor_performance *performance; struct acpi_processor_performance *performance;
struct acpi_processor_throttling throttling; struct acpi_processor_throttling throttling;
struct acpi_processor_limit limit; struct acpi_processor_limit limit;
struct thermal_cooling_device *cdev;
/* the _PDC objects for this processor, if any */ /* the _PDC objects for this processor, if any */
struct acpi_object_list *pdc; struct acpi_object_list *pdc;
}; };
@ -316,7 +319,7 @@ static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
int acpi_processor_get_throttling_info(struct acpi_processor *pr); int acpi_processor_get_throttling_info(struct acpi_processor *pr);
extern 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; extern struct file_operations acpi_processor_throttling_fops;
extern void acpi_processor_throttling_init(void);
/* in processor_idle.c */ /* in processor_idle.c */
int acpi_processor_power_init(struct acpi_processor *pr, int acpi_processor_power_init(struct acpi_processor *pr,
struct acpi_device *device); struct acpi_device *device);
@ -330,7 +333,7 @@ extern struct cpuidle_driver acpi_idle_driver;
/* in processor_thermal.c */ /* in processor_thermal.c */
int acpi_processor_get_limit_info(struct acpi_processor *pr); int acpi_processor_get_limit_info(struct acpi_processor *pr);
extern struct file_operations acpi_processor_limit_fops; extern struct file_operations acpi_processor_limit_fops;
extern struct thermal_cooling_device_ops processor_cooling_ops;
#ifdef CONFIG_CPU_FREQ #ifdef CONFIG_CPU_FREQ
void acpi_thermal_cpufreq_init(void); void acpi_thermal_cpufreq_init(void);
void acpi_thermal_cpufreq_exit(void); void acpi_thermal_cpufreq_exit(void);

View File

@ -25,6 +25,7 @@
#ifndef _LINUX_ACPI_H #ifndef _LINUX_ACPI_H
#define _LINUX_ACPI_H #define _LINUX_ACPI_H
#include <linux/ioport.h> /* for struct resource */
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
@ -43,8 +44,6 @@
#include <linux/dmi.h> #include <linux/dmi.h>
#ifdef CONFIG_ACPI
enum acpi_irq_model_id { enum acpi_irq_model_id {
ACPI_IRQ_MODEL_PIC = 0, ACPI_IRQ_MODEL_PIC = 0,
ACPI_IRQ_MODEL_IOAPIC, ACPI_IRQ_MODEL_IOAPIC,
@ -80,7 +79,6 @@ typedef int (*acpi_table_handler) (struct acpi_table_header *table);
typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end); typedef int (*acpi_table_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
char * __acpi_map_table (unsigned long phys_addr, unsigned long size); char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
unsigned long acpi_find_rsdp (void);
int acpi_boot_init (void); int acpi_boot_init (void);
int acpi_boot_table_init (void); int acpi_boot_table_init (void);
int acpi_numa_init (void); int acpi_numa_init (void);
@ -115,8 +113,8 @@ int acpi_unmap_lsapic(int cpu);
int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
void acpi_irq_stats_init(void);
extern int acpi_mp_config; extern u32 acpi_irq_handled;
extern struct acpi_mcfg_allocation *pci_mmcfg_config; extern struct acpi_mcfg_allocation *pci_mmcfg_config;
extern int pci_mmcfg_config_num; extern int pci_mmcfg_config_num;
@ -124,12 +122,6 @@ extern int pci_mmcfg_config_num;
extern int sbf_port; extern int sbf_port;
extern unsigned long acpi_realmode_flags; extern unsigned long acpi_realmode_flags;
#else /* !CONFIG_ACPI */
#define acpi_mp_config 0
#endif /* !CONFIG_ACPI */
int acpi_register_gsi (u32 gsi, int triggering, int polarity); int acpi_register_gsi (u32 gsi, int triggering, int polarity);
int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
@ -145,8 +137,6 @@ extern int acpi_get_override_irq(int bus_irq, int *trigger, int *polarity);
*/ */
void acpi_unregister_gsi (u32 gsi); void acpi_unregister_gsi (u32 gsi);
#ifdef CONFIG_ACPI
struct acpi_prt_entry { struct acpi_prt_entry {
struct list_head node; struct list_head node;
struct acpi_pci_id id; struct acpi_pci_id id;
@ -179,8 +169,6 @@ struct acpi_pci_driver {
int acpi_pci_register_driver(struct acpi_pci_driver *driver); int acpi_pci_register_driver(struct acpi_pci_driver *driver);
void acpi_pci_unregister_driver(struct acpi_pci_driver *driver); void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
#endif /* CONFIG_ACPI */
#ifdef CONFIG_ACPI_EC #ifdef CONFIG_ACPI_EC
extern int ec_read(u8 addr, u8 *val); extern int ec_read(u8 addr, u8 *val);
@ -192,6 +180,26 @@ extern int ec_transaction(u8 command,
#endif /*CONFIG_ACPI_EC*/ #endif /*CONFIG_ACPI_EC*/
#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
typedef void (*wmi_notify_handler) (u32 value, void *context);
extern acpi_status wmi_evaluate_method(const char *guid, u8 instance,
u32 method_id,
const struct acpi_buffer *in,
struct acpi_buffer *out);
extern acpi_status wmi_query_block(const char *guid, u8 instance,
struct acpi_buffer *out);
extern acpi_status wmi_set_block(const char *guid, u8 instance,
const struct acpi_buffer *in);
extern acpi_status wmi_install_notify_handler(const char *guid,
wmi_notify_handler handler, void *data);
extern acpi_status wmi_remove_notify_handler(const char *guid);
extern acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out);
extern bool wmi_has_guid(const char *guid);
#endif /* CONFIG_ACPI_WMI */
extern int acpi_blacklisted(void); extern int acpi_blacklisted(void);
#ifdef CONFIG_DMI #ifdef CONFIG_DMI
extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d); extern void acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d);
@ -217,6 +225,13 @@ extern int pnpacpi_disabled;
#define PXM_INVAL (-1) #define PXM_INVAL (-1)
#define NID_INVAL (-1) #define NID_INVAL (-1)
int acpi_check_resource_conflict(struct resource *res);
int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name);
int acpi_check_mem_region(resource_size_t start, resource_size_t n,
const char *name);
#else /* CONFIG_ACPI */ #else /* CONFIG_ACPI */
static inline int acpi_boot_init(void) static inline int acpi_boot_init(void)
@ -229,5 +244,22 @@ static inline int acpi_boot_table_init(void)
return 0; return 0;
} }
static inline int acpi_check_resource_conflict(struct resource *res)
{
return 0;
}
static inline int acpi_check_region(resource_size_t start, resource_size_t n,
const char *name)
{
return 0;
}
static inline int acpi_check_mem_region(resource_size_t start,
resource_size_t n, const char *name)
{
return 0;
}
#endif /* !CONFIG_ACPI */ #endif /* !CONFIG_ACPI */
#endif /*_LINUX_ACPI_H*/ #endif /*_LINUX_ACPI_H*/

View File

@ -46,9 +46,10 @@ struct cpuidle_state {
/* Idle State Flags */ /* Idle State Flags */
#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */ #define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
#define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */ #define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */
#define CPUIDLE_FLAG_SHALLOW (0x10) /* low latency, minimal savings */ #define CPUIDLE_FLAG_POLL (0x10) /* no latency, no savings */
#define CPUIDLE_FLAG_BALANCED (0x20) /* medium latency, moderate savings */ #define CPUIDLE_FLAG_SHALLOW (0x20) /* low latency, minimal savings */
#define CPUIDLE_FLAG_DEEP (0x40) /* high latency, large savings */ #define CPUIDLE_FLAG_BALANCED (0x40) /* medium latency, moderate savings */
#define CPUIDLE_FLAG_DEEP (0x80) /* high latency, large savings */
#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) #define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000)
@ -178,4 +179,10 @@ static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { }
#endif #endif
#ifdef CONFIG_ARCH_HAS_CPU_RELAX
#define CPUIDLE_DRIVER_STATE_START 1
#else
#define CPUIDLE_DRIVER_STATE_START 0
#endif
#endif /* _LINUX_CPUIDLE_H */ #endif /* _LINUX_CPUIDLE_H */

View File

@ -79,7 +79,6 @@ extern void dmi_scan_machine(void);
extern int dmi_get_year(int field); extern int dmi_get_year(int field);
extern int dmi_name_in_vendors(const char *str); extern int dmi_name_in_vendors(const char *str);
extern int dmi_available; extern int dmi_available;
extern char *dmi_get_slot(int slot);
#else #else
@ -90,7 +89,6 @@ static inline const struct dmi_device * dmi_find_device(int type, const char *na
static inline int dmi_get_year(int year) { return 0; } static inline int dmi_get_year(int year) { return 0; }
static inline int dmi_name_in_vendors(const char *s) { return 0; } static inline int dmi_name_in_vendors(const char *s) { return 0; }
#define dmi_available 0 #define dmi_available 0
static inline char *dmi_get_slot(int slot) { return NULL; }
#endif #endif

View File

@ -243,6 +243,7 @@ extern enum system_states {
#define TAINT_BAD_PAGE (1<<5) #define TAINT_BAD_PAGE (1<<5)
#define TAINT_USER (1<<6) #define TAINT_USER (1<<6)
#define TAINT_DIE (1<<7) #define TAINT_DIE (1<<7)
#define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8)
extern void dump_stack(void) __cold; extern void dump_stack(void) __cold;

View File

@ -94,6 +94,7 @@ enum power_supply_property {
/* Properties of type `const char *' */ /* Properties of type `const char *' */
POWER_SUPPLY_PROP_MODEL_NAME, POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_MANUFACTURER, POWER_SUPPLY_PROP_MANUFACTURER,
POWER_SUPPLY_PROP_SERIAL_NUMBER,
}; };
enum power_supply_type { enum power_supply_type {

View File

@ -101,6 +101,8 @@
#define SONYPI_EVENT_FNKEY_RELEASED 59 #define SONYPI_EVENT_FNKEY_RELEASED 59
#define SONYPI_EVENT_WIRELESS_ON 60 #define SONYPI_EVENT_WIRELESS_ON 60
#define SONYPI_EVENT_WIRELESS_OFF 61 #define SONYPI_EVENT_WIRELESS_OFF 61
#define SONYPI_EVENT_ZOOM_IN_PRESSED 62
#define SONYPI_EVENT_ZOOM_OUT_PRESSED 63
/* get/set brightness */ /* get/set brightness */
#define SONYPI_IOCGBRT _IOR('v', 0, __u8) #define SONYPI_IOCGBRT _IOR('v', 0, __u8)

94
include/linux/thermal.h Normal file
View File

@ -0,0 +1,94 @@
/*
* thermal.h ($Revision: 0 $)
*
* Copyright (C) 2008 Intel Corp
* Copyright (C) 2008 Zhang Rui <rui.zhang@intel.com>
* Copyright (C) 2008 Sujith Thomas <sujith.thomas@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#ifndef __THERMAL_H__
#define __THERMAL_H__
#include <linux/idr.h>
#include <linux/device.h>
struct thermal_zone_device;
struct thermal_cooling_device;
struct thermal_zone_device_ops {
int (*bind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*unbind) (struct thermal_zone_device *,
struct thermal_cooling_device *);
int (*get_temp) (struct thermal_zone_device *, char *);
int (*get_mode) (struct thermal_zone_device *, char *);
int (*set_mode) (struct thermal_zone_device *, const char *);
int (*get_trip_type) (struct thermal_zone_device *, int, char *);
int (*get_trip_temp) (struct thermal_zone_device *, int, char *);
};
struct thermal_cooling_device_ops {
int (*get_max_state) (struct thermal_cooling_device *, char *);
int (*get_cur_state) (struct thermal_cooling_device *, char *);
int (*set_cur_state) (struct thermal_cooling_device *, unsigned int);
};
#define THERMAL_TRIPS_NONE -1
#define THERMAL_MAX_TRIPS 10
#define THERMAL_NAME_LENGTH 20
struct thermal_cooling_device {
int id;
char type[THERMAL_NAME_LENGTH];
struct device device;
void *devdata;
struct thermal_cooling_device_ops *ops;
struct list_head node;
};
#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
((long)t-2732+5)/10 : ((long)t-2732-5)/10)
#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
struct thermal_zone_device {
int id;
char type[THERMAL_NAME_LENGTH];
struct device device;
void *devdata;
int trips;
struct thermal_zone_device_ops *ops;
struct list_head cooling_devices;
struct idr idr;
struct mutex lock; /* protect cooling devices list */
struct list_head node;
};
struct thermal_zone_device *thermal_zone_device_register(char *, int, void *,
struct thermal_zone_device_ops *);
void thermal_zone_device_unregister(struct thermal_zone_device *);
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
struct thermal_cooling_device *thermal_cooling_device_register(char *, void *,
struct thermal_cooling_device_ops *);
void thermal_cooling_device_unregister(struct thermal_cooling_device *);
#endif /* __THERMAL_H__ */

View File

@ -538,7 +538,7 @@ skip:
initrd_end = 0; initrd_end = 0;
} }
static int __init populate_rootfs(void) int __init populate_rootfs(void)
{ {
char *err = unpack_to_rootfs(__initramfs_start, char *err = unpack_to_rootfs(__initramfs_start,
__initramfs_end - __initramfs_start, 0); __initramfs_end - __initramfs_start, 0);
@ -577,4 +577,10 @@ static int __init populate_rootfs(void)
} }
return 0; return 0;
} }
#ifndef CONFIG_ACPI_CUSTOM_DSDT_INITRD
/*
* if this option is enabled, populate_rootfs() is called _earlier_ in the
* boot sequence. This insures that the ACPI initialisation can find the file.
*/
rootfs_initcall(populate_rootfs); rootfs_initcall(populate_rootfs);
#endif

View File

@ -102,6 +102,12 @@ static inline void mark_rodata_ro(void) { }
extern void tc_init(void); extern void tc_init(void);
#endif #endif
#ifdef CONFIG_ACPI_CUSTOM_DSDT_INITRD
extern int populate_rootfs(void);
#else
static inline void populate_rootfs(void) {}
#endif
enum system_states system_state; enum system_states system_state;
EXPORT_SYMBOL(system_state); EXPORT_SYMBOL(system_state);
@ -648,6 +654,7 @@ asmlinkage void __init start_kernel(void)
check_bugs(); check_bugs();
populate_rootfs(); /* For DSDT override from initramfs */
acpi_early_init(); /* before LAPIC and SMP init */ acpi_early_init(); /* before LAPIC and SMP init */
/* Do the rest non-__init'ed, we're now alive */ /* Do the rest non-__init'ed, we're now alive */

View File

@ -161,7 +161,7 @@ const char *print_tainted(void)
{ {
static char buf[20]; static char buf[20];
if (tainted) { if (tainted) {
snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c", snprintf(buf, sizeof(buf), "Tainted: %c%c%c%c%c%c%c%c%c",
tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G', tainted & TAINT_PROPRIETARY_MODULE ? 'P' : 'G',
tainted & TAINT_FORCED_MODULE ? 'F' : ' ', tainted & TAINT_FORCED_MODULE ? 'F' : ' ',
tainted & TAINT_UNSAFE_SMP ? 'S' : ' ', tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
@ -169,7 +169,8 @@ const char *print_tainted(void)
tainted & TAINT_MACHINE_CHECK ? 'M' : ' ', tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
tainted & TAINT_BAD_PAGE ? 'B' : ' ', tainted & TAINT_BAD_PAGE ? 'B' : ' ',
tainted & TAINT_USER ? 'U' : ' ', tainted & TAINT_USER ? 'U' : ' ',
tainted & TAINT_DIE ? 'D' : ' '); tainted & TAINT_DIE ? 'D' : ' ',
tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ');
} }
else else
snprintf(buf, sizeof(buf), "Not tainted"); snprintf(buf, sizeof(buf), "Not tainted");

View File

@ -74,8 +74,8 @@ config PM_TRACE_RTC
RTC across reboots, so that you can debug a machine that just hangs RTC across reboots, so that you can debug a machine that just hangs
during suspend (or more commonly, during resume). during suspend (or more commonly, during resume).
To use this debugging feature you should attempt to suspend the machine, To use this debugging feature you should attempt to suspend the
then reboot it, then run machine, reboot it and then run
dmesg -s 1000000 | grep 'hash matches' dmesg -s 1000000 | grep 'hash matches'
@ -123,7 +123,10 @@ config HIBERNATION
called "hibernation" in user interfaces. STD checkpoints the called "hibernation" in user interfaces. STD checkpoints the
system and powers it off; and restores that checkpoint on reboot. system and powers it off; and restores that checkpoint on reboot.
You can suspend your machine with 'echo disk > /sys/power/state'. You can suspend your machine with 'echo disk > /sys/power/state'
after placing resume=/dev/swappartition on the kernel command line
in your bootloader's configuration file.
Alternatively, you can use the additional userland tools available Alternatively, you can use the additional userland tools available
from <http://suspend.sf.net>. from <http://suspend.sf.net>.