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:
commit
f0f1b3364a
95 changed files with 9213 additions and 2690 deletions
|
@ -14,6 +14,7 @@ Following translations are available on the WWW:
|
|||
- this file.
|
||||
ABI/
|
||||
- info on kernel <-> userspace ABI and relative interface stability.
|
||||
|
||||
BUG-HUNTING
|
||||
- brute force method of doing binary search of patches to find bug.
|
||||
Changes
|
||||
|
@ -66,6 +67,8 @@ VGA-softcursor.txt
|
|||
- how to change your VGA cursor from a blinking underscore.
|
||||
accounting/
|
||||
- documentation on accounting and taskstats.
|
||||
acpi/
|
||||
- info on ACPI-specific hooks in the kernel.
|
||||
aoe/
|
||||
- description of AoE (ATA over Ethernet) along with config examples.
|
||||
applying-patches.txt
|
||||
|
|
99
Documentation/ABI/testing/sysfs-firmware-acpi
Normal file
99
Documentation/ABI/testing/sysfs-firmware-acpi
Normal 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.
|
15
Documentation/acpi/dsdt-override.txt
Normal file
15
Documentation/acpi/dsdt-override.txt
Normal 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.
|
43
Documentation/acpi/initramfs-add-dsdt.sh
Executable file
43
Documentation/acpi/initramfs-add-dsdt.sh
Executable 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"
|
||||
|
26
Documentation/acpi/method-tracing.txt
Normal file
26
Documentation/acpi/method-tracing.txt
Normal 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".
|
|
@ -147,8 +147,10 @@ and is between 256 and 4096 characters. It is defined in the file
|
|||
default: 0
|
||||
|
||||
acpi_sleep= [HW,ACPI] Sleep options
|
||||
Format: { s3_bios, s3_mode }
|
||||
See Documentation/power/video.txt
|
||||
Format: { s3_bios, s3_mode, s3_beep }
|
||||
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
|
||||
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_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
|
||||
Format: To spoof as Windows 98: ="Microsoft Windows"
|
||||
|
||||
|
|
|
@ -386,6 +386,11 @@ before suspending; then remount them after resuming.
|
|||
There is a work-around for this problem. For more information, see
|
||||
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
|
||||
compiled with the similar configuration files. Anyway I found that
|
||||
suspend to disk (and resume) is much slower on 2.6.16 compared to
|
||||
|
|
246
Documentation/thermal/sysfs-api.txt
Normal file
246
Documentation/thermal/sysfs-api.txt
Normal 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
|
|
@ -1,7 +1,7 @@
|
|||
ThinkPad ACPI Extras Driver
|
||||
|
||||
Version 0.17
|
||||
October 04th, 2007
|
||||
Version 0.19
|
||||
January 06th, 2008
|
||||
|
||||
Borislav Deianov <borislav@users.sf.net>
|
||||
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 ...
|
||||
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:
|
||||
|
||||
hotkey_bios_enabled:
|
||||
|
@ -231,17 +236,26 @@ sysfs notes:
|
|||
to this value.
|
||||
|
||||
hotkey_enable:
|
||||
Enables/disables the hot keys feature, and reports
|
||||
current status of the hot keys feature.
|
||||
Enables/disables the hot keys feature in the ACPI
|
||||
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
|
||||
1: enables the hot keys feature / feature enabled
|
||||
|
||||
hotkey_mask:
|
||||
bit mask to enable driver-handling and ACPI event
|
||||
generation for each hot key (see above). Returns the
|
||||
current status of the hot keys mask, and allows one to
|
||||
modify it.
|
||||
bit mask to enable driver-handling (and depending on
|
||||
the firmware, ACPI event generation) for each hot key
|
||||
(see above). Returns the current status of the hot keys
|
||||
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:
|
||||
bit mask that should enable event reporting for all
|
||||
|
@ -257,12 +271,48 @@ sysfs notes:
|
|||
handled by the firmware anyway. Echo it to
|
||||
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:
|
||||
if the ThinkPad has a hardware radio switch, this
|
||||
attribute will read 0 if the switch is in the "radios
|
||||
disabled" postition, and 1 if the switch is in the
|
||||
"radios enabled" position.
|
||||
|
||||
This attribute has poll()/select() support.
|
||||
|
||||
hotkey_report_mode:
|
||||
Returns the state of the procfs ACPI event report mode
|
||||
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
|
||||
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:
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
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)
|
||||
compatibility. Moved all hwmon attributes to this
|
||||
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
|
||||
|
|
19
MAINTAINERS
19
MAINTAINERS
|
@ -202,6 +202,13 @@ L: linux-scsi@vger.kernel.org
|
|||
W: http://www.adaptec.com/
|
||||
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
|
||||
P: Len Brown
|
||||
M: len.brown@intel.com
|
||||
|
@ -252,6 +259,13 @@ L: linux-acpi@vger.kernel.org
|
|||
W: http://acpi.sourceforge.net/
|
||||
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
|
||||
P: Jean Delvare
|
||||
M: khali@linux-fr.org
|
||||
|
@ -1790,6 +1804,11 @@ P: Jaroslav Kysela
|
|||
M: perex@perex.cz
|
||||
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)
|
||||
P: Clemens Ladisch
|
||||
M: clemens@ladisch.de
|
||||
|
|
|
@ -45,6 +45,12 @@ static void init_intel_pdc(struct acpi_processor *pr)
|
|||
buf[0] = ACPI_PDC_REVISION_ID;
|
||||
buf[1] = 1;
|
||||
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->buffer.length = 12;
|
||||
|
|
|
@ -69,6 +69,20 @@ unsigned int acpi_cpei_phys_cpuid;
|
|||
|
||||
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 *
|
||||
acpi_get_sysname(void)
|
||||
{
|
||||
|
@ -152,7 +166,7 @@ int acpi_request_vector(u32 int_type)
|
|||
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);
|
||||
}
|
||||
|
@ -601,8 +615,6 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
|
|||
IOSAPIC_LEVEL);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_register_gsi);
|
||||
|
||||
void acpi_unregister_gsi(u32 gsi)
|
||||
{
|
||||
if (acpi_irq_model == ACPI_IRQ_MODEL_PLATFORM)
|
||||
|
@ -611,8 +623,6 @@ void acpi_unregister_gsi(u32 gsi)
|
|||
iosapic_unregister_intr(gsi);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_unregister_gsi);
|
||||
|
||||
static int __init acpi_parse_fadt(struct acpi_table_header *table)
|
||||
{
|
||||
struct acpi_table_header *fadt_header;
|
||||
|
@ -631,18 +641,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
|
|||
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)
|
||||
{
|
||||
|
||||
|
|
|
@ -105,6 +105,9 @@ config GENERIC_TIME_VSYSCALL
|
|||
bool
|
||||
default X86_64
|
||||
|
||||
config ARCH_HAS_CPU_RELAX
|
||||
def_bool y
|
||||
|
||||
config HAVE_SETUP_PER_CPU_AREA
|
||||
def_bool X86_64
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ int acpi_ht __initdata = 1; /* enable HT */
|
|||
int acpi_lapic;
|
||||
int acpi_ioapic;
|
||||
int acpi_strict;
|
||||
EXPORT_SYMBOL(acpi_strict);
|
||||
|
||||
u8 acpi_sci_flags __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
|
||||
|
||||
/* 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)
|
||||
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
|
||||
* 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;
|
||||
int idx;
|
||||
|
@ -490,8 +489,6 @@ int acpi_register_gsi(u32 gsi, int triggering, int polarity)
|
|||
return irq;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_register_gsi);
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
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)
|
||||
{
|
||||
struct acpi_table_boot *sb;
|
||||
|
@ -748,27 +726,6 @@ static int __init acpi_parse_fadt(struct acpi_table_header *table)
|
|||
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
|
||||
/*
|
||||
* Parse LAPIC entries in MADT
|
||||
|
|
|
@ -46,6 +46,12 @@ static void init_intel_pdc(struct acpi_processor *pr, struct cpuinfo_x86 *c)
|
|||
buf[1] = 1;
|
||||
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))
|
||||
buf[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP;
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
/* Multiplier. */
|
||||
if (c->x86_model < 2)
|
||||
mult = msr_lo >> 27;
|
||||
else
|
||||
mult = msr_lo >> 24;
|
||||
mult = msr_lo >> 24;
|
||||
|
||||
dprintk("P4 - FSB %u kHz; Multiplier %u; Speed %u kHz\n", fsb, mult, (fsb * mult));
|
||||
|
||||
|
|
|
@ -274,7 +274,7 @@ int __init get_memcfg_from_srat(void)
|
|||
int tables = 0;
|
||||
int i = 0;
|
||||
|
||||
rsdp_address = acpi_find_rsdp();
|
||||
rsdp_address = acpi_os_get_root_pointer();
|
||||
if (!rsdp_address) {
|
||||
printk("%s: System description tables not found\n",
|
||||
__FUNCTION__);
|
||||
|
|
|
@ -60,6 +60,8 @@ source "drivers/power/Kconfig"
|
|||
|
||||
source "drivers/hwmon/Kconfig"
|
||||
|
||||
source "drivers/thermal/Kconfig"
|
||||
|
||||
source "drivers/watchdog/Kconfig"
|
||||
|
||||
source "drivers/ssb/Kconfig"
|
||||
|
|
|
@ -65,6 +65,7 @@ obj-y += i2c/
|
|||
obj-$(CONFIG_W1) += w1/
|
||||
obj-$(CONFIG_POWER_SUPPLY) += power/
|
||||
obj-$(CONFIG_HWMON) += hwmon/
|
||||
obj-$(CONFIG_THERMAL) += thermal/
|
||||
obj-$(CONFIG_WATCHDOG) += watchdog/
|
||||
obj-$(CONFIG_PHONE) += telephony/
|
||||
obj-$(CONFIG_MD) += md/
|
||||
|
|
|
@ -68,26 +68,28 @@ config ACPI_PROCFS
|
|||
|
||||
Say N to delete /proc/acpi/ files that have moved to /sys/
|
||||
config ACPI_PROCFS_POWER
|
||||
bool "Deprecated power /proc/acpi folders"
|
||||
bool "Deprecated power /proc/acpi directories"
|
||||
depends on PROC_FS
|
||||
default y
|
||||
---help---
|
||||
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.
|
||||
The deprecated folders (and their replacements) include:
|
||||
The deprecated directories (and their replacements) include:
|
||||
/proc/acpi/battery/* (/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
|
||||
|
||||
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
|
||||
bool "Future power /sys interface"
|
||||
select POWER_SUPPLY
|
||||
default y
|
||||
---help---
|
||||
Say N to disable power /sys interface
|
||||
|
||||
config ACPI_PROC_EVENT
|
||||
bool "Deprecated /proc/acpi/event support"
|
||||
depends on PROC_FS
|
||||
|
@ -186,6 +188,7 @@ config ACPI_HOTPLUG_CPU
|
|||
config ACPI_THERMAL
|
||||
tristate "Thermal Zone"
|
||||
depends on ACPI_PROCESSOR
|
||||
select THERMAL
|
||||
default y
|
||||
help
|
||||
This driver adds support for ACPI thermal zones. Most mobile and
|
||||
|
@ -199,6 +202,16 @@ config ACPI_NUMA
|
|||
depends on (X86 || IA64)
|
||||
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
|
||||
tristate "ASUS/Medion Laptop Extras"
|
||||
depends on X86
|
||||
|
@ -263,8 +276,10 @@ config ACPI_CUSTOM_DSDT
|
|||
depends on !STANDALONE
|
||||
default n
|
||||
help
|
||||
This option is to load a custom ACPI DSDT
|
||||
If you don't know what that is, say N.
|
||||
This option supports a custom DSDT by linking it into the kernel.
|
||||
See Documentation/acpi/dsdt-override.txt
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config ACPI_CUSTOM_DSDT_FILE
|
||||
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
|
||||
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
|
||||
int "Disable ACPI for systems before Jan 1st this year" if X86_32
|
||||
default 0
|
||||
|
|
|
@ -55,6 +55,7 @@ obj-$(CONFIG_ACPI_THERMAL) += thermal.o
|
|||
obj-$(CONFIG_ACPI_SYSTEM) += system.o event.o
|
||||
obj-$(CONFIG_ACPI_DEBUG) += debug.o
|
||||
obj-$(CONFIG_ACPI_NUMA) += numa.o
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi.o
|
||||
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
|
||||
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
|
||||
obj-$(CONFIG_ACPI_HOTPLUG_MEMORY) += acpi_memhotplug.o
|
||||
|
|
|
@ -142,6 +142,7 @@ struct asus_hotk {
|
|||
xxN, //M2400N, M3700N, M5200N, M6800N, S1300N, S5200N
|
||||
A4S, //Z81sp
|
||||
//(Centrino)
|
||||
F3Sa,
|
||||
END_MODEL
|
||||
} model; //Models currently supported
|
||||
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",
|
||||
.mt_bt_switch = "BLED",
|
||||
.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;
|
||||
|
||||
if (hotk->model != L3H) {
|
||||
/* 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;
|
||||
} else { /* L3H and the like have to be handled differently */
|
||||
if (hotk->model == L3H) {
|
||||
/* L3H and the like have to be handled differently */
|
||||
acpi_status status = 0;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object mt_params[2];
|
||||
|
@ -745,6 +752,32 @@ static int get_lcd_state(void)
|
|||
if (out_obj.type == ACPI_TYPE_INTEGER)
|
||||
/* That's what the AML code does */
|
||||
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 = ¶m;
|
||||
|
||||
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);
|
||||
|
@ -1134,6 +1167,8 @@ static int asus_model_match(char *model)
|
|||
return W5A;
|
||||
else if (strncmp(model, "A4S", 3) == 0)
|
||||
return A4S;
|
||||
else if (strncmp(model, "F3Sa", 4) == 0)
|
||||
return F3Sa;
|
||||
else
|
||||
return END_MODEL;
|
||||
}
|
||||
|
|
|
@ -194,6 +194,9 @@ static int acpi_battery_get_property(struct power_supply *psy,
|
|||
case POWER_SUPPLY_PROP_MANUFACTURER:
|
||||
val->strval = battery->oem_info;
|
||||
break;
|
||||
case POWER_SUPPLY_PROP_SERIAL_NUMBER:
|
||||
val->strval = battery->serial_number;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -212,6 +215,7 @@ static enum power_supply_property charge_battery_props[] = {
|
|||
POWER_SUPPLY_PROP_CHARGE_NOW,
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SERIAL_NUMBER,
|
||||
};
|
||||
|
||||
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_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SERIAL_NUMBER,
|
||||
};
|
||||
#endif
|
||||
|
||||
|
|
|
@ -46,6 +46,12 @@ MODULE_LICENSE("GPL");
|
|||
printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
|
||||
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 {
|
||||
acpi_handle handle;
|
||||
char *name;
|
||||
|
@ -128,7 +134,7 @@ static ssize_t show_present(struct device *dev,
|
|||
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
|
||||
|
@ -144,7 +150,7 @@ static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
|
|||
eject_device(bay->handle);
|
||||
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
|
||||
|
|
|
@ -70,8 +70,6 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
|
|||
/* IBM 600E - _ADR should return 7, but it returns 1 */
|
||||
{"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
|
||||
"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."
|
||||
*
|
||||
* _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 5100"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5580"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 3010"),
|
||||
* _OSI(Linux) effect unknown:
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "Ferrari 5000"),
|
||||
*/
|
||||
{
|
||||
.callback = dmi_disable_osi_linux,
|
||||
.ident = "Acer, inc.",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Acer, inc."),
|
||||
},
|
||||
},
|
||||
/*
|
||||
* note that dmi_check_system() uses strstr()
|
||||
* to match sub-strings rather than !strcmp(),
|
||||
* so "Acer" below matches "Acer, inc." above.
|
||||
*/
|
||||
/*
|
||||
* Disable OSI(Linux) warnings on all "Acer"
|
||||
*
|
||||
* _OSI(Linux) effect unknown:
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 7720Z"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5520"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 6460"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 7510"),
|
||||
* 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",
|
||||
.matches = {
|
||||
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 Inc."
|
||||
*
|
||||
* _OSI(Linux) confirmed to be a NOP:
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook1,1"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBook2,1"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro2,2"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
|
||||
* _OSI(Linux) effect unknown:
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "MacPro2,1"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro1,1"),
|
||||
* DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro3,1"),
|
||||
*/
|
||||
{
|
||||
.callback = dmi_disable_osi_linux,
|
||||
.ident = "Apple",
|
||||
.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"),
|
||||
*/
|
||||
{
|
||||
.callback = dmi_unknown_osi_linux,
|
||||
.callback = dmi_disable_osi_linux,
|
||||
.ident = "Compal",
|
||||
.matches = {
|
||||
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,
|
||||
.ident = "Dell Dimension 5150",
|
||||
.matches = {
|
||||
|
@ -310,7 +311,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
|
|||
},
|
||||
{ /* OSI(Linux) is a NOP */
|
||||
.callback = dmi_disable_osi_linux,
|
||||
.ident = "Dell",
|
||||
.ident = "Dell i1501",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
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 */
|
||||
.callback = dmi_unknown_osi_linux,
|
||||
.ident = "Dell",
|
||||
.ident = "Dell Latitude D830",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
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 */
|
||||
.callback = dmi_unknown_osi_linux,
|
||||
.ident = "Dell",
|
||||
.ident = "Dell OP GX620",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
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 */
|
||||
.callback = dmi_unknown_osi_linux,
|
||||
.ident = "Dell",
|
||||
.ident = "Dell PE 1900",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
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 */
|
||||
.callback = dmi_disable_osi_linux,
|
||||
.ident = "Dell",
|
||||
.ident = "Dell PR 390",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
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 */
|
||||
.callback = dmi_unknown_osi_linux,
|
||||
.ident = "Dell",
|
||||
.ident = "Dell PE SC440",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
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:
|
||||
* 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,
|
||||
|
@ -516,7 +530,7 @@ static struct dmi_system_id acpi_osi_dmi_table[] __initdata = {
|
|||
* DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ11M"),
|
||||
*/
|
||||
{
|
||||
.callback = dmi_unknown_osi_linux,
|
||||
.callback = dmi_disable_osi_linux,
|
||||
.ident = "Sony",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
|
||||
|
|
|
@ -122,6 +122,31 @@ int acpi_bus_get_status(struct acpi_device *device)
|
|||
|
||||
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
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -366,7 +391,6 @@ int acpi_bus_receive_event(struct acpi_bus_event *event)
|
|||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_bus_receive_event);
|
||||
#endif /* CONFIG_ACPI_PROC_EVENT */
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
|
|
|
@ -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_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)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
|
|
@ -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,
|
||||
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)) {
|
||||
/*
|
||||
* Invalid address/length. We will emit an error message and mark
|
||||
|
|
|
@ -51,6 +51,12 @@ static struct atomic_notifier_head dock_notifier_list;
|
|||
static struct platform_device *dock_device;
|
||||
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 {
|
||||
acpi_handle handle;
|
||||
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));
|
||||
|
||||
}
|
||||
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
|
||||
|
@ -691,7 +697,7 @@ static ssize_t show_flags(struct device *dev,
|
|||
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
|
||||
|
@ -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);
|
||||
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
|
||||
|
@ -723,7 +729,7 @@ static ssize_t show_dock_uid(struct device *dev,
|
|||
|
||||
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
|
||||
|
|
|
@ -573,7 +573,7 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
|
|||
void *handler_context, void *region_context)
|
||||
{
|
||||
struct acpi_ec *ec = handler_context;
|
||||
int result = 0, i = 0;
|
||||
int result = 0, i;
|
||||
u8 temp = 0;
|
||||
|
||||
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)
|
||||
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) {
|
||||
result = acpi_ec_read(ec, address, &temp);
|
||||
(*value) |= ((acpi_integer)temp) << i;
|
||||
|
@ -593,10 +604,10 @@ acpi_ec_space_handler(u32 function, acpi_physical_address address,
|
|||
temp = 0xff & ((*value) >> i);
|
||||
result = acpi_ec_write(ec, address, temp);
|
||||
}
|
||||
i += 8;
|
||||
++address;
|
||||
}
|
||||
|
||||
acpi_ec_burst_disable(ec);
|
||||
|
||||
switch (result) {
|
||||
case -EINVAL:
|
||||
return AE_BAD_PARAMETER;
|
||||
|
|
|
@ -109,6 +109,34 @@ static const struct file_operations acpi_system_event_ops = {
|
|||
};
|
||||
#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
|
||||
static unsigned int acpi_event_seqnum;
|
||||
struct acpi_genl_event {
|
||||
|
|
|
@ -259,7 +259,7 @@ u32 acpi_ev_fixed_event_detect(void)
|
|||
enable_bit_mask)) {
|
||||
|
||||
/* Found an active (signalled) event */
|
||||
|
||||
acpi_os_fixed_event_count(i);
|
||||
int_status |= acpi_ev_fixed_event_dispatch((u32) i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -270,18 +270,18 @@ acpi_status acpi_ev_disable_gpe(struct acpi_gpe_event_info *gpe_event_info)
|
|||
case ACPI_GPE_TYPE_WAKE_RUN:
|
||||
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_WAKE_ENABLED);
|
||||
|
||||
/*lint -fallthrough */
|
||||
/* fallthrough */
|
||||
|
||||
case ACPI_GPE_TYPE_RUNTIME:
|
||||
|
||||
/* Disable the requested runtime GPE */
|
||||
|
||||
ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_RUN_ENABLED);
|
||||
status = acpi_hw_write_gpe_enable_reg(gpe_event_info);
|
||||
break;
|
||||
|
||||
/* fallthrough */
|
||||
|
||||
default:
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
acpi_hw_write_gpe_enable_reg(gpe_event_info);
|
||||
}
|
||||
|
||||
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.
|
||||
*
|
||||
******************************************************************************/
|
||||
static void acpi_ev_asynch_enable_gpe(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)));
|
||||
}
|
||||
}
|
||||
/* 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) {
|
||||
/*
|
||||
* GPE is level-triggered, we clear the GPE status bit after
|
||||
* handling the event.
|
||||
*/
|
||||
status = acpi_hw_clear_gpe(&local_gpe_event_info);
|
||||
status = acpi_hw_clear_gpe(gpe_event_info);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_VOID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable this GPE */
|
||||
|
||||
(void)acpi_hw_write_gpe_enable_reg(&local_gpe_event_info);
|
||||
(void)acpi_hw_write_gpe_enable_reg(gpe_event_info);
|
||||
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_gpe_count++;
|
||||
acpi_os_gpe_count(gpe_number);
|
||||
|
||||
/*
|
||||
* If edge-triggered, clear the GPE status bit now. Note that
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/thermal.h>
|
||||
#include <acpi/acpi_bus.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)
|
||||
-------------------------------------------------------------------------- */
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
|
||||
static struct proc_dir_entry *acpi_fan_dir;
|
||||
|
||||
|
@ -171,7 +217,17 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
|
|||
|
||||
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
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -179,9 +235,8 @@ static int acpi_fan_remove_fs(struct acpi_device *device)
|
|||
static int acpi_fan_add(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
struct acpi_fan *fan = NULL;
|
||||
int state = 0;
|
||||
|
||||
struct thermal_cooling_device *cdev;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
@ -199,6 +254,25 @@ static int acpi_fan_add(struct acpi_device *device)
|
|||
acpi_bus_set_power(device->handle, state);
|
||||
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);
|
||||
if (result)
|
||||
goto end;
|
||||
|
@ -208,18 +282,20 @@ static int acpi_fan_add(struct acpi_device *device)
|
|||
!device->power.state ? "on" : "off");
|
||||
|
||||
end:
|
||||
if (result)
|
||||
kfree(fan);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -261,10 +337,12 @@ static int __init acpi_fan_init(void)
|
|||
int result = 0;
|
||||
|
||||
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
acpi_fan_dir = proc_mkdir(ACPI_FAN_CLASS, acpi_root_dir);
|
||||
if (!acpi_fan_dir)
|
||||
return -ENODEV;
|
||||
acpi_fan_dir->owner = THIS_MODULE;
|
||||
#endif
|
||||
|
||||
result = acpi_bus_register_driver(&acpi_fan_driver);
|
||||
if (result < 0) {
|
||||
|
|
|
@ -36,8 +36,6 @@ int register_acpi_bus_type(struct acpi_bus_type *type)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(register_acpi_bus_type);
|
||||
|
||||
int unregister_acpi_bus_type(struct acpi_bus_type *type)
|
||||
{
|
||||
if (acpi_disabled)
|
||||
|
@ -53,8 +51,6 @@ int unregister_acpi_bus_type(struct acpi_bus_type *type)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(unregister_acpi_bus_type);
|
||||
|
||||
static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
|
||||
{
|
||||
struct acpi_bus_type *tmp, *ret = NULL;
|
||||
|
|
|
@ -286,13 +286,13 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
|
|||
}
|
||||
|
||||
/*
|
||||
* 1) Disable/Clear all GPEs
|
||||
* 2) Enable all wakeup GPEs
|
||||
*/
|
||||
status = acpi_hw_disable_all_gpes();
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
||||
acpi_gbl_system_awake_and_running = FALSE;
|
||||
|
||||
status = acpi_hw_enable_all_wakeup_gpes();
|
||||
|
|
|
@ -443,6 +443,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
|
|||
struct acpica_device_id hid;
|
||||
struct acpi_compatible_id_list *cid;
|
||||
acpi_native_uint i;
|
||||
int found;
|
||||
|
||||
status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
@ -496,16 +497,19 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
|
|||
|
||||
/* Walk the CID list */
|
||||
|
||||
found = 0;
|
||||
for (i = 0; i < cid->count; i++) {
|
||||
if (ACPI_STRNCMP(cid->id[i].value, info->hid,
|
||||
sizeof(struct
|
||||
acpi_compatible_id)) !=
|
||||
acpi_compatible_id)) ==
|
||||
0) {
|
||||
ACPI_FREE(cid);
|
||||
return (AE_OK);
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ACPI_FREE(cid);
|
||||
if (!found)
|
||||
return (AE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ int acpi_map_pxm_to_node(int pxm)
|
|||
return node;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void __cpuinit acpi_unmap_pxm_to_node(int 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_clear(node, nodes_found_map);
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
static void __init
|
||||
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));
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_get_pxm);
|
||||
|
||||
int acpi_get_node(acpi_handle *handle)
|
||||
{
|
||||
|
|
|
@ -44,6 +44,8 @@
|
|||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/efi.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
#define _COMPONENT ACPI_OS_SERVICES
|
||||
ACPI_MODULE_NAME("osl");
|
||||
|
@ -74,9 +76,25 @@ static void *acpi_irq_context;
|
|||
static struct workqueue_struct *kacpid_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 */
|
||||
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)"
|
||||
*
|
||||
|
@ -120,7 +138,7 @@ static char osi_additional_string[OSI_STRING_LENGTH_MAX];
|
|||
*/
|
||||
#define OSI_LINUX_ENABLE 0
|
||||
|
||||
struct osi_linux {
|
||||
static struct osi_linux {
|
||||
unsigned int enable:1;
|
||||
unsigned int dmi:1;
|
||||
unsigned int cmdline:1;
|
||||
|
@ -219,8 +237,6 @@ void acpi_os_printf(const char *fmt, ...)
|
|||
va_end(args);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_printf);
|
||||
|
||||
void acpi_os_vprintf(const char *fmt, va_list args)
|
||||
{
|
||||
static char buffer[512];
|
||||
|
@ -250,11 +266,16 @@ acpi_physical_address __init acpi_os_get_root_pointer(void)
|
|||
"System description tables not found\n");
|
||||
return 0;
|
||||
}
|
||||
} else
|
||||
return acpi_find_rsdp();
|
||||
} else {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
#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_os_table_override(struct acpi_table_header * existing_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)
|
||||
return AE_BAD_PARAMETER;
|
||||
|
||||
*new_table = NULL;
|
||||
|
||||
#ifdef CONFIG_ACPI_CUSTOM_DSDT
|
||||
if (strncmp(existing_table->signature, "DSDT", 4) == 0)
|
||||
*new_table = (struct acpi_table_header *)AmlCode;
|
||||
else
|
||||
*new_table = NULL;
|
||||
#else
|
||||
*new_table = NULL;
|
||||
#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;
|
||||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
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
|
||||
|
@ -341,6 +455,8 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
|
|||
{
|
||||
unsigned int irq;
|
||||
|
||||
acpi_irq_stats_init();
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -384,8 +500,6 @@ void acpi_os_sleep(acpi_integer ms)
|
|||
schedule_timeout_interruptible(msecs_to_jiffies(ms));
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_sleep);
|
||||
|
||||
void acpi_os_stall(u32 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
|
||||
* 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);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_read_pci_configuration);
|
||||
|
||||
acpi_status
|
||||
acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
|
||||
acpi_integer value, u32 width)
|
||||
|
@ -661,25 +771,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)
|
|||
dpc->function(dpc->context);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -703,7 +794,7 @@ acpi_status acpi_os_execute(acpi_execute_type type,
|
|||
{
|
||||
acpi_status status = AE_OK;
|
||||
struct acpi_os_dpc *dpc;
|
||||
|
||||
struct workqueue_struct *queue;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
|
||||
"Scheduling function [%p(%p)] for deferred execution.\n",
|
||||
function, context));
|
||||
|
@ -727,20 +818,13 @@ acpi_status acpi_os_execute(acpi_execute_type type,
|
|||
dpc->function = function;
|
||||
dpc->context = context;
|
||||
|
||||
if (type == OSL_NOTIFY_HANDLER) {
|
||||
INIT_WORK(&dpc->work, acpi_os_execute_notify);
|
||||
if (!queue_work(kacpi_notify_wq, &dpc->work)) {
|
||||
status = AE_ERROR;
|
||||
kfree(dpc);
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
}
|
||||
INIT_WORK(&dpc->work, acpi_os_execute_deferred);
|
||||
queue = (type == OSL_NOTIFY_HANDLER) ? kacpi_notify_wq : kacpid_wq;
|
||||
if (!queue_work(queue, &dpc->work)) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Call to queue_work() failed.\n"));
|
||||
status = AE_ERROR;
|
||||
kfree(dpc);
|
||||
}
|
||||
return_ACPI_STATUS(status);
|
||||
}
|
||||
|
@ -793,8 +877,6 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
|
|||
return AE_OK;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_create_semaphore);
|
||||
|
||||
/*
|
||||
* TODO: A better way to delete semaphores? Linux doesn't have a
|
||||
* 'delete_semaphore()' function -- may result in an invalid
|
||||
|
@ -818,8 +900,6 @@ acpi_status acpi_os_delete_semaphore(acpi_handle handle)
|
|||
return AE_OK;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_delete_semaphore);
|
||||
|
||||
/*
|
||||
* TODO: The kernel doesn't have a 'down_timeout' function -- had to
|
||||
* 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;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_wait_semaphore);
|
||||
|
||||
/*
|
||||
* TODO: Support for units > 1?
|
||||
*/
|
||||
|
@ -936,8 +1014,6 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
|
|||
return AE_OK;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_signal_semaphore);
|
||||
|
||||
#ifdef ACPI_FUTURE_USAGE
|
||||
u32 acpi_os_get_line(char *buffer)
|
||||
{
|
||||
|
@ -981,8 +1057,6 @@ acpi_status acpi_os_signal(u32 function, void *info)
|
|||
return AE_OK;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_os_signal);
|
||||
|
||||
static int __init acpi_os_name_setup(char *str)
|
||||
{
|
||||
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);
|
||||
|
||||
/* 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.
|
||||
*
|
||||
|
@ -1213,24 +1409,24 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
|
|||
*
|
||||
* Returns 0 on success
|
||||
*/
|
||||
int acpi_dmi_dump(void)
|
||||
static int acpi_dmi_dump(void)
|
||||
{
|
||||
|
||||
if (!dmi_available)
|
||||
return -1;
|
||||
|
||||
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",
|
||||
dmi_get_slot(DMI_PRODUCT_NAME));
|
||||
dmi_get_system_info(DMI_PRODUCT_NAME));
|
||||
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",
|
||||
dmi_get_slot(DMI_BOARD_NAME));
|
||||
dmi_get_system_info(DMI_BOARD_NAME));
|
||||
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",
|
||||
dmi_get_slot(DMI_BIOS_DATE));
|
||||
dmi_get_system_info(DMI_BIOS_DATE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1303,10 +1499,46 @@ acpi_status
|
|||
acpi_os_validate_address (
|
||||
u8 space_id,
|
||||
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
|
||||
|
|
|
@ -44,6 +44,8 @@ struct acpi_pci_data {
|
|||
struct pci_dev *dev;
|
||||
};
|
||||
|
||||
static int acpi_pci_unbind(struct acpi_device *device);
|
||||
|
||||
static void acpi_pci_data_handler(acpi_handle handle, u32 function,
|
||||
void *context)
|
||||
{
|
||||
|
@ -267,7 +269,7 @@ int acpi_pci_bind(struct acpi_device *device)
|
|||
return result;
|
||||
}
|
||||
|
||||
int acpi_pci_unbind(struct acpi_device *device)
|
||||
static int acpi_pci_unbind(struct acpi_device *device)
|
||||
{
|
||||
int result = 0;
|
||||
acpi_status status = AE_OK;
|
||||
|
|
|
@ -51,10 +51,8 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
|
|||
int bus,
|
||||
int device, int pin)
|
||||
{
|
||||
struct list_head *node = NULL;
|
||||
struct acpi_prt_entry *entry = NULL;
|
||||
|
||||
|
||||
if (!acpi_prt.count)
|
||||
return NULL;
|
||||
|
||||
|
@ -64,8 +62,7 @@ static struct acpi_prt_entry *acpi_pci_irq_find_prt_entry(int segment,
|
|||
*
|
||||
*/
|
||||
spin_lock(&acpi_prt_lock);
|
||||
list_for_each(node, &acpi_prt.entries) {
|
||||
entry = list_entry(node, struct acpi_prt_entry, node);
|
||||
list_for_each_entry(entry, &acpi_prt.entries, node) {
|
||||
if ((segment == entry->id.segment)
|
||||
&& (bus == entry->id.bus)
|
||||
&& (device == entry->id.device)
|
||||
|
@ -478,8 +475,6 @@ int acpi_pci_irq_enable(struct pci_dev *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(acpi_pci_irq_enable);
|
||||
|
||||
/* FIXME: implement x86/x86_64 version */
|
||||
void __attribute__ ((weak)) acpi_unregister_gsi(u32 i)
|
||||
{
|
||||
|
|
|
@ -95,7 +95,7 @@ static struct {
|
|||
int count;
|
||||
struct list_head entries;
|
||||
} acpi_link;
|
||||
DEFINE_MUTEX(acpi_link_lock);
|
||||
static DEFINE_MUTEX(acpi_link_lock);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
PCI Link Device Management
|
||||
|
|
|
@ -458,11 +458,9 @@ int acpi_power_transition(struct acpi_device *device, int state)
|
|||
}
|
||||
|
||||
end:
|
||||
if (result) {
|
||||
if (result)
|
||||
device->power.state = ACPI_STATE_UNKNOWN;
|
||||
printk(KERN_WARNING PREFIX "Transitioning device [%s] to D%d\n",
|
||||
device->pnp.bus_id, state);
|
||||
} else {
|
||||
else {
|
||||
/* We shouldn't change the state till all above operations succeed */
|
||||
device->power.state = state;
|
||||
}
|
||||
|
|
|
@ -668,6 +668,24 @@ static int __cpuinit acpi_processor_start(struct acpi_device *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) {
|
||||
printk(KERN_INFO PREFIX "%s [%s] (supports",
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
kfree(pr);
|
||||
|
@ -812,11 +835,18 @@ static int is_processor_present(acpi_handle handle)
|
|||
|
||||
|
||||
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"));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
/*
|
||||
* if a processor object does not have an _STA object,
|
||||
* OSPM assumes that the processor is present.
|
||||
*/
|
||||
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
|
||||
|
@ -1061,6 +1091,8 @@ static int __init acpi_processor_init(void)
|
|||
|
||||
acpi_processor_ppc_init();
|
||||
|
||||
acpi_processor_throttling_init();
|
||||
|
||||
return 0;
|
||||
|
||||
out_cpuidle:
|
||||
|
|
|
@ -98,6 +98,9 @@ module_param(bm_history, uint, 0644);
|
|||
|
||||
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
|
||||
|
||||
/*
|
||||
|
@ -201,6 +204,10 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 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)
|
||||
{
|
||||
current_thread_info()->status &= ~TS_POLLING;
|
||||
|
@ -261,7 +268,7 @@ static atomic_t c3_cpu_count;
|
|||
/* Common C-state entry for C2, C3, .. */
|
||||
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 */
|
||||
acpi_processor_ffh_cstate_enter(cstate);
|
||||
} else {
|
||||
|
@ -413,6 +420,8 @@ static void acpi_processor_idle(void)
|
|||
pm_idle_save();
|
||||
else
|
||||
acpi_safe_halt();
|
||||
|
||||
local_irq_enable();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -521,6 +530,7 @@ static void acpi_processor_idle(void)
|
|||
* skew otherwise.
|
||||
*/
|
||||
sleep_ticks = 0xFFFFFFFF;
|
||||
local_irq_enable();
|
||||
break;
|
||||
|
||||
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.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 (acpi_processor_ffh_cstate_probe
|
||||
(pr->id, &cx, reg) == 0) {
|
||||
cx.space_id = ACPI_CSTATE_FFH;
|
||||
} else if (cx.type != ACPI_STATE_C1) {
|
||||
cx.entry_method = ACPI_CSTATE_FFH;
|
||||
} else if (cx.type == ACPI_STATE_C1) {
|
||||
/*
|
||||
* C1 is a special case where FIXED_HARDWARE
|
||||
* can be handled in non-MWAIT way as well.
|
||||
* 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.
|
||||
*/
|
||||
cx.entry_method = ACPI_CSTATE_HALT;
|
||||
} else {
|
||||
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
|
||||
* @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)
|
||||
{
|
||||
if (cx->space_id == ACPI_CSTATE_FFH) {
|
||||
if (cx->entry_method == ACPI_CSTATE_FFH) {
|
||||
/* Call into architectural FFH based C-state */
|
||||
acpi_processor_ffh_cstate_enter(cx);
|
||||
} else if (cx->entry_method == ACPI_CSTATE_HALT) {
|
||||
acpi_safe_halt();
|
||||
} else {
|
||||
int unused;
|
||||
/* 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,
|
||||
struct cpuidle_state *state)
|
||||
{
|
||||
u32 t1, t2;
|
||||
struct acpi_processor *pr;
|
||||
struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
|
||||
|
||||
pr = processors[smp_processor_id()];
|
||||
|
||||
if (unlikely(!pr))
|
||||
return 0;
|
||||
|
||||
local_irq_disable();
|
||||
if (pr->flags.bm_check)
|
||||
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++;
|
||||
|
||||
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) {
|
||||
return dev->safe_state->enter(dev, dev->safe_state);
|
||||
} else {
|
||||
local_irq_disable();
|
||||
acpi_safe_halt();
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1609,7 +1631,7 @@ struct cpuidle_driver acpi_idle_driver = {
|
|||
*/
|
||||
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 cpuidle_state *state;
|
||||
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);
|
||||
state->exit_latency = cx->latency;
|
||||
state->target_residency = cx->latency * 6;
|
||||
state->target_residency = cx->latency * latency_factor;
|
||||
state->power_usage = cx->power;
|
||||
|
||||
state->flags = 0;
|
||||
switch (cx->type) {
|
||||
case ACPI_STATE_C1:
|
||||
state->flags |= CPUIDLE_FLAG_SHALLOW;
|
||||
state->flags |= CPUIDLE_FLAG_TIME_VALID;
|
||||
state->enter = acpi_idle_enter_c1;
|
||||
dev->safe_state = state;
|
||||
break;
|
||||
|
@ -1667,6 +1690,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
|
|||
}
|
||||
|
||||
count++;
|
||||
if (count == CPUIDLE_STATE_MAX)
|
||||
break;
|
||||
}
|
||||
|
||||
dev->state_count = count;
|
||||
|
|
|
@ -60,6 +60,11 @@ static DEFINE_MUTEX(performance_mutex);
|
|||
* 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_IN_USE 2
|
||||
|
||||
|
@ -72,6 +77,9 @@ static int acpi_processor_ppc_notifier(struct notifier_block *nb,
|
|||
struct acpi_processor *pr;
|
||||
unsigned int ppc = 0;
|
||||
|
||||
if (ignore_ppc)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&performance_mutex);
|
||||
|
||||
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 ret = acpi_processor_get_platform_limit(pr);
|
||||
int ret;
|
||||
|
||||
if (ignore_ppc)
|
||||
return 0;
|
||||
|
||||
ret = acpi_processor_get_platform_limit(pr);
|
||||
|
||||
if (ret < 0)
|
||||
return (ret);
|
||||
else
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/cpufreq.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/sysdev.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.
|
||||
*/
|
||||
|
||||
#define CPUFREQ_THERMAL_MIN_STEP 0
|
||||
#define CPUFREQ_THERMAL_MAX_STEP 3
|
||||
|
||||
static unsigned int cpufreq_thermal_reduction_pctg[NR_CPUS];
|
||||
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))
|
||||
return -ENODEV;
|
||||
|
||||
if (cpufreq_thermal_reduction_pctg[cpu] < 60) {
|
||||
cpufreq_thermal_reduction_pctg[cpu] += 20;
|
||||
if (cpufreq_thermal_reduction_pctg[cpu] <
|
||||
CPUFREQ_THERMAL_MAX_STEP) {
|
||||
cpufreq_thermal_reduction_pctg[cpu]++;
|
||||
cpufreq_update_policy(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
@ -123,8 +128,9 @@ static int acpi_thermal_cpufreq_decrease(unsigned int cpu)
|
|||
if (!cpu_has_cpufreq(cpu))
|
||||
return -ENODEV;
|
||||
|
||||
if (cpufreq_thermal_reduction_pctg[cpu] > 20)
|
||||
cpufreq_thermal_reduction_pctg[cpu] -= 20;
|
||||
if (cpufreq_thermal_reduction_pctg[cpu] >
|
||||
(CPUFREQ_THERMAL_MIN_STEP + 1))
|
||||
cpufreq_thermal_reduction_pctg[cpu]--;
|
||||
else
|
||||
cpufreq_thermal_reduction_pctg[cpu] = 0;
|
||||
cpufreq_update_policy(cpu);
|
||||
|
@ -143,7 +149,7 @@ static int acpi_thermal_cpufreq_notifier(struct notifier_block *nb,
|
|||
|
||||
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);
|
||||
|
||||
|
@ -155,6 +161,32 @@ static struct notifier_block acpi_thermal_cpufreq_notifier_block = {
|
|||
.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)
|
||||
{
|
||||
int i;
|
||||
|
@ -179,6 +211,20 @@ void acpi_thermal_cpufreq_exit(void)
|
|||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -310,6 +356,84 @@ int acpi_processor_get_limit_info(struct acpi_processor *pr)
|
|||
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 */
|
||||
|
||||
static int acpi_processor_limit_seq_show(struct seq_file *seq, void *offset)
|
||||
|
|
|
@ -45,9 +45,229 @@
|
|||
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
|
||||
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);
|
||||
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
|
||||
*/
|
||||
|
@ -293,6 +513,10 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
|
|||
struct acpi_buffer state = { 0, NULL };
|
||||
union acpi_object *tsd = NULL;
|
||||
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);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
@ -340,6 +564,22 @@ static int acpi_processor_get_tsd(struct acpi_processor *pr)
|
|||
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:
|
||||
kfree(buffer.pointer);
|
||||
return result;
|
||||
|
@ -589,6 +829,11 @@ static int acpi_processor_get_throttling(struct acpi_processor *pr)
|
|||
cpumask_t saved_mask;
|
||||
int ret;
|
||||
|
||||
if (!pr)
|
||||
return -EINVAL;
|
||||
|
||||
if (!pr->flags.throttling)
|
||||
return -ENODEV;
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
cpumask_t saved_mask;
|
||||
int ret;
|
||||
/*
|
||||
* Migrate task to the cpu pointed by pr.
|
||||
*/
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
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;
|
||||
set_cpus_allowed(current, cpumask_of_cpu(pr->id));
|
||||
ret = pr->throttling.acpi_processor_set_throttling(pr, state);
|
||||
t_state.target_state = 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 */
|
||||
set_cpus_allowed(current, saved_mask);
|
||||
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 result = 0;
|
||||
struct acpi_processor_throttling *pthrottling;
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"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_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.
|
||||
|
|
|
@ -888,7 +888,7 @@ static void acpi_charger_remove(struct acpi_sbs *sbs)
|
|||
#endif
|
||||
}
|
||||
|
||||
void acpi_sbs_callback(void *context)
|
||||
static void acpi_sbs_callback(void *context)
|
||||
{
|
||||
int id;
|
||||
struct acpi_sbs *sbs = context;
|
||||
|
|
|
@ -111,8 +111,8 @@ static int wait_transaction_complete(struct acpi_smb_hc *hc, int timeout)
|
|||
return -ETIME;
|
||||
}
|
||||
|
||||
int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol, u8 address,
|
||||
u8 command, u8 *data, u8 length)
|
||||
static int acpi_smbus_transaction(struct acpi_smb_hc *hc, u8 protocol,
|
||||
u8 address, u8 command, u8 *data, u8 length)
|
||||
{
|
||||
int ret = -EFAULT, i;
|
||||
u8 temp, sz = 0;
|
||||
|
|
|
@ -59,7 +59,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
|
|||
count = snprintf(&modalias[len], size, "%s:",
|
||||
cid_list->id[i].value);
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ static int acpi_device_register(struct acpi_device *device,
|
|||
device->dev.release = &acpi_device_release;
|
||||
result = device_add(&device->dev);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -941,6 +941,15 @@ static int acpi_bay_match(struct acpi_device *device){
|
|||
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,
|
||||
struct acpi_device *parent, acpi_handle handle,
|
||||
int type)
|
||||
|
@ -950,13 +959,14 @@ static void acpi_device_set_id(struct acpi_device *device,
|
|||
char *hid = NULL;
|
||||
char *uid = NULL;
|
||||
struct acpi_compatible_id_list *cid_list = NULL;
|
||||
const char *cid_add = NULL;
|
||||
acpi_status status;
|
||||
|
||||
switch (type) {
|
||||
case ACPI_BUS_TYPE_DEVICE:
|
||||
status = acpi_get_object_info(handle, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk("%s: Error reading device info\n", __FUNCTION__);
|
||||
printk(KERN_ERR PREFIX "%s: Error reading device info\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -972,15 +982,18 @@ static void acpi_device_set_id(struct acpi_device *device,
|
|||
device->flags.bus_address = 1;
|
||||
}
|
||||
|
||||
if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
|
||||
status = acpi_video_bus_match(device);
|
||||
if(ACPI_SUCCESS(status))
|
||||
hid = ACPI_VIDEO_HID;
|
||||
/* If we have a video/bay/dock device, add our selfdefined
|
||||
HID to the CID list. Like that the video/bay/dock drivers
|
||||
will get autoloaded and the device might still match
|
||||
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;
|
||||
case ACPI_BUS_TYPE_POWER:
|
||||
hid = ACPI_POWER_HID;
|
||||
|
@ -1021,12 +1034,45 @@ static void acpi_device_set_id(struct acpi_device *device,
|
|||
strcpy(device->pnp.unique_id, uid);
|
||||
device->flags.unique_id = 1;
|
||||
}
|
||||
if (cid_list) {
|
||||
device->pnp.cid_list = kmalloc(cid_list->size, GFP_KERNEL);
|
||||
if (device->pnp.cid_list)
|
||||
memcpy(device->pnp.cid_list, cid_list, cid_list->size);
|
||||
else
|
||||
printk(KERN_ERR "Memory allocation error\n");
|
||||
if (cid_list || cid_add) {
|
||||
struct acpi_compatible_id_list *list;
|
||||
int size = 0;
|
||||
int count = 0;
|
||||
|
||||
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);
|
||||
|
@ -1050,7 +1096,7 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
|
|||
acpi_bus_data_handler, device);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk("Error attaching device data\n");
|
||||
printk(KERN_ERR PREFIX "Error attaching device data\n");
|
||||
result = -ENODEV;
|
||||
}
|
||||
}
|
||||
|
@ -1080,6 +1126,20 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
|
|||
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
|
||||
acpi_add_single_object(struct acpi_device **child,
|
||||
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_DEVICE:
|
||||
result = acpi_bus_get_status(device);
|
||||
if (ACPI_FAILURE(result) || !device->status.present) {
|
||||
result = -ENOENT;
|
||||
if (ACPI_FAILURE(result)) {
|
||||
result = -ENODEV;
|
||||
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;
|
||||
default:
|
||||
STRUCT_TO_INT(device->status) =
|
||||
|
|
|
@ -170,7 +170,7 @@ static int acpi_pm_enter(suspend_state_t pm_state)
|
|||
/* Reprogram control registers and execute _BFS */
|
||||
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
|
||||
* 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 ||
|
||||
(wake && adev->wakeup.state.enabled &&
|
||||
adev->wakeup.sleep_state <= acpi_target_sleep_state)) {
|
||||
acpi_status status;
|
||||
|
||||
acpi_method[3] = 'W';
|
||||
acpi_evaluate_integer(handle, acpi_method, NULL, &d_max);
|
||||
/* Sanity check */
|
||||
if (d_max < d_min)
|
||||
status = acpi_evaluate_integer(handle, acpi_method, NULL,
|
||||
&d_max);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (d_min_p)
|
||||
|
|
|
@ -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
|
||||
* string won't have one, but is still valid.
|
||||
*/
|
||||
if (*p == NULL)
|
||||
return result;
|
||||
|
||||
next = strpbrk(*p, "- :");
|
||||
if (next)
|
||||
*next++ = '\0';
|
||||
|
@ -190,6 +193,8 @@ static int get_date_field(char **p, u32 * value)
|
|||
|
||||
if (next)
|
||||
*p = next;
|
||||
else
|
||||
*p = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -251,27 +256,6 @@ acpi_system_write_alarm(struct file *file,
|
|||
if ((result = get_date_field(&p, &sec)))
|
||||
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);
|
||||
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
|
@ -288,24 +272,24 @@ acpi_system_write_alarm(struct file *file,
|
|||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
if (sec > 59) {
|
||||
min++;
|
||||
sec -= 60;
|
||||
min += sec/60;
|
||||
sec = sec%60;
|
||||
}
|
||||
if (min > 59) {
|
||||
hr++;
|
||||
min -= 60;
|
||||
hr += min/60;
|
||||
min = min%60;
|
||||
}
|
||||
if (hr > 23) {
|
||||
day++;
|
||||
hr -= 24;
|
||||
day += hr/24;
|
||||
hr = hr%24;
|
||||
}
|
||||
if (day > 31) {
|
||||
mo++;
|
||||
day -= 31;
|
||||
mo += day/32;
|
||||
day = day%32;
|
||||
}
|
||||
if (mo > 12) {
|
||||
yr++;
|
||||
mo -= 12;
|
||||
yr += mo/13;
|
||||
mo = mo%13;
|
||||
}
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
|
|
|
@ -40,6 +40,8 @@ ACPI_MODULE_NAME("system");
|
|||
#define ACPI_SYSTEM_CLASS "system"
|
||||
#define ACPI_SYSTEM_DEVICE_NAME "System"
|
||||
|
||||
u32 acpi_irq_handled;
|
||||
|
||||
/*
|
||||
* Make ACPICA version work as module param
|
||||
*/
|
||||
|
@ -166,6 +168,212 @@ static int acpi_system_sysfs_init(void)
|
|||
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)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
|
|
@ -2,6 +2,6 @@
|
|||
# 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)
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
@ -219,8 +219,6 @@ acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
|
|||
return_ACPI_STATUS(AE_NOT_FOUND);
|
||||
}
|
||||
|
||||
ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_tb_scan_memory_for_rsdp
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <linux/thermal.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
|
@ -65,9 +65,6 @@
|
|||
#define ACPI_THERMAL_MAX_ACTIVE 10
|
||||
#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
|
||||
ACPI_MODULE_NAME("thermal");
|
||||
|
||||
|
@ -195,6 +192,8 @@ struct acpi_thermal {
|
|||
struct acpi_thermal_trips trips;
|
||||
struct acpi_handle_list devices;
|
||||
struct timer_list timer;
|
||||
struct thermal_zone_device *thermal_zone;
|
||||
int tz_enabled;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
|
@ -321,178 +320,226 @@ static int acpi_thermal_set_cooling_mode(struct acpi_thermal *tz, int mode)
|
|||
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;
|
||||
int i = 0;
|
||||
|
||||
|
||||
if (!tz)
|
||||
return -EINVAL;
|
||||
struct acpi_handle_list devices;
|
||||
int valid = 0;
|
||||
int i;
|
||||
|
||||
/* Critical Shutdown (required) */
|
||||
|
||||
status = acpi_evaluate_integer(tz->device->handle, "_CRT", NULL,
|
||||
&tz->trips.critical.temperature);
|
||||
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) {
|
||||
if (flag & ACPI_TRIPS_CRITICAL) {
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
"_CRT", NULL, &tz->trips.critical.temperature);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
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;
|
||||
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;
|
||||
} 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) */
|
||||
|
||||
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 {
|
||||
if (flag & ACPI_TRIPS_HOT) {
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
"_PSV", NULL, &tz->trips.passive.temperature);
|
||||
}
|
||||
|
||||
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
|
||||
"_HOT", NULL, &tz->trips.hot.temperature);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
tz->trips.hot.flags.valid = 0;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Found passive threshold [%lu]\n",
|
||||
tz->trips.passive.temperature));
|
||||
"No hot threshold\n"));
|
||||
} 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++) {
|
||||
|
||||
char name[5] = { '_', 'A', 'C', ('0' + i), '\0' };
|
||||
valid = tz->trips.active[i].flags.valid;
|
||||
|
||||
if (act == -1)
|
||||
break; /* disable all active trip points */
|
||||
break; /* disable all active trip points */
|
||||
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
name, NULL, &tz->trips.active[i].temperature);
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
if (i == 0) /* no active trip points */
|
||||
if (flag & ACPI_TRIPS_ACTIVE) {
|
||||
status = acpi_evaluate_integer(tz->device->handle,
|
||||
name, NULL, &tz->trips.active[i].temperature);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
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;
|
||||
if (act <= 0) /* no override requested */
|
||||
break;
|
||||
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;
|
||||
} else
|
||||
tz->trips.active[i].flags.valid = 1;
|
||||
}
|
||||
|
||||
name[2] = 'L';
|
||||
status =
|
||||
acpi_evaluate_reference(tz->device->handle, name, NULL,
|
||||
&tz->trips.active[i].devices);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
tz->trips.active[i].flags.valid = 1;
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Found active threshold [%d]:[%lu]\n",
|
||||
i, tz->trips.active[i].temperature));
|
||||
} else
|
||||
ACPI_EXCEPTION((AE_INFO, status,
|
||||
"Invalid active threshold [%d]", i));
|
||||
if ((flag & ACPI_TRIPS_DEVICES) && tz->trips.active[i].flags.valid ) {
|
||||
memset(&devices, 0, sizeof(struct acpi_handle_list));
|
||||
status = acpi_evaluate_reference(tz->device->handle,
|
||||
name, NULL, &devices);
|
||||
if (ACPI_FAILURE(status))
|
||||
tz->trips.active[i].flags.valid = 0;
|
||||
else
|
||||
tz->trips.active[i].flags.valid = 1;
|
||||
|
||||
if (memcmp(&tz->trips.active[i].devices, &devices,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
if (!tz)
|
||||
return -EINVAL;
|
||||
|
||||
status =
|
||||
acpi_evaluate_reference(tz->device->handle, "_TZD", NULL, &tz->devices);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
return acpi_thermal_trips_update(tz, ACPI_TRIPS_INIT);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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)
|
||||
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,
|
||||
tz->trips.critical.flags.enabled);
|
||||
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,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (tz->temperature >= tz->trips.hot.temperature) {
|
||||
|
@ -534,7 +584,7 @@ static int acpi_thermal_hot(struct acpi_thermal *tz)
|
|||
ACPI_THERMAL_NOTIFY_HOT,
|
||||
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;
|
||||
}
|
||||
|
@ -732,6 +782,9 @@ static void acpi_thermal_check(void *data)
|
|||
if (result)
|
||||
goto unlock;
|
||||
|
||||
if (!tz->tz_enabled)
|
||||
goto unlock;
|
||||
|
||||
memset(&tz->state, 0, sizeof(tz->state));
|
||||
|
||||
/*
|
||||
|
@ -825,6 +878,290 @@ static void acpi_thermal_check(void *data)
|
|||
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)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -1181,15 +1518,15 @@ static void acpi_thermal_notify(acpi_handle handle, u32 event, void *data)
|
|||
acpi_thermal_check(tz);
|
||||
break;
|
||||
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_bus_generate_proc_event(device, event, 0);
|
||||
acpi_bus_generate_netlink_event(device->pnp.device_class,
|
||||
device->dev.bus_id, event, 0);
|
||||
break;
|
||||
case ACPI_THERMAL_NOTIFY_DEVICES:
|
||||
if (tz->flags.devices)
|
||||
acpi_thermal_get_devices(tz);
|
||||
acpi_thermal_trips_update(tz, ACPI_TRIPS_REFRESH_DEVICES);
|
||||
acpi_thermal_check(tz);
|
||||
acpi_bus_generate_proc_event(device, event, 0);
|
||||
acpi_bus_generate_netlink_event(device->pnp.device_class,
|
||||
device->dev.bus_id, event, 0);
|
||||
|
@ -1232,11 +1569,6 @@ static int acpi_thermal_get_info(struct acpi_thermal *tz)
|
|||
else
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1260,13 +1592,19 @@ static int acpi_thermal_add(struct acpi_device *device)
|
|||
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
|
||||
acpi_driver_data(device) = tz;
|
||||
mutex_init(&tz->lock);
|
||||
|
||||
|
||||
result = acpi_thermal_get_info(tz);
|
||||
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);
|
||||
if (result)
|
||||
goto end;
|
||||
goto unregister_thermal_zone;
|
||||
|
||||
init_timer(&tz->timer);
|
||||
|
||||
|
@ -1277,19 +1615,21 @@ static int acpi_thermal_add(struct acpi_device *device)
|
|||
acpi_thermal_notify, tz);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
result = -ENODEV;
|
||||
goto end;
|
||||
goto remove_fs;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
|
||||
acpi_device_name(device), acpi_device_bid(device),
|
||||
KELVIN_TO_CELSIUS(tz->temperature));
|
||||
goto end;
|
||||
|
||||
end:
|
||||
if (result) {
|
||||
acpi_thermal_remove_fs(device);
|
||||
kfree(tz);
|
||||
}
|
||||
|
||||
remove_fs:
|
||||
acpi_thermal_remove_fs(device);
|
||||
unregister_thermal_zone:
|
||||
thermal_zone_device_unregister(tz->thermal_zone);
|
||||
free_memory:
|
||||
kfree(tz);
|
||||
end:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1329,6 +1669,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
|
|||
}
|
||||
|
||||
acpi_thermal_remove_fs(device);
|
||||
acpi_thermal_unregister_thermal_zone(tz);
|
||||
mutex_destroy(&tz->lock);
|
||||
kfree(tz);
|
||||
return 0;
|
||||
|
|
|
@ -671,7 +671,6 @@ void acpi_ut_init_globals(void)
|
|||
|
||||
/* GPE support */
|
||||
|
||||
acpi_gpe_count = 0;
|
||||
acpi_gbl_gpe_xrupt_list_head = NULL;
|
||||
acpi_gbl_gpe_fadt_blocks[0] = 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_layer)
|
||||
ACPI_EXPORT_SYMBOL(acpi_gpe_count)
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/video_output.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -72,8 +73,12 @@ MODULE_AUTHOR("Bruno Ducrot");
|
|||
MODULE_DESCRIPTION("ACPI Video Driver");
|
||||
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_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[] = {
|
||||
{ACPI_VIDEO_HID, 0},
|
||||
|
@ -88,6 +93,7 @@ static struct acpi_driver acpi_video_bus = {
|
|||
.ops = {
|
||||
.add = acpi_video_bus_add,
|
||||
.remove = acpi_video_bus_remove,
|
||||
.resume = acpi_video_resume,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -179,6 +185,7 @@ struct acpi_video_device {
|
|||
struct acpi_device *dev;
|
||||
struct acpi_video_device_brightness *brightness;
|
||||
struct backlight_device *backlight;
|
||||
struct thermal_cooling_device *cdev;
|
||||
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,
|
||||
struct acpi_video_device *device);
|
||||
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,
|
||||
int level);
|
||||
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)
|
||||
{
|
||||
unsigned long cur_level;
|
||||
int i;
|
||||
struct acpi_video_device *vd =
|
||||
(struct acpi_video_device *)bl_get_data(bd);
|
||||
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)
|
||||
{
|
||||
int request_level = bd->props.brightness;
|
||||
int request_level = bd->props.brightness+2;
|
||||
struct acpi_video_device *vd =
|
||||
(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;
|
||||
}
|
||||
|
||||
|
@ -334,6 +348,54 @@ static struct output_properties acpi_output_properties = {
|
|||
.set_state = acpi_video_output_set,
|
||||
.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
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -652,7 +714,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
|||
kfree(obj);
|
||||
|
||||
if (device->cap._BCL && device->cap._BCM && device->cap._BQC && max_level > 0){
|
||||
unsigned long tmp;
|
||||
int result;
|
||||
static int count = 0;
|
||||
char *name;
|
||||
name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
|
||||
|
@ -660,14 +722,30 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
|||
return;
|
||||
|
||||
sprintf(name, "acpi_video%d", count++);
|
||||
acpi_video_device_lcd_get_level_current(device, &tmp);
|
||||
device->backlight = backlight_device_register(name,
|
||||
NULL, device, &acpi_backlight_ops);
|
||||
device->backlight->props.max_brightness = max_level;
|
||||
device->backlight->props.brightness = (int)tmp;
|
||||
device->backlight->props.max_brightness = device->brightness->count-3;
|
||||
device->backlight->props.brightness = acpi_video_get_brightness(device->backlight);
|
||||
backlight_update_status(device->backlight);
|
||||
|
||||
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){
|
||||
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)
|
||||
{
|
||||
acpi_status status = -ENOENT;
|
||||
|
||||
long device_id;
|
||||
struct device *dev;
|
||||
struct acpi_device *device;
|
||||
|
||||
if (!video)
|
||||
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
|
||||
* 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)
|
||||
{
|
||||
long device_id;
|
||||
int status;
|
||||
struct proc_dir_entry *entry = NULL;
|
||||
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);
|
||||
|
@ -1580,64 +1716,6 @@ static int acpi_video_device_enumerate(struct acpi_video_bus *video)
|
|||
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
|
||||
acpi_video_get_next_level(struct acpi_video_device *device,
|
||||
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_video_device_notify);
|
||||
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);
|
||||
|
||||
return 0;
|
||||
|
@ -1797,23 +1883,19 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
|
|||
* connector. */
|
||||
acpi_video_device_enumerate(video);
|
||||
acpi_video_device_rebind(video);
|
||||
acpi_video_switch_output(video, event);
|
||||
acpi_bus_generate_proc_event(device, event, 0);
|
||||
keycode = KEY_SWITCHVIDEOMODE;
|
||||
break;
|
||||
|
||||
case ACPI_VIDEO_NOTIFY_CYCLE: /* Cycle Display output hotkey pressed. */
|
||||
acpi_video_switch_output(video, event);
|
||||
acpi_bus_generate_proc_event(device, event, 0);
|
||||
keycode = KEY_SWITCHVIDEOMODE;
|
||||
break;
|
||||
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);
|
||||
keycode = KEY_VIDEO_NEXT;
|
||||
break;
|
||||
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);
|
||||
keycode = KEY_VIDEO_PREV;
|
||||
break;
|
||||
|
@ -1825,6 +1907,7 @@ static void acpi_video_bus_notify(acpi_handle handle, u32 event, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
acpi_notifier_call_chain(device, event, 0);
|
||||
input_report_key(input, keycode, 1);
|
||||
input_sync(input);
|
||||
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) {
|
||||
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);
|
||||
keycode = KEY_BRIGHTNESS_CYCLE;
|
||||
break;
|
||||
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);
|
||||
keycode = KEY_BRIGHTNESSUP;
|
||||
break;
|
||||
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);
|
||||
keycode = KEY_BRIGHTNESSDOWN;
|
||||
break;
|
||||
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);
|
||||
keycode = KEY_BRIGHTNESS_ZERO;
|
||||
break;
|
||||
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);
|
||||
keycode = KEY_DISPLAY_OFF;
|
||||
break;
|
||||
|
@ -1881,6 +1969,7 @@ static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data)
|
|||
break;
|
||||
}
|
||||
|
||||
acpi_notifier_call_chain(device, event, 0);
|
||||
input_report_key(input, keycode, 1);
|
||||
input_sync(input);
|
||||
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 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)
|
||||
{
|
||||
acpi_status status;
|
||||
|
|
710
drivers/acpi/wmi.c
Normal file
710
drivers/acpi/wmi.c
Normal 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);
|
|
@ -1,13 +1,13 @@
|
|||
|
||||
config CPU_IDLE
|
||||
bool "CPU idle PM support"
|
||||
default ACPI
|
||||
help
|
||||
CPU idle is a generic framework for supporting software-controlled
|
||||
idle processor power management. It includes modular cross-platform
|
||||
governors that can be swapped during runtime.
|
||||
|
||||
If you're using a mobile platform that supports CPU idle PM (e.g.
|
||||
an ACPI-capable notebook), you should say Y here.
|
||||
If you're using an ACPI-enabled platform, you should say Y here.
|
||||
|
||||
config CPU_IDLE_GOV_LADDER
|
||||
bool
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/pm_qos_params.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpuidle.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#include "cpuidle.h"
|
||||
|
||||
|
@ -180,6 +181,44 @@ void cpuidle_disable_device(struct cpuidle_device *dev)
|
|||
|
||||
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
|
||||
* @dev: the cpu
|
||||
|
@ -198,6 +237,8 @@ int cpuidle_register_device(struct cpuidle_device *dev)
|
|||
|
||||
mutex_lock(&cpuidle_lock);
|
||||
|
||||
poll_idle_init(dev);
|
||||
|
||||
per_cpu(cpuidle_devices, dev->cpu) = dev;
|
||||
list_add(&dev->device_list, &cpuidle_detected_devices);
|
||||
if ((ret = cpuidle_add_sysfs(sys_dev))) {
|
||||
|
|
|
@ -489,12 +489,3 @@ int dmi_get_year(int field)
|
|||
|
||||
return year;
|
||||
}
|
||||
|
||||
/**
|
||||
* dmi_get_slot - return dmi_ident[slot]
|
||||
* @slot: index into dmi_ident[]
|
||||
*/
|
||||
char *dmi_get_slot(int slot)
|
||||
{
|
||||
return(dmi_ident[slot]);
|
||||
}
|
||||
|
|
|
@ -92,6 +92,22 @@ config TIFM_7XX1
|
|||
To compile this driver as a module, choose M here: the module will
|
||||
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
|
||||
tristate "Asus Laptop Extras (EXPERIMENTAL)"
|
||||
depends on X86
|
||||
|
@ -126,6 +142,15 @@ config FUJITSU_LAPTOP
|
|||
|
||||
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
|
||||
tristate "MSI Laptop Extras"
|
||||
depends on X86
|
||||
|
@ -219,6 +244,25 @@ config THINKPAD_ACPI_BAY
|
|||
|
||||
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
|
||||
tristate "Device driver for Atmel SSC peripheral"
|
||||
|
@ -232,4 +276,13 @@ config ATMEL_SSC
|
|||
|
||||
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
|
||||
|
|
|
@ -6,8 +6,10 @@ obj- := misc.o # Dummy rule to force built-in.o to be made
|
|||
obj-$(CONFIG_IBM_ASM) += ibmasm/
|
||||
obj-$(CONFIG_HDPU_FEATURES) += hdpuftrs/
|
||||
obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o
|
||||
obj-$(CONFIG_ACER_WMI) += acer-wmi.o
|
||||
obj-$(CONFIG_ASUS_LAPTOP) += asus-laptop.o
|
||||
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
|
||||
obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
|
||||
obj-$(CONFIG_LKDTM) += lkdtm.o
|
||||
obj-$(CONFIG_TIFM_CORE) += tifm_core.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_FUJITSU_LAPTOP) += fujitsu-laptop.o
|
||||
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
|
||||
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
|
||||
|
|
1109
drivers/misc/acer-wmi.c
Normal file
1109
drivers/misc/acer-wmi.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -254,7 +254,7 @@ ASUS_LED(gled, "gaming");
|
|||
* 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
|
||||
*
|
||||
* 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,
|
||||
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
|
||||
acpi_status status;
|
||||
|
||||
if (!handle)
|
||||
return 0;
|
||||
|
||||
params.count = 1;
|
||||
params.pointer = &in_obj;
|
||||
in_obj.type = ACPI_TYPE_INTEGER;
|
||||
in_obj.integer.value = val;
|
||||
|
||||
status = acpi_evaluate_object(handle, (char *)method, ¶ms, output);
|
||||
return (status == AE_OK);
|
||||
if (status == AE_OK)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int read_wireless_status(int mask)
|
||||
|
@ -321,7 +327,7 @@ static void write_status(acpi_handle handle, int out, int mask)
|
|||
|
||||
switch (mask) {
|
||||
case MLED_ON:
|
||||
out = !out & 0x1;
|
||||
out = !(out & 0x1);
|
||||
break;
|
||||
case GLED_ON:
|
||||
out = (out & 0x1) + 1;
|
||||
|
@ -335,7 +341,7 @@ static void write_status(acpi_handle handle, int out, int mask)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -415,7 +421,7 @@ static int set_brightness(struct backlight_device *bd, int value)
|
|||
value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
|
||||
/* 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");
|
||||
ret = -EIO;
|
||||
}
|
||||
|
@ -545,7 +551,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
|
|||
|
||||
rv = parse_arg(buf, count, &value);
|
||||
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");
|
||||
else
|
||||
hotk->ledd_status = (u32) value;
|
||||
|
@ -590,7 +596,7 @@ static ssize_t store_bluetooth(struct device *dev,
|
|||
static void set_display(int value)
|
||||
{
|
||||
/* 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");
|
||||
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)
|
||||
{
|
||||
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");
|
||||
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)
|
||||
{
|
||||
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");
|
||||
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");
|
||||
|
||||
/* 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");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
526
drivers/misc/intel_menlow.c
Normal file
526
drivers/misc/intel_menlow.c
Normal 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);
|
|
@ -73,7 +73,7 @@
|
|||
if (debug) printk(KERN_WARNING DRV_PFX msg); \
|
||||
} 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_HID "SNY5001"
|
||||
|
@ -146,68 +146,70 @@ struct sony_laptop_keypress {
|
|||
* and input layer indexes in the keymap
|
||||
*/
|
||||
static int sony_laptop_input_index[] = {
|
||||
-1, /* no event */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_DOWN */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_UP */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_UP_PRESSED */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_PRESSED */
|
||||
-1, /* SONYPI_EVENT_JOGDIAL_RELEASED */
|
||||
0, /* SONYPI_EVENT_CAPTURE_PRESSED */
|
||||
1, /* SONYPI_EVENT_CAPTURE_RELEASED */
|
||||
2, /* SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
|
||||
3, /* SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
|
||||
4, /* SONYPI_EVENT_FNKEY_ESC */
|
||||
5, /* SONYPI_EVENT_FNKEY_F1 */
|
||||
6, /* SONYPI_EVENT_FNKEY_F2 */
|
||||
7, /* SONYPI_EVENT_FNKEY_F3 */
|
||||
8, /* SONYPI_EVENT_FNKEY_F4 */
|
||||
9, /* SONYPI_EVENT_FNKEY_F5 */
|
||||
10, /* SONYPI_EVENT_FNKEY_F6 */
|
||||
11, /* SONYPI_EVENT_FNKEY_F7 */
|
||||
12, /* SONYPI_EVENT_FNKEY_F8 */
|
||||
13, /* SONYPI_EVENT_FNKEY_F9 */
|
||||
14, /* SONYPI_EVENT_FNKEY_F10 */
|
||||
15, /* SONYPI_EVENT_FNKEY_F11 */
|
||||
16, /* SONYPI_EVENT_FNKEY_F12 */
|
||||
17, /* SONYPI_EVENT_FNKEY_1 */
|
||||
18, /* SONYPI_EVENT_FNKEY_2 */
|
||||
19, /* SONYPI_EVENT_FNKEY_D */
|
||||
20, /* SONYPI_EVENT_FNKEY_E */
|
||||
21, /* SONYPI_EVENT_FNKEY_F */
|
||||
22, /* SONYPI_EVENT_FNKEY_S */
|
||||
23, /* SONYPI_EVENT_FNKEY_B */
|
||||
24, /* SONYPI_EVENT_BLUETOOTH_PRESSED */
|
||||
25, /* SONYPI_EVENT_PKEY_P1 */
|
||||
26, /* SONYPI_EVENT_PKEY_P2 */
|
||||
27, /* SONYPI_EVENT_PKEY_P3 */
|
||||
28, /* SONYPI_EVENT_BACK_PRESSED */
|
||||
-1, /* SONYPI_EVENT_LID_CLOSED */
|
||||
-1, /* SONYPI_EVENT_LID_OPENED */
|
||||
29, /* SONYPI_EVENT_BLUETOOTH_ON */
|
||||
30, /* SONYPI_EVENT_BLUETOOTH_OFF */
|
||||
31, /* SONYPI_EVENT_HELP_PRESSED */
|
||||
32, /* SONYPI_EVENT_FNKEY_ONLY */
|
||||
33, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN */
|
||||
34, /* SONYPI_EVENT_JOGDIAL_FAST_UP */
|
||||
35, /* SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
|
||||
36, /* SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
|
||||
37, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
|
||||
38, /* SONYPI_EVENT_JOGDIAL_VFAST_UP */
|
||||
39, /* SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
|
||||
40, /* SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
|
||||
41, /* SONYPI_EVENT_ZOOM_PRESSED */
|
||||
42, /* SONYPI_EVENT_THUMBPHRASE_PRESSED */
|
||||
43, /* SONYPI_EVENT_MEYE_FACE */
|
||||
44, /* SONYPI_EVENT_MEYE_OPPOSITE */
|
||||
45, /* SONYPI_EVENT_MEMORYSTICK_INSERT */
|
||||
46, /* SONYPI_EVENT_MEMORYSTICK_EJECT */
|
||||
-1, /* SONYPI_EVENT_ANYBUTTON_RELEASED */
|
||||
-1, /* SONYPI_EVENT_BATTERY_INSERT */
|
||||
-1, /* SONYPI_EVENT_BATTERY_REMOVE */
|
||||
-1, /* SONYPI_EVENT_FNKEY_RELEASED */
|
||||
47, /* SONYPI_EVENT_WIRELESS_ON */
|
||||
48, /* SONYPI_EVENT_WIRELESS_OFF */
|
||||
-1, /* 0 no event */
|
||||
-1, /* 1 SONYPI_EVENT_JOGDIAL_DOWN */
|
||||
-1, /* 2 SONYPI_EVENT_JOGDIAL_UP */
|
||||
-1, /* 3 SONYPI_EVENT_JOGDIAL_DOWN_PRESSED */
|
||||
-1, /* 4 SONYPI_EVENT_JOGDIAL_UP_PRESSED */
|
||||
-1, /* 5 SONYPI_EVENT_JOGDIAL_PRESSED */
|
||||
-1, /* 6 SONYPI_EVENT_JOGDIAL_RELEASED */
|
||||
0, /* 7 SONYPI_EVENT_CAPTURE_PRESSED */
|
||||
1, /* 8 SONYPI_EVENT_CAPTURE_RELEASED */
|
||||
2, /* 9 SONYPI_EVENT_CAPTURE_PARTIALPRESSED */
|
||||
3, /* 10 SONYPI_EVENT_CAPTURE_PARTIALRELEASED */
|
||||
4, /* 11 SONYPI_EVENT_FNKEY_ESC */
|
||||
5, /* 12 SONYPI_EVENT_FNKEY_F1 */
|
||||
6, /* 13 SONYPI_EVENT_FNKEY_F2 */
|
||||
7, /* 14 SONYPI_EVENT_FNKEY_F3 */
|
||||
8, /* 15 SONYPI_EVENT_FNKEY_F4 */
|
||||
9, /* 16 SONYPI_EVENT_FNKEY_F5 */
|
||||
10, /* 17 SONYPI_EVENT_FNKEY_F6 */
|
||||
11, /* 18 SONYPI_EVENT_FNKEY_F7 */
|
||||
12, /* 19 SONYPI_EVENT_FNKEY_F8 */
|
||||
13, /* 20 SONYPI_EVENT_FNKEY_F9 */
|
||||
14, /* 21 SONYPI_EVENT_FNKEY_F10 */
|
||||
15, /* 22 SONYPI_EVENT_FNKEY_F11 */
|
||||
16, /* 23 SONYPI_EVENT_FNKEY_F12 */
|
||||
17, /* 24 SONYPI_EVENT_FNKEY_1 */
|
||||
18, /* 25 SONYPI_EVENT_FNKEY_2 */
|
||||
19, /* 26 SONYPI_EVENT_FNKEY_D */
|
||||
20, /* 27 SONYPI_EVENT_FNKEY_E */
|
||||
21, /* 28 SONYPI_EVENT_FNKEY_F */
|
||||
22, /* 29 SONYPI_EVENT_FNKEY_S */
|
||||
23, /* 30 SONYPI_EVENT_FNKEY_B */
|
||||
24, /* 31 SONYPI_EVENT_BLUETOOTH_PRESSED */
|
||||
25, /* 32 SONYPI_EVENT_PKEY_P1 */
|
||||
26, /* 33 SONYPI_EVENT_PKEY_P2 */
|
||||
27, /* 34 SONYPI_EVENT_PKEY_P3 */
|
||||
28, /* 35 SONYPI_EVENT_BACK_PRESSED */
|
||||
-1, /* 36 SONYPI_EVENT_LID_CLOSED */
|
||||
-1, /* 37 SONYPI_EVENT_LID_OPENED */
|
||||
29, /* 38 SONYPI_EVENT_BLUETOOTH_ON */
|
||||
30, /* 39 SONYPI_EVENT_BLUETOOTH_OFF */
|
||||
31, /* 40 SONYPI_EVENT_HELP_PRESSED */
|
||||
32, /* 41 SONYPI_EVENT_FNKEY_ONLY */
|
||||
33, /* 42 SONYPI_EVENT_JOGDIAL_FAST_DOWN */
|
||||
34, /* 43 SONYPI_EVENT_JOGDIAL_FAST_UP */
|
||||
35, /* 44 SONYPI_EVENT_JOGDIAL_FAST_DOWN_PRESSED */
|
||||
36, /* 45 SONYPI_EVENT_JOGDIAL_FAST_UP_PRESSED */
|
||||
37, /* 46 SONYPI_EVENT_JOGDIAL_VFAST_DOWN */
|
||||
38, /* 47 SONYPI_EVENT_JOGDIAL_VFAST_UP */
|
||||
39, /* 48 SONYPI_EVENT_JOGDIAL_VFAST_DOWN_PRESSED */
|
||||
40, /* 49 SONYPI_EVENT_JOGDIAL_VFAST_UP_PRESSED */
|
||||
41, /* 50 SONYPI_EVENT_ZOOM_PRESSED */
|
||||
42, /* 51 SONYPI_EVENT_THUMBPHRASE_PRESSED */
|
||||
43, /* 52 SONYPI_EVENT_MEYE_FACE */
|
||||
44, /* 53 SONYPI_EVENT_MEYE_OPPOSITE */
|
||||
45, /* 54 SONYPI_EVENT_MEMORYSTICK_INSERT */
|
||||
46, /* 55 SONYPI_EVENT_MEMORYSTICK_EJECT */
|
||||
-1, /* 56 SONYPI_EVENT_ANYBUTTON_RELEASED */
|
||||
-1, /* 57 SONYPI_EVENT_BATTERY_INSERT */
|
||||
-1, /* 58 SONYPI_EVENT_BATTERY_REMOVE */
|
||||
-1, /* 59 SONYPI_EVENT_FNKEY_RELEASED */
|
||||
47, /* 60 SONYPI_EVENT_WIRELESS_ON */
|
||||
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[] = {
|
||||
|
@ -260,6 +262,8 @@ static int sony_laptop_input_keycode_map[] = {
|
|||
KEY_RESERVED, /* 46 SONYPI_EVENT_MEMORYSTICK_EJECT */
|
||||
KEY_WLAN, /* 47 SONYPI_EVENT_WIRELESS_ON */
|
||||
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 */
|
||||
|
@ -311,7 +315,7 @@ static void sony_laptop_report_input_event(u8 event)
|
|||
break;
|
||||
|
||||
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);
|
||||
break;
|
||||
}
|
||||
|
@ -875,6 +879,15 @@ static const struct dmi_system_id sony_nc_ids[] = {
|
|||
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_TYPE2 0x00000002
|
||||
#define SONYPI_DEVICE_TYPE3 0x00000004
|
||||
#define SONYPI_DEVICE_TYPE4 0x00000008
|
||||
|
||||
#define SONYPI_TYPE1_OFFSET 0x04
|
||||
#define SONYPI_TYPE2_OFFSET 0x12
|
||||
#define SONYPI_TYPE3_OFFSET 0x12
|
||||
#define SONYPI_TYPE4_OFFSET 0x12
|
||||
|
||||
struct sony_pic_ioport {
|
||||
struct acpi_resource_io io1;
|
||||
|
@ -1185,18 +1200,33 @@ struct sony_pic_irq {
|
|||
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 {
|
||||
int model;
|
||||
u16 evport_offset;
|
||||
u8 camera_power;
|
||||
u8 bluetooth_power;
|
||||
u8 wwan_power;
|
||||
struct device_ctrl *control;
|
||||
struct acpi_device *acpi_dev;
|
||||
struct sony_pic_irq *cur_irq;
|
||||
struct sony_pic_ioport *cur_ioport;
|
||||
struct list_head interrupts;
|
||||
struct list_head ioports;
|
||||
struct mutex lock;
|
||||
u8 camera_power;
|
||||
u8 bluetooth_power;
|
||||
u8 wwan_power;
|
||||
};
|
||||
|
||||
static struct sony_pic_dev spic_dev = {
|
||||
|
@ -1253,6 +1283,7 @@ static struct sonypi_event sonypi_joggerev[] = {
|
|||
static struct sonypi_event sonypi_captureev[] = {
|
||||
{ 0x05, SONYPI_EVENT_CAPTURE_PARTIALPRESSED },
|
||||
{ 0x07, SONYPI_EVENT_CAPTURE_PRESSED },
|
||||
{ 0x40, SONYPI_EVENT_CAPTURE_PRESSED },
|
||||
{ 0x01, SONYPI_EVENT_CAPTURE_PARTIALRELEASED },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
@ -1289,7 +1320,6 @@ static struct sonypi_event sonypi_pkeyev[] = {
|
|||
{ 0x01, SONYPI_EVENT_PKEY_P1 },
|
||||
{ 0x02, SONYPI_EVENT_PKEY_P2 },
|
||||
{ 0x04, SONYPI_EVENT_PKEY_P3 },
|
||||
{ 0x5c, SONYPI_EVENT_PKEY_P1 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -1331,6 +1361,8 @@ static struct sonypi_event sonypi_lidev[] = {
|
|||
/* The set of possible zoom events */
|
||||
static struct sonypi_event sonypi_zoomev[] = {
|
||||
{ 0x39, SONYPI_EVENT_ZOOM_PRESSED },
|
||||
{ 0x10, SONYPI_EVENT_ZOOM_IN_PRESSED },
|
||||
{ 0x20, SONYPI_EVENT_ZOOM_OUT_PRESSED },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
@ -1361,76 +1393,58 @@ static struct sonypi_event sonypi_batteryev[] = {
|
|||
{ 0, 0 }
|
||||
};
|
||||
|
||||
static struct sonypi_eventtypes {
|
||||
int model;
|
||||
u8 data;
|
||||
unsigned long mask;
|
||||
struct sonypi_event * events;
|
||||
} sony_pic_eventtypes[] = {
|
||||
{ SONYPI_DEVICE_TYPE1, 0, 0xffffffff, sonypi_releaseev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_LID_MASK, sonypi_lidev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
||||
{ SONYPI_DEVICE_TYPE1, 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
||||
|
||||
{ SONYPI_DEVICE_TYPE2, 0, 0xffffffff, sonypi_releaseev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x38, SONYPI_LID_MASK, sonypi_lidev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x11, SONYPI_BACK_MASK, sonypi_backev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_HELP_MASK, sonypi_helpev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
||||
{ SONYPI_DEVICE_TYPE2, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
|
||||
{ SONYPI_DEVICE_TYPE3, 0, 0xffffffff, sonypi_releaseev },
|
||||
{ SONYPI_DEVICE_TYPE3, 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
||||
{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_WIRELESS_MASK, sonypi_wlessev },
|
||||
{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
||||
{ SONYPI_DEVICE_TYPE3, 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
||||
{ SONYPI_DEVICE_TYPE3, 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
{ 0 }
|
||||
static struct sonypi_eventtypes type1_events[] = {
|
||||
{ 0, 0xffffffff, sonypi_releaseev },
|
||||
{ 0x70, SONYPI_MEYE_MASK, sonypi_meyeev },
|
||||
{ 0x30, SONYPI_LID_MASK, sonypi_lidev },
|
||||
{ 0x60, SONYPI_CAPTURE_MASK, sonypi_captureev },
|
||||
{ 0x10, SONYPI_JOGGER_MASK, sonypi_joggerev },
|
||||
{ 0x20, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
||||
{ 0x30, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
|
||||
{ 0x40, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
{ 0x30, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
||||
{ 0x40, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
||||
{ 0 },
|
||||
};
|
||||
static struct sonypi_eventtypes type2_events[] = {
|
||||
{ 0, 0xffffffff, sonypi_releaseev },
|
||||
{ 0x38, SONYPI_LID_MASK, sonypi_lidev },
|
||||
{ 0x11, SONYPI_JOGGER_MASK, sonypi_joggerev },
|
||||
{ 0x61, SONYPI_CAPTURE_MASK, sonypi_captureev },
|
||||
{ 0x21, SONYPI_FNKEY_MASK, sonypi_fnkeyev },
|
||||
{ 0x31, SONYPI_BLUETOOTH_MASK, sonypi_blueev },
|
||||
{ 0x08, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
{ 0x11, SONYPI_BACK_MASK, sonypi_backev },
|
||||
{ 0x21, SONYPI_HELP_MASK, sonypi_helpev },
|
||||
{ 0x21, SONYPI_ZOOM_MASK, sonypi_zoomev },
|
||||
{ 0x20, SONYPI_THUMBPHRASE_MASK, sonypi_thumbphraseev },
|
||||
{ 0x31, SONYPI_MEMORYSTICK_MASK, sonypi_memorystickev },
|
||||
{ 0x41, SONYPI_BATTERY_MASK, sonypi_batteryev },
|
||||
{ 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
{ 0 },
|
||||
};
|
||||
static struct sonypi_eventtypes type3_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 },
|
||||
{ 0x31, SONYPI_PKEY_MASK, sonypi_pkeyev },
|
||||
{ 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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/* low level spic calls */
|
||||
#define ITERATIONS_LONG 10000
|
||||
#define ITERATIONS_SHORT 10
|
||||
#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);
|
||||
v1 = inb_p(spic_dev.cur_ioport->io1.minimum + 4);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1466,7 +1480,7 @@ static u8 sony_pic_call2(u8 dev, u8 fn)
|
|||
ITERATIONS_LONG);
|
||||
outb(fn, 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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
outb(v, 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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
#define SONYPI_CAMERA_PICTURE 5
|
||||
#define SONYPI_CAMERA_CONTROL 0x10
|
||||
|
@ -2253,7 +2362,7 @@ static int sony_pic_enable(struct acpi_device *device,
|
|||
buffer.pointer = resource;
|
||||
|
||||
/* setup Type 1 resources */
|
||||
if (spic_dev.model == SONYPI_DEVICE_TYPE1) {
|
||||
if (spic_dev.control->model == SONYPI_DEVICE_TYPE1) {
|
||||
|
||||
/* setup io resources */
|
||||
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)
|
||||
data_mask = inb_p(dev->cur_ioport->io2.minimum);
|
||||
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",
|
||||
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)
|
||||
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;
|
||||
|
||||
if ((data_mask & sony_pic_eventtypes[i].data) !=
|
||||
sony_pic_eventtypes[i].data)
|
||||
if (!(mask & dev->control->event_types[i].mask))
|
||||
continue;
|
||||
|
||||
if (!(mask & sony_pic_eventtypes[i].mask))
|
||||
continue;
|
||||
|
||||
for (j = 0; sony_pic_eventtypes[i].events[j].event; j++) {
|
||||
if (ev == sony_pic_eventtypes[i].events[j].data) {
|
||||
for (j = 0; dev->control->event_types[i].events[j].event; j++) {
|
||||
if (ev == dev->control->event_types[i].events[j].data) {
|
||||
device_event =
|
||||
sony_pic_eventtypes[i].events[j].event;
|
||||
dev->control->
|
||||
event_types[i].events[j].event;
|
||||
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;
|
||||
|
||||
found:
|
||||
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);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
|
@ -2429,23 +2548,9 @@ static int sony_pic_add(struct acpi_device *device)
|
|||
|
||||
spic_dev.acpi_dev = device;
|
||||
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);
|
||||
|
||||
/* model specific characteristics */
|
||||
switch(spic_dev.model) {
|
||||
case SONYPI_DEVICE_TYPE1:
|
||||
spic_dev.evport_offset = SONYPI_TYPE1_OFFSET;
|
||||
break;
|
||||
case SONYPI_DEVICE_TYPE3:
|
||||
spic_dev.evport_offset = SONYPI_TYPE3_OFFSET;
|
||||
break;
|
||||
case SONYPI_DEVICE_TYPE2:
|
||||
default:
|
||||
spic_dev.evport_offset = SONYPI_TYPE2_OFFSET;
|
||||
break;
|
||||
}
|
||||
|
||||
/* read _PRS resources */
|
||||
result = sony_pic_possible_resources(device);
|
||||
if (result) {
|
||||
|
|
290
drivers/misc/tc1100-wmi.c
Normal file
290
drivers/misc/tc1100-wmi.c
Normal 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
|
@ -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 */
|
|
@ -183,7 +183,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
|
|||
if (ACPI_SUCCESS(status))
|
||||
dev->capabilities |= PNP_CONFIGURABLE;
|
||||
dev->capabilities |= PNP_READ;
|
||||
if (device->flags.dynamic_status)
|
||||
if (device->flags.dynamic_status && (dev->capabilities & PNP_CONFIGURABLE))
|
||||
dev->capabilities |= PNP_WRITE;
|
||||
if (device->flags.removable)
|
||||
dev->capabilities |= PNP_REMOVABLE;
|
||||
|
|
|
@ -115,6 +115,7 @@ static struct device_attribute power_supply_attrs[] = {
|
|||
/* Properties of type `const char *' */
|
||||
POWER_SUPPLY_ATTR(model_name),
|
||||
POWER_SUPPLY_ATTR(manufacturer),
|
||||
POWER_SUPPLY_ATTR(serial_number),
|
||||
};
|
||||
|
||||
static ssize_t power_supply_show_static_attrs(struct device *dev,
|
||||
|
|
15
drivers/thermal/Kconfig
Normal file
15
drivers/thermal/Kconfig
Normal 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
5
drivers/thermal/Makefile
Normal file
|
@ -0,0 +1,5 @@
|
|||
#
|
||||
# Makefile for sensor chip drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_THERMAL) += thermal.o
|
714
drivers/thermal/thermal.c
Normal file
714
drivers/thermal/thermal.c
Normal 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);
|
|
@ -117,10 +117,6 @@ extern u32 acpi_dbg_layer;
|
|||
|
||||
extern u32 acpi_gbl_nesting_level;
|
||||
|
||||
/* Event counters */
|
||||
|
||||
ACPI_EXTERN u32 acpi_gpe_count;
|
||||
|
||||
/* Support for dynamic control method tracing mechanism */
|
||||
|
||||
ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
|
||||
|
|
|
@ -486,7 +486,7 @@
|
|||
#define ACPI_FUNCTION_NAME(name)
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG_FUNC_TRACE
|
||||
#ifdef CONFIG_ACPI_DEBUG_FUNC_TRACE
|
||||
|
||||
#define ACPI_FUNCTION_TRACE(a) ACPI_FUNCTION_NAME(a) \
|
||||
acpi_ut_trace(ACPI_DEBUG_PARAMETERS)
|
||||
|
@ -565,7 +565,7 @@
|
|||
|
||||
#endif /* ACPI_SIMPLE_RETURN_MACROS */
|
||||
|
||||
#else /* !DEBUG_FUNC_TRACE */
|
||||
#else /* !CONFIG_ACPI_DEBUG_FUNC_TRACE */
|
||||
|
||||
#define ACPI_FUNCTION_TRACE(a)
|
||||
#define ACPI_FUNCTION_TRACE_PTR(a,b)
|
||||
|
@ -584,7 +584,7 @@
|
|||
#define return_UINT32(s) return(s)
|
||||
#define return_PTR(s) return(s)
|
||||
|
||||
#endif /* DEBUG_FUNC_TRACE */
|
||||
#endif /* CONFIG_ACPI_DEBUG_FUNC_TRACE */
|
||||
|
||||
/* Conditional execution */
|
||||
|
||||
|
|
|
@ -321,6 +321,11 @@ struct acpi_bus_event {
|
|||
|
||||
extern struct kobject *acpi_kobj;
|
||||
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
|
||||
*/
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#define ACPI_BUTTON_HID_SLEEPF "LNXSLPBN"
|
||||
#define ACPI_VIDEO_HID "LNXVIDEO"
|
||||
#define ACPI_BAY_HID "LNXIOBAY"
|
||||
#define ACPI_DOCK_HID "LNXDOCK"
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
PCI
|
||||
|
@ -73,7 +74,6 @@ struct pci_bus;
|
|||
|
||||
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_unbind(struct acpi_device *device);
|
||||
int acpi_pci_bind_root(struct acpi_device *device, struct acpi_pci_id *id,
|
||||
struct pci_bus *bus);
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ extern int pxm_to_node(int);
|
|||
extern int node_to_pxm(int);
|
||||
extern void __acpi_map_pxm_to_node(int, int);
|
||||
extern int acpi_map_pxm_to_node(int);
|
||||
extern void __cpuinit acpi_unmap_pxm_to_node(int);
|
||||
|
||||
#endif /* CONFIG_ACPI_NUMA */
|
||||
#endif /* __ACP_NUMA_H */
|
||||
|
|
|
@ -181,6 +181,9 @@ acpi_os_install_interrupt_handler(u32 gsi,
|
|||
acpi_status
|
||||
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
|
||||
*/
|
||||
|
@ -239,8 +242,8 @@ acpi_status acpi_os_validate_interface(char *interface);
|
|||
acpi_status acpi_osi_invalidate(char* interface);
|
||||
|
||||
acpi_status
|
||||
acpi_os_validate_address(u8 space_id,
|
||||
acpi_physical_address address, acpi_size length);
|
||||
acpi_os_validate_address(u8 space_id, acpi_physical_address address,
|
||||
acpi_size length, char *name);
|
||||
|
||||
u64 acpi_os_get_timer(void);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpuidle.h>
|
||||
|
||||
#include <linux/thermal.h>
|
||||
#include <asm/acpi.h>
|
||||
|
||||
#define ACPI_PROCESSOR_BUSY_METRIC 10
|
||||
|
@ -34,6 +34,7 @@
|
|||
|
||||
#define ACPI_CSTATE_SYSTEMIO (0)
|
||||
#define ACPI_CSTATE_FFH (1)
|
||||
#define ACPI_CSTATE_HALT (2)
|
||||
|
||||
/* Power Management */
|
||||
|
||||
|
@ -64,7 +65,7 @@ struct acpi_processor_cx {
|
|||
u8 valid;
|
||||
u8 type;
|
||||
u32 address;
|
||||
u8 space_id;
|
||||
u8 entry_method;
|
||||
u8 index;
|
||||
u32 latency;
|
||||
u32 latency_ticks;
|
||||
|
@ -176,6 +177,8 @@ struct acpi_processor_throttling {
|
|||
u32 address;
|
||||
u8 duty_offset;
|
||||
u8 duty_width;
|
||||
u8 tsd_valid_flag;
|
||||
unsigned int shared_type;
|
||||
struct acpi_processor_tx states[ACPI_PROCESSOR_MAX_THROTTLING];
|
||||
};
|
||||
|
||||
|
@ -218,7 +221,7 @@ struct acpi_processor {
|
|||
struct acpi_processor_performance *performance;
|
||||
struct acpi_processor_throttling throttling;
|
||||
struct acpi_processor_limit limit;
|
||||
|
||||
struct thermal_cooling_device *cdev;
|
||||
/* the _PDC objects for this processor, if any */
|
||||
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);
|
||||
extern int acpi_processor_set_throttling(struct acpi_processor *pr, int state);
|
||||
extern struct file_operations acpi_processor_throttling_fops;
|
||||
|
||||
extern void acpi_processor_throttling_init(void);
|
||||
/* in processor_idle.c */
|
||||
int acpi_processor_power_init(struct acpi_processor *pr,
|
||||
struct acpi_device *device);
|
||||
|
@ -330,7 +333,7 @@ extern struct cpuidle_driver acpi_idle_driver;
|
|||
/* in processor_thermal.c */
|
||||
int acpi_processor_get_limit_info(struct acpi_processor *pr);
|
||||
extern struct file_operations acpi_processor_limit_fops;
|
||||
|
||||
extern struct thermal_cooling_device_ops processor_cooling_ops;
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
void acpi_thermal_cpufreq_init(void);
|
||||
void acpi_thermal_cpufreq_exit(void);
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef _LINUX_ACPI_H
|
||||
#define _LINUX_ACPI_H
|
||||
|
||||
#include <linux/ioport.h> /* for struct resource */
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
|
@ -43,8 +44,6 @@
|
|||
#include <linux/dmi.h>
|
||||
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
enum acpi_irq_model_id {
|
||||
ACPI_IRQ_MODEL_PIC = 0,
|
||||
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);
|
||||
|
||||
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_table_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_unregister_ioapic(acpi_handle handle, u32 gsi_base);
|
||||
|
||||
extern int acpi_mp_config;
|
||||
void acpi_irq_stats_init(void);
|
||||
extern u32 acpi_irq_handled;
|
||||
|
||||
extern struct acpi_mcfg_allocation *pci_mmcfg_config;
|
||||
extern int pci_mmcfg_config_num;
|
||||
|
@ -124,12 +122,6 @@ extern int pci_mmcfg_config_num;
|
|||
extern int sbf_port;
|
||||
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_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);
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
||||
struct acpi_prt_entry {
|
||||
struct list_head node;
|
||||
struct acpi_pci_id id;
|
||||
|
@ -179,8 +169,6 @@ struct acpi_pci_driver {
|
|||
int acpi_pci_register_driver(struct acpi_pci_driver *driver);
|
||||
void acpi_pci_unregister_driver(struct acpi_pci_driver *driver);
|
||||
|
||||
#endif /* CONFIG_ACPI */
|
||||
|
||||
#ifdef CONFIG_ACPI_EC
|
||||
|
||||
extern int ec_read(u8 addr, u8 *val);
|
||||
|
@ -192,6 +180,26 @@ extern int ec_transaction(u8 command,
|
|||
|
||||
#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);
|
||||
#ifdef CONFIG_DMI
|
||||
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 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 */
|
||||
|
||||
static inline int acpi_boot_init(void)
|
||||
|
@ -229,5 +244,22 @@ static inline int acpi_boot_table_init(void)
|
|||
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 /*_LINUX_ACPI_H*/
|
||||
|
|
|
@ -46,9 +46,10 @@ struct cpuidle_state {
|
|||
/* Idle State Flags */
|
||||
#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
|
||||
#define CPUIDLE_FLAG_CHECK_BM (0x02) /* BM activity will exit state */
|
||||
#define CPUIDLE_FLAG_SHALLOW (0x10) /* low latency, minimal savings */
|
||||
#define CPUIDLE_FLAG_BALANCED (0x20) /* medium latency, moderate savings */
|
||||
#define CPUIDLE_FLAG_DEEP (0x40) /* high latency, large savings */
|
||||
#define CPUIDLE_FLAG_POLL (0x10) /* no latency, no savings */
|
||||
#define CPUIDLE_FLAG_SHALLOW (0x20) /* low latency, minimal 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)
|
||||
|
||||
|
@ -178,4 +179,10 @@ static inline void cpuidle_unregister_governor(struct cpuidle_governor *gov) { }
|
|||
|
||||
#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 */
|
||||
|
|
|
@ -79,7 +79,6 @@ extern void dmi_scan_machine(void);
|
|||
extern int dmi_get_year(int field);
|
||||
extern int dmi_name_in_vendors(const char *str);
|
||||
extern int dmi_available;
|
||||
extern char *dmi_get_slot(int slot);
|
||||
|
||||
#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_name_in_vendors(const char *s) { return 0; }
|
||||
#define dmi_available 0
|
||||
static inline char *dmi_get_slot(int slot) { return NULL; }
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -243,6 +243,7 @@ extern enum system_states {
|
|||
#define TAINT_BAD_PAGE (1<<5)
|
||||
#define TAINT_USER (1<<6)
|
||||
#define TAINT_DIE (1<<7)
|
||||
#define TAINT_OVERRIDDEN_ACPI_TABLE (1<<8)
|
||||
|
||||
extern void dump_stack(void) __cold;
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ enum power_supply_property {
|
|||
/* Properties of type `const char *' */
|
||||
POWER_SUPPLY_PROP_MODEL_NAME,
|
||||
POWER_SUPPLY_PROP_MANUFACTURER,
|
||||
POWER_SUPPLY_PROP_SERIAL_NUMBER,
|
||||
};
|
||||
|
||||
enum power_supply_type {
|
||||
|
|
|
@ -101,6 +101,8 @@
|
|||
#define SONYPI_EVENT_FNKEY_RELEASED 59
|
||||
#define SONYPI_EVENT_WIRELESS_ON 60
|
||||
#define SONYPI_EVENT_WIRELESS_OFF 61
|
||||
#define SONYPI_EVENT_ZOOM_IN_PRESSED 62
|
||||
#define SONYPI_EVENT_ZOOM_OUT_PRESSED 63
|
||||
|
||||
/* get/set brightness */
|
||||
#define SONYPI_IOCGBRT _IOR('v', 0, __u8)
|
||||
|
|
94
include/linux/thermal.h
Normal file
94
include/linux/thermal.h
Normal 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__ */
|
|
@ -538,7 +538,7 @@ static void __init free_initrd(void)
|
|||
initrd_end = 0;
|
||||
}
|
||||
|
||||
static int __init populate_rootfs(void)
|
||||
int __init populate_rootfs(void)
|
||||
{
|
||||
char *err = unpack_to_rootfs(__initramfs_start,
|
||||
__initramfs_end - __initramfs_start, 0);
|
||||
|
@ -577,4 +577,10 @@ static int __init populate_rootfs(void)
|
|||
}
|
||||
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);
|
||||
#endif
|
||||
|
|
|
@ -102,6 +102,12 @@ static inline void mark_rodata_ro(void) { }
|
|||
extern void tc_init(void);
|
||||
#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;
|
||||
EXPORT_SYMBOL(system_state);
|
||||
|
||||
|
@ -648,6 +654,7 @@ asmlinkage void __init start_kernel(void)
|
|||
|
||||
check_bugs();
|
||||
|
||||
populate_rootfs(); /* For DSDT override from initramfs */
|
||||
acpi_early_init(); /* before LAPIC and SMP init */
|
||||
|
||||
/* Do the rest non-__init'ed, we're now alive */
|
||||
|
|
|
@ -161,7 +161,7 @@ const char *print_tainted(void)
|
|||
{
|
||||
static char buf[20];
|
||||
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_FORCED_MODULE ? 'F' : ' ',
|
||||
tainted & TAINT_UNSAFE_SMP ? 'S' : ' ',
|
||||
|
@ -169,7 +169,8 @@ const char *print_tainted(void)
|
|||
tainted & TAINT_MACHINE_CHECK ? 'M' : ' ',
|
||||
tainted & TAINT_BAD_PAGE ? 'B' : ' ',
|
||||
tainted & TAINT_USER ? 'U' : ' ',
|
||||
tainted & TAINT_DIE ? 'D' : ' ');
|
||||
tainted & TAINT_DIE ? 'D' : ' ',
|
||||
tainted & TAINT_OVERRIDDEN_ACPI_TABLE ? 'A' : ' ');
|
||||
}
|
||||
else
|
||||
snprintf(buf, sizeof(buf), "Not tainted");
|
||||
|
|
|
@ -74,8 +74,8 @@ config PM_TRACE_RTC
|
|||
RTC across reboots, so that you can debug a machine that just hangs
|
||||
during suspend (or more commonly, during resume).
|
||||
|
||||
To use this debugging feature you should attempt to suspend the machine,
|
||||
then reboot it, then run
|
||||
To use this debugging feature you should attempt to suspend the
|
||||
machine, reboot it and then run
|
||||
|
||||
dmesg -s 1000000 | grep 'hash matches'
|
||||
|
||||
|
@ -123,7 +123,10 @@ config HIBERNATION
|
|||
called "hibernation" in user interfaces. STD checkpoints the
|
||||
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
|
||||
from <http://suspend.sf.net>.
|
||||
|
||||
|
|
Loading…
Reference in a new issue