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
|
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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue