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:
Linus Torvalds 2008-02-21 16:33:19 -08:00
commit 20f8d2a493
18 changed files with 322 additions and 124 deletions

View file

@ -160,7 +160,7 @@ Hot keys
procfs: /proc/acpi/ibm/hotkey procfs: /proc/acpi/ibm/hotkey
sysfs device attribute: 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 some important events and also keyboard hot key presses to the operating
system. Enabling the hotkey functionality of thinkpad-acpi signals the system. Enabling the hotkey functionality of thinkpad-acpi signals the
firmware that such a driver is present, and modifies how the ThinkPad firmware that such a driver is present, and modifies how the ThinkPad
@ -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 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 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 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 Note that unmasking some keys prevents their default behavior. For
example, if Fn+F5 is unmasked, that key will no longer enable/disable 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 in ACPI event mode, volume up/down/mute are reported as
separate events, but this behaviour may be corrected in separate events, but this behaviour may be corrected in
future releases of this driver, in which case the 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. enforced.
hotkey_poll_freq: hotkey_poll_freq:
@ -306,13 +306,20 @@ sysfs notes:
The recommended polling frequency is 10Hz. The recommended polling frequency is 10Hz.
hotkey_radio_sw: hotkey_radio_sw:
if the ThinkPad has a hardware radio switch, this If the ThinkPad has a hardware radio switch, this
attribute will read 0 if the switch is in the "radios attribute will read 0 if the switch is in the "radios
disabled" postition, and 1 if the switch is in the disabled" position, and 1 if the switch is in the
"radios enabled" position. "radios enabled" position.
This attribute has poll()/select() support. 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: hotkey_report_mode:
Returns the state of the procfs ACPI event report mode Returns the state of the procfs ACPI event report mode
filter for hot keys. If it is set to 1 (the default), filter for hot keys. If it is set to 1 (the default),
@ -339,7 +346,7 @@ sysfs notes:
wakeup_hotunplug_complete: wakeup_hotunplug_complete:
Set to 1 if the system was waken up because of an Set to 1 if the system was waken up because of an
undock or bay ejection request, and that request 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 be useful to send the system back to sleep, at the
user's choice. Refer to HKEY events 0x4003 and user's choice. Refer to HKEY events 0x4003 and
0x3003, below. 0x3003, below.
@ -392,7 +399,7 @@ event code Key Notes
Lenovo: battery Lenovo: battery
0x1004 0x03 FN+F4 Sleep button (ACPI sleep button 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 It is always generate some kind
of event, either the hot key of event, either the hot key
event or a ACPI sleep button event or a ACPI sleep button
@ -403,12 +410,12 @@ event code Key Notes
time passes. time passes.
0x1005 0x04 FN+F5 Radio. Enables/disables 0x1005 0x04 FN+F5 Radio. Enables/disables
the internal BlueTooth hardware the internal Bluetooth hardware
and W-WAN card if left in control and W-WAN card if left in control
of the firmware. Does not affect of the firmware. Does not affect
the WLAN card. the WLAN card.
Should be used to turn on/off all Should be used to turn on/off all
radios (bluetooth+W-WAN+WLAN), radios (Bluetooth+W-WAN+WLAN),
really. really.
0x1006 0x05 FN+F6 - 0x1006 0x05 FN+F6 -
@ -417,7 +424,7 @@ event code Key Notes
Do you feel lucky today? Do you feel lucky today?
0x1008 0x07 FN+F8 IBM: toggle screen expand 0x1008 0x07 FN+F8 IBM: toggle screen expand
Lenovo: configure ultranav Lenovo: configure UltraNav
0x1009 0x08 FN+F9 - 0x1009 0x08 FN+F9 -
.. .. .. .. .. ..
@ -447,7 +454,7 @@ event code Key Notes
0x1011 0x10 FN+END Brightness down. See brightness 0x1011 0x10 FN+END Brightness down. See brightness
up for details. 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, always handled by the firmware,
even when unmasked. even when unmasked.
@ -469,7 +476,7 @@ event code Key Notes
key is always handled by the key is always handled by the
firmware, even when unmasked. firmware, even when unmasked.
0x1018 0x17 THINKPAD Thinkpad/Access IBM/Lenovo key 0x1018 0x17 THINKPAD ThinkPad/Access IBM/Lenovo key
0x1019 0x18 unknown 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 includes an scan code. If a key is mapped to anything else, it will
generate input device EV_KEY events. 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: Non hot-key ACPI HKEY event map:
0x5001 Lid closed 0x5001 Lid closed
0x5002 Lid opened 0x5002 Lid opened
0x5009 Tablet swivel: switched to tablet mode
0x500A Tablet swivel: switched to normal mode
0x7000 Radio Switch may have changed state 0x7000 Radio Switch may have changed state
The above events are not propagated by the driver, except for legacy 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 0x3003 Bay ejection (see 0x2x05) complete, can sleep again
0x4003 Undocked (see 0x2x04), can sleep again 0x4003 Undocked (see 0x2x04), can sleep again
0x5009 Tablet swivel: switched to tablet mode 0x500B Tablet pen inserted into its storage bay
0x500A Tablet swivel: switched to normal mode
0x500B Tablet pen insterted into its storage bay
0x500C Tablet pen removed from its storage bay 0x500C Tablet pen removed from its storage bay
0x5010 Brightness level changed (newer Lenovo BIOSes) 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 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 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 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 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 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 0: disables Bluetooth / Bluetooth is disabled
1: enables Bluetooth / Bluetooth is enabled. 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. generic rfkill class, so it is NOT to be considered stable yet.
Video output control -- /proc/acpi/ibm/video 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 1 - Related to "Volume up" key press
2 - Related to "Mute on" key press 2 - Related to "Mute on" key press
3 - Related to "Access IBM" 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 5 - Related to "LCD brightness down" key press
11 - Related to "toggle screen expansion" key press/function 11 - Related to "toggle screen expansion" key press/function
12 - Related to "ThinkLight on" 12 - Related to "ThinkLight on"
13 - Related to "ThinkLight off" 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 The cmos command interface is prone to firmware split-brain problems, as
in newer ThinkPads it is just a compatibility layer. Do not use it, it is in newer ThinkPads it is just a compatibility layer. Do not use it, it is
@ -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 EC and CMOS. To select which one should be used, use the
brightness_mode module parameter: brightness_mode=1 selects EC mode, brightness_mode module parameter: brightness_mode=1 selects EC mode,
brightness_mode=2 selects CMOS mode, brightness_mode=3 selects both EC brightness_mode=2 selects 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 When display backlight brightness controls are available through the
standard ACPI interface, it is best to use it instead of this direct standard ACPI interface, it is best to use it instead of this direct
@ -1266,8 +1279,8 @@ experimental=1 parameter when loading the module.
This feature shows the presence and current state of a W-WAN (Sierra This feature shows the presence and current state of a W-WAN (Sierra
Wireless EV-DO) device. Wireless EV-DO) device.
It was tested on a Lenovo Thinkpad X60. It should probably work on other It was tested on a Lenovo ThinkPad X60. It should probably work on other
Thinkpad models which come with this module installed. ThinkPad models which come with this module installed.
Procfs notes: Procfs notes:
@ -1286,7 +1299,7 @@ Sysfs notes:
0: disables WWAN card / WWAN card is disabled 0: disables WWAN card / WWAN card is disabled
1: enables WWAN card / WWAN card is enabled. 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. generic rfkill class, so it is NOT to be considered stable yet.
Multiple Commands, Module Parameters Multiple Commands, Module Parameters
@ -1309,7 +1322,7 @@ Enabling debugging output
The module takes a debug parameter which can be used to selectively The module takes a debug parameter which can be used to selectively
enable various classes of debugging output, for example: 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 will enable all debugging output classes. It takes a bitmask, so
to enable more than one output class, just add their values. to enable more than one output class, just add their values.
@ -1356,7 +1369,7 @@ Sysfs interface changelog:
NVRAM is compiled out by the user because it is NVRAM is compiled out by the user because it is
unneeded/undesired in the first place). unneeded/undesired in the first place).
0x020101: Marker for thinkpad-acpi with hot key NVRAM polling 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 NVRAM polling patch). Some development snapshots of
0.18 had an earlier version that did strange things 0.18 had an earlier version that did strange things
to hotkey_mask. to hotkey_mask.

View file

@ -899,7 +899,24 @@ void kernel_map_pages(struct page *page, int numpages, int enable)
*/ */
cpa_fill_pool(); 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 * The testcases use internal knowledge of the implementation that shouldn't

View file

@ -943,7 +943,11 @@ int __init acpi_ec_ecdt_probe(void)
boot_ec->command_addr = ecdt_ptr->control.address; boot_ec->command_addr = ecdt_ptr->control.address;
boot_ec->data_addr = ecdt_ptr->data.address; boot_ec->data_addr = ecdt_ptr->data.address;
boot_ec->gpe = ecdt_ptr->gpe; 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 { } else {
/* This workaround is needed only on some broken machines, /* This workaround is needed only on some broken machines,
* which require early EC, but fail to provide ECDT */ * which require early EC, but fail to provide ECDT */

View file

@ -338,6 +338,7 @@ acpi_ex_pci_config_space_handler(u32 function,
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_pci_id *pci_id; struct acpi_pci_id *pci_id;
u16 pci_register; u16 pci_register;
u32 value32;
ACPI_FUNCTION_TRACE(ex_pci_config_space_handler); ACPI_FUNCTION_TRACE(ex_pci_config_space_handler);
@ -364,9 +365,9 @@ acpi_ex_pci_config_space_handler(u32 function,
switch (function) { switch (function) {
case ACPI_READ: case ACPI_READ:
*value = 0;
status = acpi_os_read_pci_configuration(pci_id, pci_register, status = acpi_os_read_pci_configuration(pci_id, pci_register,
value, bit_width); &value32, bit_width);
*value = value32;
break; break;
case ACPI_WRITE: case ACPI_WRITE:

View file

@ -256,22 +256,28 @@ static int acpi_fan_add(struct acpi_device *device)
cdev = thermal_cooling_device_register("Fan", device, cdev = thermal_cooling_device_register("Fan", device,
&fan_cooling_ops); &fan_cooling_ops);
if (cdev) if (IS_ERR(cdev)) {
result = PTR_ERR(cdev);
goto end;
}
if (cdev) {
printk(KERN_INFO PREFIX printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n", "%s is registered as cooling_device%d\n",
device->dev.bus_id, cdev->id); 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, acpi_driver_data(device) = cdev;
"device"); result = sysfs_create_link(&device->dev.kobj,
if (result) &cdev->device.kobj,
return result; "thermal_cooling");
if (result)
return result;
result = sysfs_create_link(&cdev->device.kobj,
&device->dev.kobj,
"device");
if (result)
return result;
}
result = acpi_fan_add_fs(device); result = acpi_fan_add_fs(device);
if (result) if (result)

View file

@ -670,21 +670,26 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
pr->cdev = thermal_cooling_device_register("Processor", device, pr->cdev = thermal_cooling_device_register("Processor", device,
&processor_cooling_ops); &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 printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n", "%s is registered as cooling_device%d\n",
device->dev.bus_id, pr->cdev->id); device->dev.bus_id, pr->cdev->id);
else
goto end;
result = sysfs_create_link(&device->dev.kobj, &pr->cdev->device.kobj, result = sysfs_create_link(&device->dev.kobj,
"thermal_cooling"); &pr->cdev->device.kobj,
if (result) "thermal_cooling");
return result; if (result)
result = sysfs_create_link(&pr->cdev->device.kobj, &device->dev.kobj, return result;
"device"); result = sysfs_create_link(&pr->cdev->device.kobj,
if (result) &device->dev.kobj,
return result; "device");
if (result)
return result;
}
if (pr->flags.throttling) { if (pr->flags.throttling) {
printk(KERN_INFO PREFIX "%s [%s] (supports", printk(KERN_INFO PREFIX "%s [%s] (supports",
@ -809,10 +814,12 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
acpi_processor_remove_fs(device); acpi_processor_remove_fs(device);
sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); if (pr->cdev) {
sysfs_remove_link(&pr->cdev->device.kobj, "device"); sysfs_remove_link(&device->dev.kobj, "thermal_cooling");
thermal_cooling_device_unregister(pr->cdev); sysfs_remove_link(&pr->cdev->device.kobj, "device");
pr->cdev = NULL; thermal_cooling_device_unregister(pr->cdev);
pr->cdev = NULL;
}
processors[pr->id] = NULL; processors[pr->id] = NULL;
@ -826,8 +833,6 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
* Acpi processor hotplug support * * Acpi processor hotplug support *
****************************************************************************/ ****************************************************************************/
static int is_processor_present(acpi_handle handle);
static int is_processor_present(acpi_handle handle) static int is_processor_present(acpi_handle handle)
{ {
acpi_status status; acpi_status status;

View file

@ -364,7 +364,7 @@ int acpi_processor_resume(struct acpi_device * device)
return 0; 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) static int tsc_halts_in_c(int state)
{ {
switch (boot_cpu_data.x86_vendor) { switch (boot_cpu_data.x86_vendor) {
@ -544,7 +544,7 @@ static void acpi_processor_idle(void)
/* Get end time (ticks) */ /* Get end time (ticks) */
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); 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 */ /* TSC halts in C2, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C2)) if (tsc_halts_in_c(ACPI_STATE_C2))
mark_tsc_unstable("possible TSC halt in 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); 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 */ /* TSC halts in C3, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C3)) if (tsc_halts_in_c(ACPI_STATE_C3))
mark_tsc_unstable("TSC halts in 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); acpi_idle_do_entry(cx);
t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); 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 */ /* TSC could halt in idle, so notify users */
if (tsc_halts_in_c(cx->type)) if (tsc_halts_in_c(cx->type))
mark_tsc_unstable("TSC halts in idle");; 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); 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 */ /* TSC could halt in idle, so notify users */
if (tsc_halts_in_c(ACPI_STATE_C3)) if (tsc_halts_in_c(ACPI_STATE_C3))
mark_tsc_unstable("TSC halts in idle"); mark_tsc_unstable("TSC halts in idle");

View file

@ -36,16 +36,20 @@ ACPI_MODULE_NAME("utils");
/* -------------------------------------------------------------------------- /* --------------------------------------------------------------------------
Object Evaluation Helpers Object Evaluation Helpers
-------------------------------------------------------------------------- */ -------------------------------------------------------------------------- */
static void
acpi_util_eval_error(acpi_handle h, acpi_string p, acpi_status s)
{
#ifdef ACPI_DEBUG_OUTPUT #ifdef ACPI_DEBUG_OUTPUT
#define acpi_util_eval_error(h,p,s) {\ char prefix[80] = {'\0'};
char prefix[80] = {'\0'};\ struct acpi_buffer buffer = {sizeof(prefix), prefix};
struct acpi_buffer buffer = {sizeof(prefix), prefix};\ acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);
acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluate [%s.%s]: %s\n",\ (char *) prefix, p, acpi_format_exception(s)));
(char *) prefix, p, acpi_format_exception(s))); }
#else #else
#define acpi_util_eval_error(h,p,s) return;
#endif #endif
}
acpi_status acpi_status
acpi_extract_package(union acpi_object *package, acpi_extract_package(union acpi_object *package,
struct acpi_buffer *format, struct acpi_buffer *buffer) struct acpi_buffer *format, struct acpi_buffer *buffer)

View file

@ -731,6 +731,9 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
device->cdev = thermal_cooling_device_register("LCD", device->cdev = thermal_cooling_device_register("LCD",
device->dev, &video_cooling_ops); device->dev, &video_cooling_ops);
if (IS_ERR(device->cdev))
return;
if (device->cdev) { if (device->cdev) {
printk(KERN_INFO PREFIX printk(KERN_INFO PREFIX
"%s is registered as cooling_device%d\n", "%s is registered as cooling_device%d\n",

View file

@ -415,7 +415,7 @@ EXPORT_SYMBOL_GPL(device_power_down);
* @dev: Device. * @dev: Device.
* @state: Power state device is entering. * @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; int error = 0;

View file

@ -258,6 +258,23 @@ config THINKPAD_ACPI_BAY
If you are not sure, say Y here. 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 config THINKPAD_ACPI_HOTKEY_POLL
bool "Suport NVRAM polling for hot keys" bool "Suport NVRAM polling for hot keys"
depends on THINKPAD_ACPI depends on THINKPAD_ACPI

View file

@ -271,6 +271,15 @@ static struct dmi_system_id acer_quirks[] = {
}, },
.driver_data = &quirk_acer_travelmate_2490, .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, .callback = dmi_matched,
.ident = "Medion MD 98300", .ident = "Medion MD 98300",

View file

@ -170,10 +170,13 @@ static int intel_menlow_memory_add(struct acpi_device *device)
cdev = thermal_cooling_device_register("Memory controller", device, cdev = thermal_cooling_device_register("Memory controller", device,
&memory_cooling_ops); &memory_cooling_ops);
acpi_driver_data(device) = cdev; if (IS_ERR(cdev)) {
if (!cdev) result = PTR_ERR(cdev);
result = -ENODEV; goto end;
else { }
if (cdev) {
acpi_driver_data(device) = cdev;
result = sysfs_create_link(&device->dev.kobj, result = sysfs_create_link(&device->dev.kobj,
&cdev->device.kobj, "thermal_cooling"); &cdev->device.kobj, "thermal_cooling");
if (result) if (result)

View file

@ -221,6 +221,7 @@ static struct {
u32 hotkey:1; u32 hotkey:1;
u32 hotkey_mask:1; u32 hotkey_mask:1;
u32 hotkey_wlsw:1; u32 hotkey_wlsw:1;
u32 hotkey_tablet:1;
u32 light:1; u32 light:1;
u32 light_status:1; u32 light_status:1;
u32 bright_16levels:1; u32 bright_16levels:1;
@ -301,6 +302,13 @@ TPACPI_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */
"HKEY", /* all others */ "HKEY", /* all others */
); /* 570 */ ); /* 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 * ACPI helpers
@ -1053,6 +1061,9 @@ static struct attribute_set *hotkey_dev_attributes;
#define HOTKEY_CONFIG_CRITICAL_END #define HOTKEY_CONFIG_CRITICAL_END
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */ #endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
/* HKEY.MHKG() return bits */
#define TP_HOTKEY_TABLET_MASK (1 << 3)
static int hotkey_get_wlsw(int *status) static int hotkey_get_wlsw(int *status)
{ {
if (!acpi_evalf(hkey_handle, status, "WLSW", "d")) if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))
@ -1060,6 +1071,16 @@ static int hotkey_get_wlsw(int *status)
return 0; 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 * Call with hotkey_mutex held
*/ */
@ -1154,15 +1175,31 @@ static void tpacpi_input_send_radiosw(void)
{ {
int wlsw; int wlsw;
mutex_lock(&tpacpi_inputdev_send_mutex);
if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) {
mutex_lock(&tpacpi_inputdev_send_mutex);
input_report_switch(tpacpi_inputdev, input_report_switch(tpacpi_inputdev,
SW_RADIO, !!wlsw); SW_RADIO, !!wlsw);
input_sync(tpacpi_inputdev); 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) 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); 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) static int hotkey_inputdev_open(struct input_dev *dev)
{ {
switch (tpacpi_lifecycle) { switch (tpacpi_lifecycle) {
@ -1444,7 +1489,6 @@ static void hotkey_inputdev_close(struct input_dev *dev)
if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING) if (tpacpi_lifecycle == TPACPI_LIFE_RUNNING)
hotkey_poll_setup_safe(0); hotkey_poll_setup_safe(0);
} }
#endif /* CONFIG_THINKPAD_ACPI_HOTKEY_POLL */
/* sysfs hotkey enable ------------------------------------------------- */ /* sysfs hotkey enable ------------------------------------------------- */
static ssize_t hotkey_enable_show(struct device *dev, static ssize_t hotkey_enable_show(struct device *dev,
@ -1666,6 +1710,29 @@ static void hotkey_radio_sw_notify_change(void)
"hotkey_radio_sw"); "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 -------------------------------------------- */ /* sysfs hotkey report_mode -------------------------------------------- */
static ssize_t hotkey_report_mode_show(struct device *dev, static ssize_t hotkey_report_mode_show(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
@ -1878,7 +1945,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
str_supported(tp_features.hotkey)); str_supported(tp_features.hotkey));
if (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) if (!hotkey_dev_attributes)
return -ENOMEM; return -ENOMEM;
res = add_many_to_attr_set(hotkey_dev_attributes, 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); &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) if (!res)
res = register_attr_set_with_sysfs( res = register_attr_set_with_sysfs(
hotkey_dev_attributes, 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(EV_SW, tpacpi_inputdev->evbit);
set_bit(SW_RADIO, tpacpi_inputdev->swbit); 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, dbg_printk(TPACPI_DBG_INIT,
"enabling hot key handling\n"); "enabling hot key handling\n");
@ -2023,12 +2106,12 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
(hotkey_report_mode < 2) ? (hotkey_report_mode < 2) ?
"enabled" : "disabled"); "enabled" : "disabled");
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
tpacpi_inputdev->open = &hotkey_inputdev_open; tpacpi_inputdev->open = &hotkey_inputdev_open;
tpacpi_inputdev->close = &hotkey_inputdev_close; tpacpi_inputdev->close = &hotkey_inputdev_close;
hotkey_poll_setup_safe(1); hotkey_poll_setup_safe(1);
#endif tpacpi_input_send_radiosw();
tpacpi_input_send_tabletsw();
} }
return (tp_features.hotkey)? 0 : 1; 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 */ /* 0x5000-0x5FFF: human interface helpers */
switch (hkey) { switch (hkey) {
case 0x5010: /* Lenovo new BIOS: brightness changed */ 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 0x500b: /* X61t: tablet pen inserted into bay */
case 0x500c: /* X61t: tablet pen removed from bay */ case 0x500c: /* X61t: tablet pen removed from bay */
break; 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 0x5001:
case 0x5002: case 0x5002:
/* LID switch events. Do not propagate */ /* LID switch events. Do not propagate */
@ -2219,11 +2306,10 @@ static void hotkey_resume(void)
"from firmware\n"); "from firmware\n");
tpacpi_input_send_radiosw(); tpacpi_input_send_radiosw();
hotkey_radio_sw_notify_change(); hotkey_radio_sw_notify_change();
hotkey_tablet_mode_notify_change();
hotkey_wakeup_reason_notify_change(); hotkey_wakeup_reason_notify_change();
hotkey_wakeup_hotunplug_complete_notify_change(); hotkey_wakeup_hotunplug_complete_notify_change();
#ifdef CONFIG_THINKPAD_ACPI_HOTKEY_POLL
hotkey_poll_setup_safe(0); hotkey_poll_setup_safe(0);
#endif
} }
/* procfs -------------------------------------------------------------- */ /* procfs -------------------------------------------------------------- */
@ -2676,6 +2762,8 @@ static struct ibm_struct wan_driver_data = {
* Video subdriver * Video subdriver
*/ */
#ifdef CONFIG_THINKPAD_ACPI_VIDEO
enum video_access_mode { enum video_access_mode {
TPACPI_VIDEO_NONE = 0, TPACPI_VIDEO_NONE = 0,
TPACPI_VIDEO_570, /* 570 */ TPACPI_VIDEO_570, /* 570 */
@ -2703,13 +2791,6 @@ static int video_orig_autosw;
static int video_autosw_get(void); static int video_autosw_get(void);
static int video_autosw_set(int enable); 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 */ TPACPI_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID"); /* G41 */
static int __init video_init(struct ibm_init_struct *iibm) static int __init video_init(struct ibm_init_struct *iibm)
@ -3019,6 +3100,8 @@ static struct ibm_struct video_driver_data = {
.exit = video_exit, .exit = video_exit,
}; };
#endif /* CONFIG_THINKPAD_ACPI_VIDEO */
/************************************************************************* /*************************************************************************
* Light (thinklight) subdriver * Light (thinklight) subdriver
*/ */
@ -5803,10 +5886,12 @@ static struct ibm_init_struct ibms_init[] __initdata = {
.init = wan_init, .init = wan_init,
.data = &wan_driver_data, .data = &wan_driver_data,
}, },
#ifdef CONFIG_THINKPAD_ACPI_VIDEO
{ {
.init = video_init, .init = video_init,
.data = &video_driver_data, .data = &video_driver_data,
}, },
#endif
{ {
.init = light_init, .init = light_init,
.data = &light_driver_data, .data = &light_driver_data,
@ -5918,7 +6003,7 @@ MODULE_PARM_DESC(hotkey_report_mode,
#define TPACPI_PARAM(feature) \ #define TPACPI_PARAM(feature) \
module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ 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") "at module load, see documentation")
TPACPI_PARAM(hotkey); TPACPI_PARAM(hotkey);

View file

@ -242,8 +242,6 @@ EXPORT_SYMBOL(pci_osc_control_set);
* choose from highest power _SxD to lowest power _SxW * choose from highest power _SxD to lowest power _SxW
* else // no _PRW at S-state x * else // no _PRW at S-state x
* choose highest power _SxD or any lower power * 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, static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev,

View file

@ -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 *dev;
struct thermal_cooling_device_instance *pos; struct thermal_cooling_device_instance *pos;
struct thermal_zone_device *pos1;
struct thermal_cooling_device *pos2;
int result; int result;
if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE)) if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE))
return -EINVAL; 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; return -EINVAL;
dev = dev =
@ -437,20 +448,20 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
int result; int result;
if (strlen(type) >= THERMAL_NAME_LENGTH) if (strlen(type) >= THERMAL_NAME_LENGTH)
return NULL; return ERR_PTR(-EINVAL);
if (!ops || !ops->get_max_state || !ops->get_cur_state || if (!ops || !ops->get_max_state || !ops->get_cur_state ||
!ops->set_cur_state) !ops->set_cur_state)
return NULL; return ERR_PTR(-EINVAL);
cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL); cdev = kzalloc(sizeof(struct thermal_cooling_device), GFP_KERNEL);
if (!cdev) if (!cdev)
return NULL; return ERR_PTR(-ENOMEM);
result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id); result = get_idr(&thermal_cdev_idr, &thermal_idr_lock, &cdev->id);
if (result) { if (result) {
kfree(cdev); kfree(cdev);
return NULL; return ERR_PTR(result);
} }
strcpy(cdev->type, type); strcpy(cdev->type, type);
@ -462,7 +473,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
if (result) { if (result) {
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
kfree(cdev); kfree(cdev);
return NULL; return ERR_PTR(result);
} }
/* sys I/F */ /* sys I/F */
@ -498,7 +509,7 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
unregister: unregister:
release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id); release_idr(&thermal_cdev_idr, &thermal_idr_lock, cdev->id);
device_unregister(&cdev->device); device_unregister(&cdev->device);
return NULL; return ERR_PTR(result);
} }
EXPORT_SYMBOL(thermal_cooling_device_register); EXPORT_SYMBOL(thermal_cooling_device_register);
@ -570,17 +581,17 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
int count; int count;
if (strlen(type) >= THERMAL_NAME_LENGTH) if (strlen(type) >= THERMAL_NAME_LENGTH)
return NULL; return ERR_PTR(-EINVAL);
if (trips > THERMAL_MAX_TRIPS || trips < 0) if (trips > THERMAL_MAX_TRIPS || trips < 0)
return NULL; return ERR_PTR(-EINVAL);
if (!ops || !ops->get_temp) if (!ops || !ops->get_temp)
return NULL; return ERR_PTR(-EINVAL);
tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL); tz = kzalloc(sizeof(struct thermal_zone_device), GFP_KERNEL);
if (!tz) if (!tz)
return NULL; return ERR_PTR(-ENOMEM);
INIT_LIST_HEAD(&tz->cooling_devices); INIT_LIST_HEAD(&tz->cooling_devices);
idr_init(&tz->idr); 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); result = get_idr(&thermal_tz_idr, &thermal_idr_lock, &tz->id);
if (result) { if (result) {
kfree(tz); kfree(tz);
return NULL; return ERR_PTR(result);
} }
strcpy(tz->type, type); strcpy(tz->type, type);
@ -601,7 +612,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
if (result) { if (result) {
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
kfree(tz); kfree(tz);
return NULL; return ERR_PTR(result);
} }
/* sys I/F */ /* sys I/F */
@ -643,7 +654,7 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
unregister: unregister:
release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id);
device_unregister(&tz->device); device_unregister(&tz->device);
return NULL; return ERR_PTR(result);
} }
EXPORT_SYMBOL(thermal_zone_device_register); EXPORT_SYMBOL(thermal_zone_device_register);

View file

@ -1171,12 +1171,18 @@ static inline void enable_debug_pagealloc(void)
{ {
debug_pagealloc_enabled = 1; debug_pagealloc_enabled = 1;
} }
#ifdef CONFIG_HIBERNATION
extern bool kernel_page_present(struct page *page);
#endif /* CONFIG_HIBERNATION */
#else #else
static inline void static inline void
kernel_map_pages(struct page *page, int numpages, int enable) {} kernel_map_pages(struct page *page, int numpages, int enable) {}
static inline void enable_debug_pagealloc(void) 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 #endif
extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk); extern struct vm_area_struct *get_gate_vma(struct task_struct *tsk);

View file

@ -875,8 +875,8 @@ static inline void *saveable_highmem_page(unsigned long pfn) { return NULL; }
#endif /* CONFIG_HIGHMEM */ #endif /* CONFIG_HIGHMEM */
/** /**
* saveable - Determine whether a non-highmem page should be included in * saveable_page - Determine whether a non-highmem page should be included
* the suspend image. * in the suspend image.
* *
* We should save the page if it isn't Nosave, and is not in the range * 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 * 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)) if (swsusp_page_is_forbidden(page) || swsusp_page_is_free(page))
return NULL; return NULL;
if (PageReserved(page) && pfn_is_nosave(pfn)) if (PageReserved(page)
&& (!kernel_page_present(page) || pfn_is_nosave(pfn)))
return NULL; return NULL;
return page; return page;
@ -938,6 +939,25 @@ static inline void do_copy_page(long *dst, long *src)
*dst++ = *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 #ifdef CONFIG_HIGHMEM
static inline struct page * static inline struct page *
page_is_saveable(struct zone *zone, unsigned long pfn) 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); saveable_highmem_page(pfn) : saveable_page(pfn);
} }
static inline void static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
{ {
struct page *s_page, *d_page; struct page *s_page, *d_page;
void *src, *dst; 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(src, KM_USER0);
kunmap_atomic(dst, KM_USER1); kunmap_atomic(dst, KM_USER1);
} else { } else {
src = page_address(s_page);
if (PageHighMem(d_page)) { if (PageHighMem(d_page)) {
/* Page pointed to by src may contain some kernel /* Page pointed to by src may contain some kernel
* data modified by kmap_atomic() * 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); dst = kmap_atomic(pfn_to_page(dst_pfn), KM_USER0);
memcpy(dst, buffer, PAGE_SIZE); memcpy(dst, buffer, PAGE_SIZE);
kunmap_atomic(dst, KM_USER0); kunmap_atomic(dst, KM_USER0);
} else { } else {
dst = page_address(d_page); safe_copy_page(page_address(d_page), s_page);
do_copy_page(dst, src);
} }
} }
} }
#else #else
#define page_is_saveable(zone, pfn) saveable_page(pfn) #define page_is_saveable(zone, pfn) saveable_page(pfn)
static inline void static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
copy_data_page(unsigned long dst_pfn, unsigned long src_pfn)
{ {
do_copy_page(page_address(pfn_to_page(dst_pfn)), safe_copy_page(page_address(pfn_to_page(dst_pfn)),
page_address(pfn_to_page(src_pfn))); pfn_to_page(src_pfn));
} }
#endif /* CONFIG_HIGHMEM */ #endif /* CONFIG_HIGHMEM */