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: (26 commits) PM: Make suspend_device() static PCI ACPI: Fix comment describing acpi_pci_choose_state Hibernation: Handle DEBUG_PAGEALLOC on x86 ACPI: fix build warning ACPI: TSC breaks atkbd suspend ACPI: remove is_processor_present prototype acer-wmi: Add DMI match for mail LED on Acer TravelMate 4200 series ACPI: sparse fix, replace macro with static function ACPI: thinkpad-acpi: add tablet-mode reporting ACPI: thinkpad-acpi: minor hotkey_radio_sw fixes ACPI: thinkpad-acpi: improve thinkpad-acpi input device documentation ACPI: thinkpad-acpi: issue input events for tablet swivel events ACPI: thinkpad-acpi: make the video output feature optional ACPI: thinkpad-acpi: synchronize input device switches ACPI: thinkpad-acpi: always track input device open/close ACPI: thinkpad-acpi: trivial fix to documentation ACPI: thinkpad-acpi: trivial fix to module_desc typo intel_menlo: extract return values using PTR_ERR ACPI video: check for error from thermal_cooling_device_register ACPI thermal: extract return values using PTR_ERR ...
This commit is contained in:
commit
20f8d2a493
18 changed files with 322 additions and 124 deletions
|
@ -160,7 +160,7 @@ Hot keys
|
|||
procfs: /proc/acpi/ibm/hotkey
|
||||
sysfs device attribute: hotkey_*
|
||||
|
||||
In a ThinkPad, the ACPI HKEY handler is responsible for comunicating
|
||||
In a ThinkPad, the ACPI HKEY handler is responsible for communicating
|
||||
some important events and also keyboard hot key presses to the operating
|
||||
system. Enabling the hotkey functionality of thinkpad-acpi signals the
|
||||
firmware that such a driver is present, and modifies how the ThinkPad
|
||||
|
@ -193,7 +193,7 @@ Not all bits in the mask can be modified. Not all bits that can be
|
|||
modified do anything. Not all hot keys can be individually controlled
|
||||
by the mask. Some models do not support the mask at all, and in those
|
||||
models, hot keys cannot be controlled individually. The behaviour of
|
||||
the mask is, therefore, higly dependent on the ThinkPad model.
|
||||
the mask is, therefore, highly dependent on the ThinkPad model.
|
||||
|
||||
Note that unmasking some keys prevents their default behavior. For
|
||||
example, if Fn+F5 is unmasked, that key will no longer enable/disable
|
||||
|
@ -288,7 +288,7 @@ sysfs notes:
|
|||
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
|
||||
ThinkPad volume mixer user interface semantics will be
|
||||
enforced.
|
||||
|
||||
hotkey_poll_freq:
|
||||
|
@ -306,13 +306,20 @@ sysfs notes:
|
|||
The recommended polling frequency is 10Hz.
|
||||
|
||||
hotkey_radio_sw:
|
||||
if the ThinkPad has a hardware radio switch, this
|
||||
If the ThinkPad has a hardware radio switch, this
|
||||
attribute will read 0 if the switch is in the "radios
|
||||
disabled" postition, and 1 if the switch is in the
|
||||
disabled" position, and 1 if the switch is in the
|
||||
"radios enabled" position.
|
||||
|
||||
This attribute has poll()/select() support.
|
||||
|
||||
hotkey_tablet_mode:
|
||||
If the ThinkPad has tablet capabilities, this attribute
|
||||
will read 0 if the ThinkPad is in normal mode, and
|
||||
1 if the ThinkPad is in tablet mode.
|
||||
|
||||
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),
|
||||
|
@ -339,7 +346,7 @@ sysfs notes:
|
|||
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
|
||||
was successfully 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.
|
||||
|
@ -392,7 +399,7 @@ event code Key Notes
|
|||
Lenovo: battery
|
||||
|
||||
0x1004 0x03 FN+F4 Sleep button (ACPI sleep button
|
||||
semanthics, i.e. sleep-to-RAM).
|
||||
semantics, i.e. sleep-to-RAM).
|
||||
It is always generate some kind
|
||||
of event, either the hot key
|
||||
event or a ACPI sleep button
|
||||
|
@ -403,12 +410,12 @@ event code Key Notes
|
|||
time passes.
|
||||
|
||||
0x1005 0x04 FN+F5 Radio. Enables/disables
|
||||
the internal BlueTooth hardware
|
||||
the internal Bluetooth hardware
|
||||
and W-WAN card if left in control
|
||||
of the firmware. Does not affect
|
||||
the WLAN card.
|
||||
Should be used to turn on/off all
|
||||
radios (bluetooth+W-WAN+WLAN),
|
||||
radios (Bluetooth+W-WAN+WLAN),
|
||||
really.
|
||||
|
||||
0x1006 0x05 FN+F6 -
|
||||
|
@ -417,7 +424,7 @@ event code Key Notes
|
|||
Do you feel lucky today?
|
||||
|
||||
0x1008 0x07 FN+F8 IBM: toggle screen expand
|
||||
Lenovo: configure ultranav
|
||||
Lenovo: configure UltraNav
|
||||
|
||||
0x1009 0x08 FN+F9 -
|
||||
.. .. ..
|
||||
|
@ -447,7 +454,7 @@ event code Key Notes
|
|||
0x1011 0x10 FN+END Brightness down. See brightness
|
||||
up for details.
|
||||
|
||||
0x1012 0x11 FN+PGUP Thinklight toggle. This key is
|
||||
0x1012 0x11 FN+PGUP ThinkLight toggle. This key is
|
||||
always handled by the firmware,
|
||||
even when unmasked.
|
||||
|
||||
|
@ -469,7 +476,7 @@ event code Key Notes
|
|||
key is always handled by the
|
||||
firmware, even when unmasked.
|
||||
|
||||
0x1018 0x17 THINKPAD Thinkpad/Access IBM/Lenovo key
|
||||
0x1018 0x17 THINKPAD ThinkPad/Access IBM/Lenovo key
|
||||
|
||||
0x1019 0x18 unknown
|
||||
.. .. ..
|
||||
|
@ -488,9 +495,17 @@ If a key is mapped to KEY_UNKNOWN, it generates an input event that
|
|||
includes an scan code. If a key is mapped to anything else, it will
|
||||
generate input device EV_KEY events.
|
||||
|
||||
In addition to the EV_KEY events, thinkpad-acpi may also issue EV_SW
|
||||
events for switches:
|
||||
|
||||
SW_RADIO T60 and later hardare rfkill rocker switch
|
||||
SW_TABLET_MODE Tablet ThinkPads HKEY events 0x5009 and 0x500A
|
||||
|
||||
Non hot-key ACPI HKEY event map:
|
||||
0x5001 Lid closed
|
||||
0x5002 Lid opened
|
||||
0x5009 Tablet swivel: switched to tablet mode
|
||||
0x500A Tablet swivel: switched to normal mode
|
||||
0x7000 Radio Switch may have changed state
|
||||
|
||||
The above events are not propagated by the driver, except for legacy
|
||||
|
@ -505,9 +520,7 @@ 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
|
||||
0x500B Tablet pen inserted into its storage bay
|
||||
0x500C Tablet pen removed from its storage bay
|
||||
0x5010 Brightness level changed (newer Lenovo BIOSes)
|
||||
|
||||
|
@ -539,7 +552,7 @@ sysfs (it is read-only).
|
|||
If the hotkey_report_mode module parameter is set to 1 or 2, it cannot
|
||||
be changed later through sysfs (any writes will return -EPERM to signal
|
||||
that hotkey_report_mode was locked. On 2.6.23 and later, where
|
||||
hotkey_report_mode cannot be changed at all, writes will return -EACES).
|
||||
hotkey_report_mode cannot be changed at all, writes will return -EACCES).
|
||||
|
||||
hotkey_report_mode set to 1 makes the driver export through the procfs
|
||||
ACPI event interface all hot key presses (which are *also* sent to the
|
||||
|
@ -584,7 +597,7 @@ Sysfs notes:
|
|||
0: disables Bluetooth / Bluetooth is disabled
|
||||
1: enables Bluetooth / Bluetooth is enabled.
|
||||
|
||||
Note: this interface will be probably be superseeded by the
|
||||
Note: this interface will be probably be superseded by the
|
||||
generic rfkill class, so it is NOT to be considered stable yet.
|
||||
|
||||
Video output control -- /proc/acpi/ibm/video
|
||||
|
@ -791,12 +804,12 @@ on the X40 (tpb is the ThinkPad Buttons utility):
|
|||
1 - Related to "Volume up" key press
|
||||
2 - Related to "Mute on" key press
|
||||
3 - Related to "Access IBM" key press
|
||||
4 - Related to "LCD brightness up" key pess
|
||||
4 - Related to "LCD brightness up" key press
|
||||
5 - Related to "LCD brightness down" key press
|
||||
11 - Related to "toggle screen expansion" key press/function
|
||||
12 - Related to "ThinkLight on"
|
||||
13 - Related to "ThinkLight off"
|
||||
14 - Related to "ThinkLight" key press (toggle thinklight)
|
||||
14 - Related to "ThinkLight" key press (toggle ThinkLight)
|
||||
|
||||
The cmos command interface is prone to firmware split-brain problems, as
|
||||
in newer ThinkPads it is just a compatibility layer. Do not use it, it is
|
||||
|
@ -1024,7 +1037,7 @@ There are two interfaces to the firmware for direct brightness control,
|
|||
EC and CMOS. To select which one should be used, use the
|
||||
brightness_mode module parameter: brightness_mode=1 selects EC mode,
|
||||
brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC
|
||||
and CMOS. The driver tries to autodetect which interface to use.
|
||||
and CMOS. The driver tries to auto-detect which interface to use.
|
||||
|
||||
When display backlight brightness controls are available through the
|
||||
standard ACPI interface, it is best to use it instead of this direct
|
||||
|
@ -1266,8 +1279,8 @@ experimental=1 parameter when loading the module.
|
|||
This feature shows the presence and current state of a W-WAN (Sierra
|
||||
Wireless EV-DO) device.
|
||||
|
||||
It was tested on a Lenovo Thinkpad X60. It should probably work on other
|
||||
Thinkpad models which come with this module installed.
|
||||
It was tested on a Lenovo ThinkPad X60. It should probably work on other
|
||||
ThinkPad models which come with this module installed.
|
||||
|
||||
Procfs notes:
|
||||
|
||||
|
@ -1286,7 +1299,7 @@ Sysfs notes:
|
|||
0: disables WWAN card / WWAN card is disabled
|
||||
1: enables WWAN card / WWAN card is enabled.
|
||||
|
||||
Note: this interface will be probably be superseeded by the
|
||||
Note: this interface will be probably be superseded by the
|
||||
generic rfkill class, so it is NOT to be considered stable yet.
|
||||
|
||||
Multiple Commands, Module Parameters
|
||||
|
@ -1309,7 +1322,7 @@ Enabling debugging output
|
|||
The module takes a debug parameter which can be used to selectively
|
||||
enable various classes of debugging output, for example:
|
||||
|
||||
modprobe ibm_acpi debug=0xffff
|
||||
modprobe thinkpad_acpi debug=0xffff
|
||||
|
||||
will enable all debugging output classes. It takes a bitmask, so
|
||||
to enable more than one output class, just add their values.
|
||||
|
@ -1356,7 +1369,7 @@ Sysfs interface changelog:
|
|||
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
|
||||
and proper hotkey_mask semantics (version 8 of the
|
||||
NVRAM polling patch). Some development snapshots of
|
||||
0.18 had an earlier version that did strange things
|
||||
to hotkey_mask.
|
||||
|
|
|
@ -899,7 +899,24 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
|
|||
*/
|
||||
cpa_fill_pool();
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_HIBERNATION
|
||||
|
||||
bool kernel_page_present(struct page *page)
|
||||
{
|
||||
unsigned int level;
|
||||
pte_t *pte;
|
||||
|
||||
if (PageHighMem(page))
|
||||
return false;
|
||||
|
||||
pte = lookup_address((unsigned long)page_address(page), &level);
|
||||
return (pte_val(*pte) & _PAGE_PRESENT);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_HIBERNATION */
|
||||
|
||||
#endif /* CONFIG_DEBUG_PAGEALLOC */
|
||||
|
||||
/*
|
||||
* The testcases use internal knowledge of the implementation that shouldn't
|
||||
|
|
|
@ -943,7 +943,11 @@ int __init acpi_ec_ecdt_probe(void)
|
|||
boot_ec->command_addr = ecdt_ptr->control.address;
|
||||
boot_ec->data_addr = ecdt_ptr->data.address;
|
||||
boot_ec->gpe = ecdt_ptr->gpe;
|
||||
boot_ec->handle = ACPI_ROOT_OBJECT;
|
||||
if (ACPI_FAILURE(acpi_get_handle(NULL, ecdt_ptr->id,
|
||||
&boot_ec->handle))) {
|
||||
pr_info("Failed to locate handle for boot EC\n");
|
||||
boot_ec->handle = ACPI_ROOT_OBJECT;
|
||||
}
|
||||
} else {
|
||||
/* This workaround is needed only on some broken machines,
|
||||
* which require early EC, but fail to provide ECDT */
|
||||
|
|
|
@ -338,6 +338,7 @@ acpi_ex_pci_config_space_handler(u32 function,
|
|||
acpi_status status = AE_OK;
|
||||
struct acpi_pci_id *pci_id;
|
||||
u16 pci_register;
|
||||
u32 value32;
|
||||
|
||||
ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
|
||||
|
||||
|
@ -364,9 +365,9 @@ acpi_ex_pci_config_space_handler(u32 function,
|
|||
switch (function) {
|
||||
case ACPI_READ:
|
||||
|
||||
*value = 0;
|
||||
status = acpi_os_read_pci_configuration(pci_id, pci_register,
|
||||
value, bit_width);
|
||||
&value32, bit_width);
|
||||
*value = value32;
|
||||
break;
|
||||
|
||||
case ACPI_WRITE:
|
||||
|
|
|
@ -256,22 +256,28 @@ static int acpi_fan_add(struct acpi_device *device)
|
|||
|
||||
cdev = thermal_cooling_device_register("Fan", device,
|
||||
&fan_cooling_ops);
|
||||
if (cdev)
|
||||
if (IS_ERR(cdev)) {
|
||||
result = PTR_ERR(cdev);
|
||||
goto end;
|
||||
}
|
||||
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;
|
||||
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)
|
||||
|
|
|
@ -670,21 +670,26 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
|
|||
|
||||
pr->cdev = thermal_cooling_device_register("Processor", device,
|
||||
&processor_cooling_ops);
|
||||
if (pr->cdev)
|
||||
if (IS_ERR(pr->cdev)) {
|
||||
result = PTR_ERR(pr->cdev);
|
||||
goto end;
|
||||
}
|
||||
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;
|
||||
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",
|
||||
|
@ -809,10 +814,12 @@ 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;
|
||||
if (pr->cdev) {
|
||||
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;
|
||||
|
||||
|
@ -826,8 +833,6 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
|
|||
* Acpi processor hotplug support *
|
||||
****************************************************************************/
|
||||
|
||||
static int is_processor_present(acpi_handle handle);
|
||||
|
||||
static int is_processor_present(acpi_handle handle)
|
||||
{
|
||||
acpi_status status;
|
||||
|
|
|
@ -364,7 +364,7 @@ int acpi_processor_resume(struct acpi_device * device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
|
||||
static int tsc_halts_in_c(int state)
|
||||
{
|
||||
switch (boot_cpu_data.x86_vendor) {
|
||||
|
@ -544,7 +544,7 @@ static void acpi_processor_idle(void)
|
|||
/* Get end time (ticks) */
|
||||
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
|
||||
/* TSC halts in C2, so notify users */
|
||||
if (tsc_halts_in_c(ACPI_STATE_C2))
|
||||
mark_tsc_unstable("possible TSC halt in C2");
|
||||
|
@ -609,7 +609,7 @@ static void acpi_processor_idle(void)
|
|||
acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
|
||||
}
|
||||
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
|
||||
/* TSC halts in C3, so notify users */
|
||||
if (tsc_halts_in_c(ACPI_STATE_C3))
|
||||
mark_tsc_unstable("TSC halts in C3");
|
||||
|
@ -1500,7 +1500,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
|
|||
acpi_idle_do_entry(cx);
|
||||
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
|
||||
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
|
||||
/* TSC could halt in idle, so notify users */
|
||||
if (tsc_halts_in_c(cx->type))
|
||||
mark_tsc_unstable("TSC halts in idle");;
|
||||
|
@ -1614,7 +1614,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
|
|||
spin_unlock(&c3_lock);
|
||||
}
|
||||
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
|
||||
#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
|
||||
/* TSC could halt in idle, so notify users */
|
||||
if (tsc_halts_in_c(ACPI_STATE_C3))
|
||||
mark_tsc_unstable("TSC halts in idle");
|
||||
|
|
|
@ -36,16 +36,20 @@ ACPI_MODULE_NAME("utils");
|
|||
/* --------------------------------------------------------------------------
|
||||
Object Evaluation Helpers
|
||||
-------------------------------------------------------------------------- */
|
||||
static void
|
||||
acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
|
||||
{
|
||||
#ifdef ACPI_DEBUG_OUTPUT
|
||||
#define acpi_util_eval_error(h,p,s) {\
|
||||
char prefix[80] = {'\0'};\
|
||||
struct acpi_buffer buffer = {sizeof(prefix), prefix};\
|
||||
acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",\
|
||||
(char *) prefix, p, acpi_format_exception(s))); }
|
||||
char prefix[80] = {'\0'};
|
||||
struct acpi_buffer buffer = {sizeof(prefix), prefix};
|
||||
acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
|
||||
(char *) prefix, p, acpi_format_exception(s)));
|
||||
#else
|
||||
#define acpi_util_eval_error(h,p,s)
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
acpi_status
|
||||
acpi_extract_package(union acpi_object *package,
|
||||
struct acpi_buffer *format, struct acpi_buffer *buffer)
|
||||
|
|
|
@ -731,6 +731,9 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
|
|||
|
||||
device->cdev = thermal_cooling_device_register("LCD",
|
||||
device->dev, &video_cooling_ops);
|
||||
if (IS_ERR(device->cdev))
|
||||
return;
|
||||
|
||||
if (device->cdev) {
|
||||
printk(KERN_INFO PREFIX
|
||||
"%s is registered as cooling_device%d\n",
|
||||
|
|
|
@ -415,7 +415,7 @@ EXPORT_SYMBOL_GPL(device_power_down);
|
|||
* @dev: Device.
|
||||
* @state: Power state device is entering.
|
||||
*/
|
||||
int suspend_device(struct device *dev, pm_message_t state)
|
||||
static int suspend_device(struct device *dev, pm_message_t state)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
|
|
|
@ -258,6 +258,23 @@ config THINKPAD_ACPI_BAY
|
|||
|
||||
If you are not sure, say Y here.
|
||||
|
||||
config THINKPAD_ACPI_VIDEO
|
||||
bool "Video output control support"
|
||||
depends on THINKPAD_ACPI
|
||||
default y
|
||||
---help---
|
||||
Allows the thinkpad_acpi driver to provide an interface to control
|
||||
the various video output ports.
|
||||
|
||||
This feature often won't work well, depending on ThinkPad model,
|
||||
display state, video output devices in use, whether there is a X
|
||||
server running, phase of the moon, and the current mood of
|
||||
Schroedinger's cat. If you can use X.org's RandR to control
|
||||
your ThinkPad's video output ports instead of this feature,
|
||||
don't think twice: do it and say N here to save some memory.
|
||||
|
||||
If you are not sure, say Y here.
|
||||
|
||||
config THINKPAD_ACPI_HOTKEY_POLL
|
||||
bool "Suport NVRAM polling for hot keys"
|
||||
depends on THINKPAD_ACPI
|
||||
|
|
|
@ -271,6 +271,15 @@ static struct dmi_system_id acer_quirks[] = {
|
|||
},
|
||||
.driver_data = &quirk_acer_travelmate_2490,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Acer TravelMate 4200",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
|
||||
},
|
||||
.driver_data = &quirk_acer_travelmate_2490,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Medion MD 98300",
|
||||
|
|
|
@ -170,10 +170,13 @@ static int intel_menlow_memory_add(struct acpi_device *device)
|
|||
|
||||
cdev = thermal_cooling_device_register("Memory controller", device,
|
||||
&memory_cooling_ops);
|
||||
acpi_driver_data(device) = cdev;
|
||||
if (!cdev)
|
||||
result = -ENODEV;
|
||||
else {
|
||||
if (IS_ERR(cdev)) {
|
||||
result = PTR_ERR(cdev);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (cdev) {
|
||||
acpi_driver_data(device) = cdev;
|
||||
result = sysfs_create_link(&device->dev.kobj,
|
||||
&cdev->device.kobj, "thermal_cooling");
|
||||
if (result)
|
||||
|
|
|
@ -221,6 +221,7 @@ static struct {
|
|||
u32 hotkey:1;
|
||||
u32 hotkey_mask:1;
|
||||
u32 hotkey_wlsw:1;
|
||||
u32 hotkey_tablet:1;
|
||||
u32 light:1;
|
||||
u32 light_status:1;
|
||||
u32 bright_16levels:1;
|
||||
|
@ -301,6 +302,13 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
|
|||
"HKEY", /* all others */
|
||||
); /* 570 */
|
||||
|
||||
TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
|
||||
"\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
|
||||
"\\_SB.PCI0.VID0", /* 770e */
|
||||
"\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
|
||||
"\\_SB.PCI0.AGP.VID", /* all others */
|
||||
); /* R30, R31 */
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* ACPI helpers
|
||||
|
@ -1053,6 +1061,9 @@ static struct attribute_set *hotkey_dev_attributes;
|
|||
#define HOTKEY_CONFIG_CRITICAL_END
|
||||
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
|
||||
|
||||
/* HKEY.MHKG() return bits */
|
||||
#define TP_HOTKEY_TABLET_MASK (1 << 3)
|
||||
|
||||
static int hotkey_get_wlsw(int *status)
|
||||
{
|
||||
if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
|
||||
|
@ -1060,6 +1071,16 @@ static int hotkey_get_wlsw(int *status)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hotkey_get_tablet_mode(int *status)
|
||||
{
|
||||
int s;
|
||||
|
||||
if (!acpi_evalf(hkey_handle, &s, "MHKG", "d"))
|
||||
return -EIO;
|
||||
|
||||
return ((s & TP_HOTKEY_TABLET_MASK) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call with hotkey_mutex held
|
||||
*/
|
||||
|
@ -1154,15 +1175,31 @@ static void tpacpi_input_send_radiosw(void)
|
|||
{
|
||||
int wlsw;
|
||||
|
||||
mutex_lock(&tpacpi_inputdev_send_mutex);
|
||||
|
||||
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
|
||||
mutex_lock(&tpacpi_inputdev_send_mutex);
|
||||
|
||||
input_report_switch(tpacpi_inputdev,
|
||||
SW_RADIO, !!wlsw);
|
||||
input_sync(tpacpi_inputdev);
|
||||
}
|
||||
|
||||
mutex_unlock(&tpacpi_inputdev_send_mutex);
|
||||
mutex_unlock(&tpacpi_inputdev_send_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void tpacpi_input_send_tabletsw(void)
|
||||
{
|
||||
int state;
|
||||
|
||||
if (tp_features.hotkey_tablet &&
|
||||
!hotkey_get_tablet_mode(&state)) {
|
||||
mutex_lock(&tpacpi_inputdev_send_mutex);
|
||||
|
||||
input_report_switch(tpacpi_inputdev,
|
||||
SW_TABLET_MODE, !!state);
|
||||
input_sync(tpacpi_inputdev);
|
||||
|
||||
mutex_unlock(&tpacpi_inputdev_send_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static void tpacpi_input_send_key(unsigned int scancode)
|
||||
|
@ -1417,6 +1454,14 @@ static void hotkey_poll_setup_safe(int may_warn)
|
|||
mutex_unlock(&hotkey_mutex);
|
||||
}
|
||||
|
||||
#else /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
|
||||
|
||||
static void hotkey_poll_setup_safe(int __unused)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
|
||||
|
||||
static int hotkey_inputdev_open(struct input_dev *dev)
|
||||
{
|
||||
switch (tpacpi_lifecycle) {
|
||||
|
@ -1444,7 +1489,6 @@ static void hotkey_inputdev_close(struct input_dev *dev)
|
|||
if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
|
||||
hotkey_poll_setup_safe(0);
|
||||
}
|
||||
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
|
||||
|
||||
/* sysfs hotkey enable ------------------------------------------------- */
|
||||
static ssize_t hotkey_enable_show(struct device *dev,
|
||||
|
@ -1666,6 +1710,29 @@ static void hotkey_radio_sw_notify_change(void)
|
|||
"hotkey_radio_sw");
|
||||
}
|
||||
|
||||
/* sysfs hotkey tablet mode (pollable) --------------------------------- */
|
||||
static ssize_t hotkey_tablet_mode_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int res, s;
|
||||
res = hotkey_get_tablet_mode(&s);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", !!s);
|
||||
}
|
||||
|
||||
static struct device_attribute dev_attr_hotkey_tablet_mode =
|
||||
__ATTR(hotkey_tablet_mode, S_IRUGO, hotkey_tablet_mode_show, NULL);
|
||||
|
||||
static void hotkey_tablet_mode_notify_change(void)
|
||||
{
|
||||
if (tp_features.hotkey_tablet)
|
||||
sysfs_notify(&tpacpi_pdev->dev.kobj, NULL,
|
||||
"hotkey_tablet_mode");
|
||||
}
|
||||
|
||||
/* sysfs hotkey report_mode -------------------------------------------- */
|
||||
static ssize_t hotkey_report_mode_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
|
@ -1878,7 +1945,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
str_supported(tp_features.hotkey));
|
||||
|
||||
if (tp_features.hotkey) {
|
||||
hotkey_dev_attributes = create_attr_set(12, NULL);
|
||||
hotkey_dev_attributes = create_attr_set(13, NULL);
|
||||
if (!hotkey_dev_attributes)
|
||||
return -ENOMEM;
|
||||
res = add_many_to_attr_set(hotkey_dev_attributes,
|
||||
|
@ -1957,6 +2024,18 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
&dev_attr_hotkey_radio_sw.attr);
|
||||
}
|
||||
|
||||
/* For X41t, X60t, X61t Tablets... */
|
||||
if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) {
|
||||
tp_features.hotkey_tablet = 1;
|
||||
printk(TPACPI_INFO
|
||||
"possible tablet mode switch found; "
|
||||
"ThinkPad in %s mode\n",
|
||||
(status & TP_HOTKEY_TABLET_MASK)?
|
||||
"tablet" : "laptop");
|
||||
res = add_to_attr_set(hotkey_dev_attributes,
|
||||
&dev_attr_hotkey_tablet_mode.attr);
|
||||
}
|
||||
|
||||
if (!res)
|
||||
res = register_attr_set_with_sysfs(
|
||||
hotkey_dev_attributes,
|
||||
|
@ -2006,6 +2085,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
set_bit(EV_SW, tpacpi_inputdev->evbit);
|
||||
set_bit(SW_RADIO, tpacpi_inputdev->swbit);
|
||||
}
|
||||
if (tp_features.hotkey_tablet) {
|
||||
set_bit(EV_SW, tpacpi_inputdev->evbit);
|
||||
set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit);
|
||||
}
|
||||
|
||||
dbg_printk(TPACPI_DBG_INIT,
|
||||
"enabling hot key handling\n");
|
||||
|
@ -2023,12 +2106,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
|
|||
(hotkey_report_mode < 2) ?
|
||||
"enabled" : "disabled");
|
||||
|
||||
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
|
||||
tpacpi_inputdev->open = &hotkey_inputdev_open;
|
||||
tpacpi_inputdev->close = &hotkey_inputdev_close;
|
||||
|
||||
hotkey_poll_setup_safe(1);
|
||||
#endif
|
||||
tpacpi_input_send_radiosw();
|
||||
tpacpi_input_send_tabletsw();
|
||||
}
|
||||
|
||||
return (tp_features.hotkey)? 0 : 1;
|
||||
|
@ -2156,11 +2239,15 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
|
|||
/* 0x5000-0x5FFF: human interface helpers */
|
||||
switch (hkey) {
|
||||
case 0x5010: /* Lenovo new BIOS: brightness changed */
|
||||
case 0x5009: /* X61t: swivel up (tablet mode) */
|
||||
case 0x500a: /* X61t: swivel down (normal mode) */
|
||||
case 0x500b: /* X61t: tablet pen inserted into bay */
|
||||
case 0x500c: /* X61t: tablet pen removed from bay */
|
||||
break;
|
||||
case 0x5009: /* X41t-X61t: swivel up (tablet mode) */
|
||||
case 0x500a: /* X41t-X61t: swivel down (normal mode) */
|
||||
tpacpi_input_send_tabletsw();
|
||||
hotkey_tablet_mode_notify_change();
|
||||
send_acpi_ev = 0;
|
||||
break;
|
||||
case 0x5001:
|
||||
case 0x5002:
|
||||
/* LID switch events. Do not propagate */
|
||||
|
@ -2219,11 +2306,10 @@ static void hotkey_resume(void)
|
|||
"from firmware\n");
|
||||
tpacpi_input_send_radiosw();
|
||||
hotkey_radio_sw_notify_change();
|
||||
hotkey_tablet_mode_notify_change();
|
||||
hotkey_wakeup_reason_notify_change();
|
||||
hotkey_wakeup_hotunplug_complete_notify_change();
|
||||
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
|
||||
hotkey_poll_setup_safe(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* procfs -------------------------------------------------------------- */
|
||||
|
@ -2676,6 +2762,8 @@ static struct ibm_struct wan_driver_data = {
|
|||
* Video subdriver
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_THINKPAD_ACPI_VIDEO
|
||||
|
||||
enum video_access_mode {
|
||||
TPACPI_VIDEO_NONE = 0,
|
||||
TPACPI_VIDEO_570, /* 570 */
|
||||
|
@ -2703,13 +2791,6 @@ static int video_orig_autosw;
|
|||
static int video_autosw_get(void);
|
||||
static int video_autosw_set(int enable);
|
||||
|
||||
TPACPI_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA", /* 570 */
|
||||
"\\_SB.PCI0.AGP0.VID0", /* 600e/x, 770x */
|
||||
"\\_SB.PCI0.VID0", /* 770e */
|
||||
"\\_SB.PCI0.VID", /* A21e, G4x, R50e, X30, X40 */
|
||||
"\\_SB.PCI0.AGP.VID", /* all others */
|
||||
); /* R30, R31 */
|
||||
|
||||
TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
|
||||
|
||||
static int __init video_init(struct ibm_init_struct *iibm)
|
||||
|
@ -3019,6 +3100,8 @@ static struct ibm_struct video_driver_data = {
|
|||
.exit = video_exit,
|
||||
};
|
||||
|
||||
#endif /* CONFIG_THINKPAD_ACPI_VIDEO */
|
||||
|
||||
/*************************************************************************
|
||||
* Light (thinklight) subdriver
|
||||
*/
|
||||
|
@ -5803,10 +5886,12 @@ static struct ibm_init_struct ibms_init[] __initdata = {
|
|||
.init = wan_init,
|
||||
.data = &wan_driver_data,
|
||||
},
|
||||
#ifdef CONFIG_THINKPAD_ACPI_VIDEO
|
||||
{
|
||||
.init = video_init,
|
||||
.data = &video_driver_data,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.init = light_init,
|
||||
.data = &light_driver_data,
|
||||
|
@ -5918,7 +6003,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
|
|||
|
||||
#define TPACPI_PARAM(feature) \
|
||||
module_param_call(feature, set_ibm_param, NULL, NULL, 0); \
|
||||
MODULE_PARM_DESC(feature, "Simulates thinkpad-aci procfs command " \
|
||||
MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \
|
||||
"at module load, see documentation")
|
||||
|
||||
TPACPI_PARAM(hotkey);
|
||||
|
|
|
@ -242,8 +242,6 @@ EXPORT_SYMBOL(pci_osc_control_set);
|
|||
* choose from highest power _SxD to lowest power _SxW
|
||||
* else // no _PRW at S-state x
|
||||
* choose highest power _SxD or any lower power
|
||||
*
|
||||
* currently we simply return _SxD, if present.
|
||||
*/
|
||||
|
||||
static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,
|
||||
|
|
|
@ -306,12 +306,23 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
|||
{
|
||||
struct thermal_cooling_device_instance *dev;
|
||||
struct thermal_cooling_device_instance *pos;
|
||||
struct thermal_zone_device *pos1;
|
||||
struct thermal_cooling_device *pos2;
|
||||
int result;
|
||||
|
||||
if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
|
||||
return -EINVAL;
|
||||
|
||||
if (!tz || !cdev)
|
||||
list_for_each_entry(pos1, &thermal_tz_list, node) {
|
||||
if (pos1 == tz)
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(pos2, &thermal_cdev_list, node) {
|
||||
if (pos2 == cdev)
|
||||
break;
|
||||
}
|
||||
|
||||
if (tz != pos1 || cdev != pos2)
|
||||
return -EINVAL;
|
||||
|
||||
dev =
|
||||
|
@ -437,20 +448,20 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
|
|||
int result;
|
||||
|
||||
if (strlen(type) >= THERMAL_NAME_LENGTH)
|
||||
return NULL;
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!ops || !ops->get_max_state || !ops->get_cur_state ||
|
||||
!ops->set_cur_state)
|
||||
return NULL;
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
|
||||
if (!cdev)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
|
||||
if (result) {
|
||||
kfree(cdev);
|
||||
return NULL;
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
strcpy(cdev->type, type);
|
||||
|
@ -462,7 +473,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
|
|||
if (result) {
|
||||
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
|
||||
kfree(cdev);
|
||||
return NULL;
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
/* sys I/F */
|
||||
|
@ -498,7 +509,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
|
|||
unregister:
|
||||
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
|
||||
device_unregister(&cdev->device);
|
||||
return NULL;
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(thermal_cooling_device_register);
|
||||
|
@ -570,17 +581,17 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
|
|||
int count;
|
||||
|
||||
if (strlen(type) >= THERMAL_NAME_LENGTH)
|
||||
return NULL;
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (trips > THERMAL_MAX_TRIPS || trips < 0)
|
||||
return NULL;
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (!ops || !ops->get_temp)
|
||||
return NULL;
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
|
||||
if (!tz)
|
||||
return NULL;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_LIST_HEAD(&tz->cooling_devices);
|
||||
idr_init(&tz->idr);
|
||||
|
@ -588,7 +599,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
|
|||
result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
|
||||
if (result) {
|
||||
kfree(tz);
|
||||
return NULL;
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
strcpy(tz->type, type);
|
||||
|
@ -601,7 +612,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
|
|||
if (result) {
|
||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
||||
kfree(tz);
|
||||
return NULL;
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
/* sys I/F */
|
||||
|
@ -643,7 +654,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
|
|||
unregister:
|
||||
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
|
||||
device_unregister(&tz->device);
|
||||
return NULL;
|
||||
return ERR_PTR(result);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(thermal_zone_device_register);
|
||||
|
|
|
@ -1171,12 +1171,18 @@ static inline void enable_debug_pagealloc(void)
|
|||
{
|
||||
debug_pagealloc_enabled = 1;
|
||||
}
|
||||
#ifdef CONFIG_HIBERNATION
|
||||
extern bool kernel_page_present(struct page *page);
|
||||
#endif /* CONFIG_HIBERNATION */
|
||||
#else
|
||||
static inline void
|
||||
kernel_map_pages(struct page *page, int numpages, int enable) {}
|
||||
static inline void enable_debug_pagealloc(void)
|
||||
{
|
||||
}
|
||||
#ifdef CONFIG_HIBERNATION
|
||||
static inline bool kernel_page_present(struct page *page) { return true; }
|
||||
#endif /* CONFIG_HIBERNATION */
|
||||
#endif
|
||||
|
||||
extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk);
|
||||
|
|
|
@ -875,8 +875,8 @@ static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
|
|||
#endif /* CONFIG_HIGHMEM */
|
||||
|
||||
/**
|
||||
* saveable - Determine whether a non-highmem page should be included in
|
||||
* the suspend image.
|
||||
* saveable_page - Determine whether a non-highmem page should be included
|
||||
* in the suspend image.
|
||||
*
|
||||
* We should save the page if it isn't Nosave, and is not in the range
|
||||
* of pages statically defined as 'unsaveable', and it isn't a part of
|
||||
|
@ -897,7 +897,8 @@ static struct page *saveable_page(unsigned long pfn)
|
|||
if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
|
||||
return NULL;
|
||||
|
||||
if (PageReserved(page) && pfn_is_nosave(pfn))
|
||||
if (PageReserved(page)
|
||||
&& (!kernel_page_present(page) || pfn_is_nosave(pfn)))
|
||||
return NULL;
|
||||
|
||||
return page;
|
||||
|
@ -938,6 +939,25 @@ static inline void do_copy_page(long *dst, long *src)
|
|||
*dst++ = *src++;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* safe_copy_page - check if the page we are going to copy is marked as
|
||||
* present in the kernel page tables (this always is the case if
|
||||
* CONFIG_DEBUG_PAGEALLOC is not set and in that case
|
||||
* kernel_page_present() always returns 'true').
|
||||
*/
|
||||
static void safe_copy_page(void *dst, struct page *s_page)
|
||||
{
|
||||
if (kernel_page_present(s_page)) {
|
||||
do_copy_page(dst, page_address(s_page));
|
||||
} else {
|
||||
kernel_map_pages(s_page, 1, 1);
|
||||
do_copy_page(dst, page_address(s_page));
|
||||
kernel_map_pages(s_page, 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_HIGHMEM
|
||||
static inline struct page *
|
||||
page_is_saveable(struct zone *zone, unsigned long pfn)
|
||||
|
@ -946,8 +966,7 @@ page_is_saveable(struct zone *zone, unsigned long pfn)
|
|||
saveable_highmem_page(pfn) : saveable_page(pfn);
|
||||
}
|
||||
|
||||
static inline void
|
||||
copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
|
||||
static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
|
||||
{
|
||||
struct page *s_page, *d_page;
|
||||
void *src, *dst;
|
||||
|
@ -961,29 +980,26 @@ copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
|
|||
kunmap_atomic(src, KM_USER0);
|
||||
kunmap_atomic(dst, KM_USER1);
|
||||
} else {
|
||||
src = page_address(s_page);
|
||||
if (PageHighMem(d_page)) {
|
||||
/* Page pointed to by src may contain some kernel
|
||||
* data modified by kmap_atomic()
|
||||
*/
|
||||
do_copy_page(buffer, src);
|
||||
safe_copy_page(buffer, s_page);
|
||||
dst = kmap_atomic(pfn_to_page(dst_pfn), KM_USER0);
|
||||
memcpy(dst, buffer, PAGE_SIZE);
|
||||
kunmap_atomic(dst, KM_USER0);
|
||||
} else {
|
||||
dst = page_address(d_page);
|
||||
do_copy_page(dst, src);
|
||||
safe_copy_page(page_address(d_page), s_page);
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define page_is_saveable(zone, pfn) saveable_page(pfn)
|
||||
|
||||
static inline void
|
||||
copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
|
||||
static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
|
||||
{
|
||||
do_copy_page(page_address(pfn_to_page(dst_pfn)),
|
||||
page_address(pfn_to_page(src_pfn)));
|
||||
safe_copy_page(page_address(pfn_to_page(dst_pfn)),
|
||||
pfn_to_page(src_pfn));
|
||||
}
|
||||
#endif /* CONFIG_HIGHMEM */
|
||||
|
||||
|
|
Loading…
Reference in a new issue