mirror of
https://github.com/adulau/aha.git
synced 2024-12-26 10:46:11 +00:00
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: (117 commits) ACPI processor: Fix section mismatch for processor_add() ACPI: Add platform-wide _OSC support. ACPI: cleanup pci_root _OSC code. ACPI: Add a generic API for _OSC -v2 msi-wmi: depend on backlight and fix corner-cases problems msi-wmi: switch to using input sparse keymap library msi-wmi: replace one-condition switch-case with if statement msi-wmi: remove unused field 'instance' in key_entry structure msi-wmi: remove custom runtime debug implementation msi-wmi: rework init msi-wmi: remove useless includes X86 drivers: Introduce msi-wmi driver Toshiba Bluetooth Enabling driver (RFKill handler v3) ACPI: fix for lapic_timer_propagate_broadcast() acpi_pad: squish warning ACPI: dock: minor whitespace and style cleanups ACPI: dock: add struct dock_station * directly to platform device data ACPI: dock: dock_add - hoist up platform_device_register_simple() ACPI: dock: remove global 'dock_device_name' ACPI: dock: combine add|alloc_dock_dependent_device (v2) ...
This commit is contained in:
commit
288f02bbb6
66 changed files with 4204 additions and 1803 deletions
66
Documentation/acpi/method-customizing.txt
Normal file
66
Documentation/acpi/method-customizing.txt
Normal file
|
@ -0,0 +1,66 @@
|
|||
Linux ACPI Custom Control Method How To
|
||||
=======================================
|
||||
|
||||
Written by Zhang Rui <rui.zhang@intel.com>
|
||||
|
||||
|
||||
Linux supports customizing ACPI control methods at runtime.
|
||||
|
||||
Users can use this to
|
||||
1. override an existing method which may not work correctly,
|
||||
or just for debugging purposes.
|
||||
2. insert a completely new method in order to create a missing
|
||||
method such as _OFF, _ON, _STA, _INI, etc.
|
||||
For these cases, it is far simpler to dynamically install a single
|
||||
control method rather than override the entire DSDT, because kernel
|
||||
rebuild/reboot is not needed and test result can be got in minutes.
|
||||
|
||||
Note: Only ACPI METHOD can be overridden, any other object types like
|
||||
"Device", "OperationRegion", are not recognized.
|
||||
Note: The same ACPI control method can be overridden for many times,
|
||||
and it's always the latest one that used by Linux/kernel.
|
||||
|
||||
1. override an existing method
|
||||
a) get the ACPI table via ACPI sysfs I/F. e.g. to get the DSDT,
|
||||
just run "cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.dat"
|
||||
b) disassemble the table by running "iasl -d dsdt.dat".
|
||||
c) rewrite the ASL code of the method and save it in a new file,
|
||||
d) package the new file (psr.asl) to an ACPI table format.
|
||||
Here is an example of a customized \_SB._AC._PSR method,
|
||||
|
||||
DefinitionBlock ("", "SSDT", 1, "", "", 0x20080715)
|
||||
{
|
||||
External (ACON)
|
||||
|
||||
Method (\_SB_.AC._PSR, 0, NotSerialized)
|
||||
{
|
||||
Store ("In AC _PSR", Debug)
|
||||
Return (ACON)
|
||||
}
|
||||
}
|
||||
Note that the full pathname of the method in ACPI namespace
|
||||
should be used.
|
||||
And remember to use "External" to declare external objects.
|
||||
e) assemble the file to generate the AML code of the method.
|
||||
e.g. "iasl psr.asl" (psr.aml is generated as a result)
|
||||
f) mount debugfs by "mount -t debugfs none /sys/kernel/debug"
|
||||
g) override the old method via the debugfs by running
|
||||
"cat /tmp/psr.aml > /sys/kernel/debug/acpi/custom_method"
|
||||
|
||||
2. insert a new method
|
||||
This is easier than overriding an existing method.
|
||||
We just need to create the ASL code of the method we want to
|
||||
insert and then follow the step c) ~ g) in section 1.
|
||||
|
||||
3. undo your changes
|
||||
The "undo" operation is not supported for a new inserted method
|
||||
right now, i.e. we can not remove a method currently.
|
||||
For an overrided method, in order to undo your changes, please
|
||||
save a copy of the method original ASL code in step c) section 1,
|
||||
and redo step c) ~ g) to override the method with the original one.
|
||||
|
||||
|
||||
Note: We can use a kernel with multiple custom ACPI method running,
|
||||
But each individual write to debugfs can implement a SINGLE
|
||||
method override. i.e. if we want to insert/override multiple
|
||||
ACPI methods, we need to redo step c) ~ g) for multiple times.
|
|
@ -474,3 +474,22 @@ Why: Obsoleted by the adt7475 driver.
|
|||
Who: Jean Delvare <khali@linux-fr.org>
|
||||
|
||||
---------------------------
|
||||
What: Support for lcd_switch and display_get in asus-laptop driver
|
||||
When: March 2010
|
||||
Why: These two features use non-standard interfaces. There are the
|
||||
only features that really need multiple path to guess what's
|
||||
the right method name on a specific laptop.
|
||||
|
||||
Removing them will allow to remove a lot of code an significantly
|
||||
clean the drivers.
|
||||
|
||||
This will affect the backlight code which won't be able to know
|
||||
if the backlight is on or off. The platform display file will also be
|
||||
write only (like the one in eeepc-laptop).
|
||||
|
||||
This should'nt affect a lot of user because they usually know
|
||||
when their display is on or off.
|
||||
|
||||
Who: Corentin Chary <corentin.chary@gmail.com>
|
||||
|
||||
----------------------------
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
ThinkPad ACPI Extras Driver
|
||||
|
||||
Version 0.23
|
||||
April 10th, 2009
|
||||
Version 0.24
|
||||
December 11th, 2009
|
||||
|
||||
Borislav Deianov <borislav@users.sf.net>
|
||||
Henrique de Moraes Holschuh <hmh@hmh.eng.br>
|
||||
|
@ -460,6 +460,8 @@ event code Key Notes
|
|||
For Lenovo ThinkPads with a new
|
||||
BIOS, it has to be handled either
|
||||
by the ACPI OSI, or by userspace.
|
||||
The driver does the right thing,
|
||||
never mess with this.
|
||||
0x1011 0x10 FN+END Brightness down. See brightness
|
||||
up for details.
|
||||
|
||||
|
@ -582,46 +584,15 @@ with hotkey_report_mode.
|
|||
|
||||
Brightness hotkey notes:
|
||||
|
||||
These are the current sane choices for brightness key mapping in
|
||||
thinkpad-acpi:
|
||||
Don't mess with the brightness hotkeys in a Thinkpad. If you want
|
||||
notifications for OSD, use the sysfs backlight class event support.
|
||||
|
||||
For IBM and Lenovo models *without* ACPI backlight control (the ones on
|
||||
which thinkpad-acpi will autoload its backlight interface by default,
|
||||
and on which ACPI video does not export a backlight interface):
|
||||
|
||||
1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as
|
||||
these older firmware versions unfortunately won't respect the hotkey
|
||||
mask for brightness keys anyway, and always reacts to them. This
|
||||
usually work fine, unless X.org drivers are doing something to block
|
||||
the BIOS. In that case, use (3) below. This is the default mode of
|
||||
operation.
|
||||
|
||||
2. Enable the hotkeys, but map them to something else that is NOT
|
||||
KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause
|
||||
userspace to try to change the backlight level, and use that as an
|
||||
on-screen-display hint.
|
||||
|
||||
3. IF AND ONLY IF X.org drivers find a way to block the firmware from
|
||||
automatically changing the brightness, enable the hotkeys and map
|
||||
them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to
|
||||
something that calls xbacklight. thinkpad-acpi will not be able to
|
||||
change brightness in that case either, so you should disable its
|
||||
backlight interface.
|
||||
|
||||
For Lenovo models *with* ACPI backlight control:
|
||||
|
||||
1. Load up ACPI video and use that. ACPI video will report ACPI
|
||||
events for brightness change keys. Do not mess with thinkpad-acpi
|
||||
defaults in this case. thinkpad-acpi should not have anything to do
|
||||
with backlight events in a scenario where ACPI video is loaded:
|
||||
brightness hotkeys must be disabled, and the backlight interface is
|
||||
to be kept disabled as well. This is the default mode of operation.
|
||||
|
||||
2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi,
|
||||
and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process
|
||||
these keys on userspace somehow (e.g. by calling xbacklight).
|
||||
The driver will do this automatically if it detects that ACPI video
|
||||
has been disabled.
|
||||
The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN events
|
||||
automatically for the cases were userspace has to do something to
|
||||
implement brightness changes. When you override these events, you will
|
||||
either fail to handle properly the ThinkPads that require explicit
|
||||
action to change backlight brightness, or the ThinkPads that require
|
||||
that no action be taken to work properly.
|
||||
|
||||
|
||||
Bluetooth
|
||||
|
@ -1121,25 +1092,61 @@ WARNING:
|
|||
its level up and down at every change.
|
||||
|
||||
|
||||
Volume control -- /proc/acpi/ibm/volume
|
||||
---------------------------------------
|
||||
Volume control
|
||||
--------------
|
||||
|
||||
This feature allows volume control on ThinkPad models which don't have
|
||||
a hardware volume knob. The available commands are:
|
||||
procfs: /proc/acpi/ibm/volume
|
||||
ALSA: "ThinkPad Console Audio Control", default ID: "ThinkPadEC"
|
||||
|
||||
NOTE: by default, the volume control interface operates in read-only
|
||||
mode, as it is supposed to be used for on-screen-display purposes.
|
||||
The read/write mode can be enabled through the use of the
|
||||
"volume_control=1" module parameter.
|
||||
|
||||
NOTE: distros are urged to not enable volume_control by default, this
|
||||
should be done by the local admin only. The ThinkPad UI is for the
|
||||
console audio control to be done through the volume keys only, and for
|
||||
the desktop environment to just provide on-screen-display feedback.
|
||||
Software volume control should be done only in the main AC97/HDA
|
||||
mixer.
|
||||
|
||||
This feature allows volume control on ThinkPad models with a digital
|
||||
volume knob (when available, not all models have it), as well as
|
||||
mute/unmute control. The available commands are:
|
||||
|
||||
echo up >/proc/acpi/ibm/volume
|
||||
echo down >/proc/acpi/ibm/volume
|
||||
echo mute >/proc/acpi/ibm/volume
|
||||
echo unmute >/proc/acpi/ibm/volume
|
||||
echo 'level <level>' >/proc/acpi/ibm/volume
|
||||
|
||||
The <level> number range is 0 to 15 although not all of them may be
|
||||
The <level> number range is 0 to 14 although not all of them may be
|
||||
distinct. The unmute the volume after the mute command, use either the
|
||||
up or down command (the level command will not unmute the volume).
|
||||
up or down command (the level command will not unmute the volume), or
|
||||
the unmute command.
|
||||
|
||||
The current volume level and mute state is shown in the file.
|
||||
|
||||
The ALSA mixer interface to this feature is still missing, but patches
|
||||
to add it exist. That problem should be addressed in the not so
|
||||
distant future.
|
||||
You can use the volume_capabilities parameter to tell the driver
|
||||
whether your thinkpad has volume control or mute-only control:
|
||||
volume_capabilities=1 for mixers with mute and volume control,
|
||||
volume_capabilities=2 for mixers with only mute control.
|
||||
|
||||
If the driver misdetects the capabilities for your ThinkPad model,
|
||||
please report this to ibm-acpi-devel@lists.sourceforge.net, so that we
|
||||
can update the driver.
|
||||
|
||||
There are two strategies for volume control. To select which one
|
||||
should be used, use the volume_mode module parameter: volume_mode=1
|
||||
selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing
|
||||
(so that volume/mute changes are remembered across shutdown/reboot).
|
||||
|
||||
The driver will operate in volume_mode=3 by default. If that does not
|
||||
work well on your ThinkPad model, please report this to
|
||||
ibm-acpi-devel@lists.sourceforge.net.
|
||||
|
||||
The driver supports the standard ALSA module parameters. If the ALSA
|
||||
mixer is disabled, the driver will disable all volume functionality.
|
||||
|
||||
|
||||
Fan control and monitoring: fan speed, fan enable/disable
|
||||
|
@ -1405,6 +1412,7 @@ to enable more than one output class, just add their values.
|
|||
0x0008 HKEY event interface, hotkeys
|
||||
0x0010 Fan control
|
||||
0x0020 Backlight brightness
|
||||
0x0040 Audio mixer/volume control
|
||||
|
||||
There is also a kernel build option to enable more debugging
|
||||
information, which may be necessary to debug driver problems.
|
||||
|
@ -1465,3 +1473,9 @@ Sysfs interface changelog:
|
|||
and it is always able to disable hot keys. Very old
|
||||
thinkpads are properly supported. hotkey_bios_mask
|
||||
is deprecated and marked for removal.
|
||||
|
||||
0x020600: Marker for backlight change event support.
|
||||
|
||||
0x020700: Support for mute-only mixers.
|
||||
Volume control in read-only mode by default.
|
||||
Marker for ALSA mixer support.
|
||||
|
|
|
@ -206,6 +206,7 @@ passive
|
|||
passive trip point for the zone. Activation is done by polling with
|
||||
an interval of 1 second.
|
||||
Unit: millidegrees Celsius
|
||||
Valid values: 0 (disabled) or greater than 1000
|
||||
RW, Optional
|
||||
|
||||
*****************************
|
||||
|
|
|
@ -48,7 +48,7 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
|
|||
* P4, Core and beyond CPUs
|
||||
*/
|
||||
if (c->x86_vendor == X86_VENDOR_INTEL &&
|
||||
(c->x86 > 0xf || (c->x86 == 6 && c->x86_model >= 14)))
|
||||
(c->x86 > 0xf || (c->x86 == 6 && c->x86_model >= 0x0f)))
|
||||
flags->bm_control = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
|
||||
|
|
|
@ -100,7 +100,8 @@ static void round_robin_cpu(unsigned int tsk_index)
|
|||
struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits);
|
||||
cpumask_var_t tmp;
|
||||
int cpu;
|
||||
unsigned long min_weight = -1, preferred_cpu;
|
||||
unsigned long min_weight = -1;
|
||||
unsigned long uninitialized_var(preferred_cpu);
|
||||
|
||||
if (!alloc_cpumask_var(&tmp, GFP_KERNEL))
|
||||
return;
|
||||
|
|
|
@ -296,6 +296,11 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data,
|
|||
acpi_status validate_status,
|
||||
union acpi_operand_object **return_object_ptr);
|
||||
|
||||
void
|
||||
acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
|
||||
u8 package_type,
|
||||
union acpi_operand_object *obj_desc);
|
||||
|
||||
/*
|
||||
* nssearch - Namespace searching and entry
|
||||
*/
|
||||
|
@ -354,9 +359,7 @@ acpi_ns_externalize_name(u32 internal_name_length,
|
|||
const char *internal_name,
|
||||
u32 * converted_name_length, char **converted_name);
|
||||
|
||||
struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle);
|
||||
|
||||
acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node);
|
||||
struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle);
|
||||
|
||||
void acpi_ns_terminate(void);
|
||||
|
||||
|
|
|
@ -180,7 +180,11 @@ struct acpi_object_method {
|
|||
u8 sync_level;
|
||||
union acpi_operand_object *mutex;
|
||||
u8 *aml_start;
|
||||
ACPI_INTERNAL_METHOD implementation;
|
||||
union {
|
||||
ACPI_INTERNAL_METHOD implementation;
|
||||
union acpi_operand_object *handler;
|
||||
} extra;
|
||||
|
||||
u32 aml_length;
|
||||
u8 thread_count;
|
||||
acpi_owner_id owner_id;
|
||||
|
|
|
@ -414,7 +414,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
|
|||
/* Invoke an internal method if necessary */
|
||||
|
||||
if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
|
||||
status = obj_desc->method.implementation(next_walk_state);
|
||||
status = obj_desc->method.extra.implementation(next_walk_state);
|
||||
if (status == AE_OK) {
|
||||
status = AE_CTRL_TERMINATE;
|
||||
}
|
||||
|
|
|
@ -212,18 +212,19 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
|
|||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
/*
|
||||
* These types we will allow, but we will change the type. This
|
||||
* enables some existing code of the form:
|
||||
* These types we will allow, but we will change the type.
|
||||
* This enables some existing code of the form:
|
||||
*
|
||||
* Name (DEB, 0)
|
||||
* Scope (DEB) { ... }
|
||||
*
|
||||
* Note: silently change the type here. On the second pass, we will report
|
||||
* a warning
|
||||
* Note: silently change the type here. On the second pass,
|
||||
* we will report a warning
|
||||
*/
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
|
||||
"Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
|
||||
path,
|
||||
"Type override - [%4.4s] had invalid type (%s) "
|
||||
"for Scope operator, changed to type ANY\n",
|
||||
acpi_ut_get_node_name(node),
|
||||
acpi_ut_get_type_name(node->type)));
|
||||
|
||||
node->type = ACPI_TYPE_ANY;
|
||||
|
@ -235,8 +236,10 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
|
|||
/* All other types are an error */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)",
|
||||
acpi_ut_get_type_name(node->type), path));
|
||||
"Invalid type (%s) for target of "
|
||||
"Scope operator [%4.4s] (Cannot override)",
|
||||
acpi_ut_get_type_name(node->type),
|
||||
acpi_ut_get_node_name(node)));
|
||||
|
||||
return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
@ -697,15 +700,16 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
|
|||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
/*
|
||||
* These types we will allow, but we will change the type. This
|
||||
* enables some existing code of the form:
|
||||
* These types we will allow, but we will change the type.
|
||||
* This enables some existing code of the form:
|
||||
*
|
||||
* Name (DEB, 0)
|
||||
* Scope (DEB) { ... }
|
||||
*/
|
||||
ACPI_WARNING((AE_INFO,
|
||||
"Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)",
|
||||
buffer_ptr,
|
||||
"Type override - [%4.4s] had invalid type (%s) "
|
||||
"for Scope operator, changed to type ANY\n",
|
||||
acpi_ut_get_node_name(node),
|
||||
acpi_ut_get_type_name(node->type)));
|
||||
|
||||
node->type = ACPI_TYPE_ANY;
|
||||
|
@ -717,9 +721,10 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
|
|||
/* All other types are an error */
|
||||
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Invalid type (%s) for target of Scope operator [%4.4s]",
|
||||
"Invalid type (%s) for target of "
|
||||
"Scope operator [%4.4s] (Cannot override)",
|
||||
acpi_ut_get_type_name(node->type),
|
||||
buffer_ptr));
|
||||
acpi_ut_get_node_name(node)));
|
||||
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
@ -1047,9 +1052,22 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
|
|||
}
|
||||
|
||||
/*
|
||||
* If we are executing a method, initialize the region
|
||||
* The op_region is not fully parsed at this time. The only valid
|
||||
* argument is the space_id. (We must save the address of the
|
||||
* AML of the address and length operands)
|
||||
*
|
||||
* If we have a valid region, initialize it. The namespace is
|
||||
* unlocked at this point.
|
||||
*
|
||||
* Need to unlock interpreter if it is locked (if we are running
|
||||
* a control method), in order to allow _REG methods to be run
|
||||
* during acpi_ev_initialize_region.
|
||||
*/
|
||||
if (walk_state->method_node) {
|
||||
/*
|
||||
* Executing a method: initialize the region and unlock
|
||||
* the interpreter
|
||||
*/
|
||||
status =
|
||||
acpi_ex_create_region(op->named.data,
|
||||
op->named.length,
|
||||
|
@ -1058,21 +1076,17 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state)
|
|||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
|
||||
acpi_ex_exit_interpreter();
|
||||
}
|
||||
|
||||
/*
|
||||
* The op_region is not fully parsed at this time. Only valid
|
||||
* argument is the space_id. (We must save the address of the
|
||||
* AML of the address and length operands)
|
||||
*/
|
||||
|
||||
/*
|
||||
* If we have a valid region, initialize it
|
||||
* Namespace is NOT locked at this point.
|
||||
*/
|
||||
status =
|
||||
acpi_ev_initialize_region
|
||||
(acpi_ns_get_attached_object(node), FALSE);
|
||||
if (walk_state->method_node) {
|
||||
acpi_ex_enter_interpreter();
|
||||
}
|
||||
|
||||
if (ACPI_FAILURE(status)) {
|
||||
/*
|
||||
* If AE_NOT_EXIST is returned, it is not fatal
|
||||
|
|
|
@ -718,7 +718,7 @@ acpi_ev_install_handler(acpi_handle obj_handle,
|
|||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
node = acpi_ns_validate_handle(obj_handle);
|
||||
if (!node) {
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
@ -1087,7 +1087,7 @@ acpi_ev_reg_run(acpi_handle obj_handle,
|
|||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
node = acpi_ns_validate_handle(obj_handle);
|
||||
if (!node) {
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
|
|
@ -575,6 +575,21 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj,
|
|||
handler_obj = obj_desc->thermal_zone.handler;
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_METHOD:
|
||||
/*
|
||||
* If we are executing module level code, the original
|
||||
* Node's object was replaced by this Method object and we
|
||||
* saved the handler in the method object.
|
||||
*
|
||||
* See acpi_ns_exec_module_code
|
||||
*/
|
||||
if (obj_desc->method.
|
||||
flags & AOPOBJ_MODULE_LEVEL) {
|
||||
handler_obj =
|
||||
obj_desc->method.extra.handler;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* Ignore other objects */
|
||||
break;
|
||||
|
|
|
@ -259,7 +259,7 @@ acpi_install_notify_handler(acpi_handle device,
|
|||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(device);
|
||||
node = acpi_ns_validate_handle(device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -425,7 +425,7 @@ acpi_remove_notify_handler(acpi_handle device,
|
|||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(device);
|
||||
node = acpi_ns_validate_handle(device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
|
|
@ -610,7 +610,7 @@ acpi_install_gpe_block(acpi_handle gpe_device,
|
|||
return (status);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(gpe_device);
|
||||
node = acpi_ns_validate_handle(gpe_device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -698,7 +698,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device)
|
|||
return (status);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(gpe_device);
|
||||
node = acpi_ns_validate_handle(gpe_device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
|
|
@ -89,7 +89,7 @@ acpi_install_address_space_handler(acpi_handle device,
|
|||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(device);
|
||||
node = acpi_ns_validate_handle(device);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -155,7 +155,7 @@ acpi_remove_address_space_handler(acpi_handle device,
|
|||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(device);
|
||||
node = acpi_ns_validate_handle(device);
|
||||
if (!node ||
|
||||
((node->type != ACPI_TYPE_DEVICE) &&
|
||||
(node->type != ACPI_TYPE_PROCESSOR) &&
|
||||
|
|
|
@ -375,6 +375,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
|
|||
return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
|
||||
}
|
||||
|
||||
/* Must have a valid thread ID */
|
||||
|
||||
if (!walk_state->thread) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Cannot release Mutex [%4.4s], null thread info",
|
||||
acpi_ut_get_node_name(obj_desc->mutex.node)));
|
||||
return_ACPI_STATUS(AE_AML_INTERNAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Mutex is owned, but this thread must be the owner.
|
||||
* Special case for Global Lock, any thread can release
|
||||
|
@ -392,15 +401,6 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
|
|||
return_ACPI_STATUS(AE_AML_NOT_OWNER);
|
||||
}
|
||||
|
||||
/* Must have a valid thread ID */
|
||||
|
||||
if (!walk_state->thread) {
|
||||
ACPI_ERROR((AE_INFO,
|
||||
"Cannot release Mutex [%4.4s], null thread info",
|
||||
acpi_ut_get_node_name(obj_desc->mutex.node)));
|
||||
return_ACPI_STATUS(AE_AML_INTERNAL);
|
||||
}
|
||||
|
||||
/*
|
||||
* The sync level of the mutex must be equal to the current sync level. In
|
||||
* other words, the current level means that at least one mutex at that
|
||||
|
|
|
@ -165,7 +165,7 @@ acpi_status acpi_ns_root_initialize(void)
|
|||
|
||||
obj_desc->method.method_flags =
|
||||
AML_METHOD_INTERNAL_ONLY;
|
||||
obj_desc->method.implementation =
|
||||
obj_desc->method.extra.implementation =
|
||||
acpi_ut_osi_implementation;
|
||||
#endif
|
||||
break;
|
||||
|
|
|
@ -180,7 +180,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
|
|||
return (AE_OK);
|
||||
}
|
||||
|
||||
this_node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
this_node = acpi_ns_validate_handle(obj_handle);
|
||||
if (!this_node) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n",
|
||||
obj_handle));
|
||||
|
|
|
@ -381,6 +381,18 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
|
|||
method_obj->method.next_object);
|
||||
type = acpi_ns_get_type(parent_node);
|
||||
|
||||
/*
|
||||
* Get the region handler and save it in the method object. We may need
|
||||
* this if an operation region declaration causes a _REG method to be run.
|
||||
*
|
||||
* We can't do this in acpi_ps_link_module_code because
|
||||
* acpi_gbl_root_node->Object is NULL at PASS1.
|
||||
*/
|
||||
if ((type == ACPI_TYPE_DEVICE) && parent_node->object) {
|
||||
method_obj->method.extra.handler =
|
||||
parent_node->object->device.handler;
|
||||
}
|
||||
|
||||
/* Must clear next_object (acpi_ns_attach_object needs the field) */
|
||||
|
||||
method_obj->method.next_object = NULL;
|
||||
|
@ -415,6 +427,12 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj,
|
|||
ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n",
|
||||
method_obj->method.aml_start));
|
||||
|
||||
/* Delete a possible implicit return value (in slack mode) */
|
||||
|
||||
if (info->return_object) {
|
||||
acpi_ut_remove_reference(info->return_object);
|
||||
}
|
||||
|
||||
/* Detach the temporary method object */
|
||||
|
||||
acpi_ns_detach_object(parent_node);
|
||||
|
|
|
@ -232,7 +232,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle,
|
|||
|
||||
ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle);
|
||||
|
||||
node = acpi_ns_map_handle_to_node(target_handle);
|
||||
node = acpi_ns_validate_handle(target_handle);
|
||||
if (!node) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
|
|
@ -216,29 +216,38 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node,
|
|||
data->pathname = pathname;
|
||||
|
||||
/*
|
||||
* Check that the type of the return object is what is expected for
|
||||
* this predefined name
|
||||
* Check that the type of the main return object is what is expected
|
||||
* for this predefined name
|
||||
*/
|
||||
status = acpi_ns_check_object_type(data, return_object_ptr,
|
||||
predefined->info.expected_btypes,
|
||||
ACPI_NOT_PACKAGE_ELEMENT);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto check_validation_status;
|
||||
}
|
||||
|
||||
/* For returned Package objects, check the type of all sub-objects */
|
||||
|
||||
if (return_object->common.type == ACPI_TYPE_PACKAGE) {
|
||||
status = acpi_ns_check_package(data, return_object_ptr);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Perform additional, more complicated repairs on a per-name
|
||||
* basis.
|
||||
* For returned Package objects, check the type of all sub-objects.
|
||||
* Note: Package may have been newly created by call above.
|
||||
*/
|
||||
if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) {
|
||||
status = acpi_ns_check_package(data, return_object_ptr);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The return object was OK, or it was successfully repaired above.
|
||||
* Now make some additional checks such as verifying that package
|
||||
* objects are sorted correctly (if required) or buffer objects have
|
||||
* the correct data width (bytes vs. dwords). These repairs are
|
||||
* performed on a per-name basis, i.e., the code is specific to
|
||||
* particular predefined names.
|
||||
*/
|
||||
status = acpi_ns_complex_repairs(data, node, status, return_object_ptr);
|
||||
|
||||
check_validation_status:
|
||||
exit:
|
||||
/*
|
||||
* If the object validation failed or if we successfully repaired one
|
||||
* or more objects, mark the parent node to suppress further warning
|
||||
|
@ -427,6 +436,13 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
|
|||
data->pathname, package->ret_info.type,
|
||||
return_object->package.count));
|
||||
|
||||
/*
|
||||
* For variable-length Packages, we can safely remove all embedded
|
||||
* and trailing NULL package elements
|
||||
*/
|
||||
acpi_ns_remove_null_elements(data, package->ret_info.type,
|
||||
return_object);
|
||||
|
||||
/* Extract package count and elements array */
|
||||
|
||||
elements = return_object->package.elements;
|
||||
|
@ -461,11 +477,11 @@ acpi_ns_check_package(struct acpi_predefined_data *data,
|
|||
if (count < expected_count) {
|
||||
goto package_too_small;
|
||||
} else if (count > expected_count) {
|
||||
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
|
||||
data->node_flags,
|
||||
"Return Package is larger than needed - "
|
||||
"found %u, expected %u", count,
|
||||
expected_count));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
|
||||
"%s: Return Package is larger than needed - "
|
||||
"found %u, expected %u\n",
|
||||
data->pathname, count,
|
||||
expected_count));
|
||||
}
|
||||
|
||||
/* Validate all elements of the returned package */
|
||||
|
@ -680,53 +696,18 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data,
|
|||
union acpi_operand_object *sub_package;
|
||||
union acpi_operand_object **sub_elements;
|
||||
acpi_status status;
|
||||
u8 non_trailing_null = FALSE;
|
||||
u32 expected_count;
|
||||
u32 i;
|
||||
u32 j;
|
||||
|
||||
/* Validate each sub-Package in the parent Package */
|
||||
|
||||
/*
|
||||
* Validate each sub-Package in the parent Package
|
||||
*
|
||||
* NOTE: assumes list of sub-packages contains no NULL elements.
|
||||
* Any NULL elements should have been removed by earlier call
|
||||
* to acpi_ns_remove_null_elements.
|
||||
*/
|
||||
for (i = 0; i < count; i++) {
|
||||
/*
|
||||
* Handling for NULL package elements. For now, we will simply allow
|
||||
* a parent package with trailing NULL elements. This can happen if
|
||||
* the package was defined to be longer than the initializer list.
|
||||
* This is legal as per the ACPI specification. It is often used
|
||||
* to allow for dynamic initialization of a Package.
|
||||
*
|
||||
* A future enhancement may be to simply truncate the package to
|
||||
* remove the trailing NULL elements.
|
||||
*/
|
||||
if (!(*elements)) {
|
||||
if (!non_trailing_null) {
|
||||
|
||||
/* Ensure the remaining elements are all NULL */
|
||||
|
||||
for (j = 1; j < (count - i + 1); j++) {
|
||||
if (elements[j]) {
|
||||
non_trailing_null = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (!non_trailing_null) {
|
||||
|
||||
/* Ignore the trailing NULL elements */
|
||||
|
||||
return (AE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
/* There are trailing non-null elements, issue warning */
|
||||
|
||||
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
|
||||
data->node_flags,
|
||||
"Found NULL element at package index %u",
|
||||
i));
|
||||
elements++;
|
||||
continue;
|
||||
}
|
||||
|
||||
sub_package = *elements;
|
||||
sub_elements = sub_package->package.elements;
|
||||
|
||||
|
|
|
@ -45,11 +45,50 @@
|
|||
#include "accommon.h"
|
||||
#include "acnamesp.h"
|
||||
#include "acinterp.h"
|
||||
#include "acpredef.h"
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsrepair")
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* This module attempts to repair or convert objects returned by the
|
||||
* predefined methods to an object type that is expected, as per the ACPI
|
||||
* specification. The need for this code is dictated by the many machines that
|
||||
* return incorrect types for the standard predefined methods. Performing these
|
||||
* conversions here, in one place, eliminates the need for individual ACPI
|
||||
* device drivers to do the same. Note: Most of these conversions are different
|
||||
* than the internal object conversion routines used for implicit object
|
||||
* conversion.
|
||||
*
|
||||
* The following conversions can be performed as necessary:
|
||||
*
|
||||
* Integer -> String
|
||||
* Integer -> Buffer
|
||||
* String -> Integer
|
||||
* String -> Buffer
|
||||
* Buffer -> Integer
|
||||
* Buffer -> String
|
||||
* Buffer -> Package of Integers
|
||||
* Package -> Package of one Package
|
||||
*
|
||||
******************************************************************************/
|
||||
/* Local prototypes */
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_string(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_package(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object);
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_repair_object
|
||||
|
@ -68,6 +107,7 @@ ACPI_MODULE_NAME("nsrepair")
|
|||
* not expected.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_status
|
||||
acpi_ns_repair_object(struct acpi_predefined_data *data,
|
||||
u32 expected_btypes,
|
||||
|
@ -76,98 +116,46 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
|
|||
{
|
||||
union acpi_operand_object *return_object = *return_object_ptr;
|
||||
union acpi_operand_object *new_object;
|
||||
acpi_size length;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_NAME(ns_repair_object);
|
||||
|
||||
/*
|
||||
* At this point, we know that the type of the returned object was not
|
||||
* one of the expected types for this predefined name. Attempt to
|
||||
* repair the object. Only a limited number of repairs are possible.
|
||||
* repair the object by converting it to one of the expected object
|
||||
* types for this predefined name.
|
||||
*/
|
||||
switch (return_object->common.type) {
|
||||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
/* Does the method/object legally return a string? */
|
||||
|
||||
if (!(expected_btypes & ACPI_RTYPE_STRING)) {
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
if (expected_btypes & ACPI_RTYPE_INTEGER) {
|
||||
status = acpi_ns_convert_to_integer(return_object, &new_object);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
goto object_repaired;
|
||||
}
|
||||
|
||||
/*
|
||||
* Have a Buffer, expected a String, convert. Use a to_string
|
||||
* conversion, no transform performed on the buffer data. The best
|
||||
* example of this is the _BIF method, where the string data from
|
||||
* the battery is often (incorrectly) returned as buffer object(s).
|
||||
*/
|
||||
length = 0;
|
||||
while ((length < return_object->buffer.length) &&
|
||||
(return_object->buffer.pointer[length])) {
|
||||
length++;
|
||||
}
|
||||
|
||||
/* Allocate a new string object */
|
||||
|
||||
new_object = acpi_ut_create_string_object(length);
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the raw buffer data with no transform. String is already NULL
|
||||
* terminated at Length+1.
|
||||
*/
|
||||
ACPI_MEMCPY(new_object->string.pointer,
|
||||
return_object->buffer.pointer, length);
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_INTEGER:
|
||||
|
||||
/* 1) Does the method/object legally return a buffer? */
|
||||
|
||||
if (expected_btypes & ACPI_RTYPE_BUFFER) {
|
||||
/*
|
||||
* Convert the Integer to a packed-byte buffer. _MAT needs
|
||||
* this sometimes, if a read has been performed on a Field
|
||||
* object that is less than or equal to the global integer
|
||||
* size (32 or 64 bits).
|
||||
*/
|
||||
status =
|
||||
acpi_ex_convert_to_buffer(return_object,
|
||||
&new_object);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
}
|
||||
|
||||
/* 2) Does the method/object legally return a string? */
|
||||
|
||||
else if (expected_btypes & ACPI_RTYPE_STRING) {
|
||||
/*
|
||||
* The only supported Integer-to-String conversion is to convert
|
||||
* an integer of value 0 to a NULL string. The last element of
|
||||
* _BIF and _BIX packages occasionally need this fix.
|
||||
*/
|
||||
if (return_object->integer.value != 0) {
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/* Allocate a new NULL string object */
|
||||
|
||||
new_object = acpi_ut_create_string_object(0);
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
} else {
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/* We cannot repair this object */
|
||||
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
if (expected_btypes & ACPI_RTYPE_STRING) {
|
||||
status = acpi_ns_convert_to_string(return_object, &new_object);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
goto object_repaired;
|
||||
}
|
||||
}
|
||||
if (expected_btypes & ACPI_RTYPE_BUFFER) {
|
||||
status = acpi_ns_convert_to_buffer(return_object, &new_object);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
goto object_repaired;
|
||||
}
|
||||
}
|
||||
if (expected_btypes & ACPI_RTYPE_PACKAGE) {
|
||||
status = acpi_ns_convert_to_package(return_object, &new_object);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
goto object_repaired;
|
||||
}
|
||||
}
|
||||
|
||||
/* We cannot repair this object */
|
||||
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
|
||||
object_repaired:
|
||||
|
||||
/* Object was successfully repaired */
|
||||
|
||||
|
@ -185,19 +173,18 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
|
|||
return_object->common.reference_count--;
|
||||
}
|
||||
|
||||
ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
|
||||
"Converted %s to expected %s at index %u",
|
||||
acpi_ut_get_object_type_name
|
||||
(return_object),
|
||||
acpi_ut_get_object_type_name(new_object),
|
||||
package_index));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
|
||||
"%s: Converted %s to expected %s at index %u\n",
|
||||
data->pathname,
|
||||
acpi_ut_get_object_type_name(return_object),
|
||||
acpi_ut_get_object_type_name(new_object),
|
||||
package_index));
|
||||
} else {
|
||||
ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
|
||||
"Converted %s to expected %s",
|
||||
acpi_ut_get_object_type_name
|
||||
(return_object),
|
||||
acpi_ut_get_object_type_name
|
||||
(new_object)));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
|
||||
"%s: Converted %s to expected %s\n",
|
||||
data->pathname,
|
||||
acpi_ut_get_object_type_name(return_object),
|
||||
acpi_ut_get_object_type_name(new_object)));
|
||||
}
|
||||
|
||||
/* Delete old object, install the new return object */
|
||||
|
@ -208,6 +195,315 @@ acpi_ns_repair_object(struct acpi_predefined_data *data,
|
|||
return (AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_convert_to_integer
|
||||
*
|
||||
* PARAMETERS: original_object - Object to be converted
|
||||
* return_object - Where the new converted object is returned
|
||||
*
|
||||
* RETURN: Status. AE_OK if conversion was successful.
|
||||
*
|
||||
* DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_integer(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object)
|
||||
{
|
||||
union acpi_operand_object *new_object;
|
||||
acpi_status status;
|
||||
u64 value = 0;
|
||||
u32 i;
|
||||
|
||||
switch (original_object->common.type) {
|
||||
case ACPI_TYPE_STRING:
|
||||
|
||||
/* String-to-Integer conversion */
|
||||
|
||||
status = acpi_ut_strtoul64(original_object->string.pointer,
|
||||
ACPI_ANY_BASE, &value);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
/* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
|
||||
|
||||
if (original_object->buffer.length > 8) {
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/* Extract each buffer byte to create the integer */
|
||||
|
||||
for (i = 0; i < original_object->buffer.length; i++) {
|
||||
value |=
|
||||
((u64) original_object->buffer.
|
||||
pointer[i] << (i * 8));
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
new_object = acpi_ut_create_integer_object(value);
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
*return_object = new_object;
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_convert_to_string
|
||||
*
|
||||
* PARAMETERS: original_object - Object to be converted
|
||||
* return_object - Where the new converted object is returned
|
||||
*
|
||||
* RETURN: Status. AE_OK if conversion was successful.
|
||||
*
|
||||
* DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_string(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object)
|
||||
{
|
||||
union acpi_operand_object *new_object;
|
||||
acpi_size length;
|
||||
acpi_status status;
|
||||
|
||||
switch (original_object->common.type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
/*
|
||||
* Integer-to-String conversion. Commonly, convert
|
||||
* an integer of value 0 to a NULL string. The last element of
|
||||
* _BIF and _BIX packages occasionally need this fix.
|
||||
*/
|
||||
if (original_object->integer.value == 0) {
|
||||
|
||||
/* Allocate a new NULL string object */
|
||||
|
||||
new_object = acpi_ut_create_string_object(0);
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
} else {
|
||||
status =
|
||||
acpi_ex_convert_to_string(original_object,
|
||||
&new_object,
|
||||
ACPI_IMPLICIT_CONVERT_HEX);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_BUFFER:
|
||||
/*
|
||||
* Buffer-to-String conversion. Use a to_string
|
||||
* conversion, no transform performed on the buffer data. The best
|
||||
* example of this is the _BIF method, where the string data from
|
||||
* the battery is often (incorrectly) returned as buffer object(s).
|
||||
*/
|
||||
length = 0;
|
||||
while ((length < original_object->buffer.length) &&
|
||||
(original_object->buffer.pointer[length])) {
|
||||
length++;
|
||||
}
|
||||
|
||||
/* Allocate a new string object */
|
||||
|
||||
new_object = acpi_ut_create_string_object(length);
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the raw buffer data with no transform. String is already NULL
|
||||
* terminated at Length+1.
|
||||
*/
|
||||
ACPI_MEMCPY(new_object->string.pointer,
|
||||
original_object->buffer.pointer, length);
|
||||
break;
|
||||
|
||||
default:
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
*return_object = new_object;
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_convert_to_buffer
|
||||
*
|
||||
* PARAMETERS: original_object - Object to be converted
|
||||
* return_object - Where the new converted object is returned
|
||||
*
|
||||
* RETURN: Status. AE_OK if conversion was successful.
|
||||
*
|
||||
* DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_buffer(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object)
|
||||
{
|
||||
union acpi_operand_object *new_object;
|
||||
acpi_status status;
|
||||
union acpi_operand_object **elements;
|
||||
u32 *dword_buffer;
|
||||
u32 count;
|
||||
u32 i;
|
||||
|
||||
switch (original_object->common.type) {
|
||||
case ACPI_TYPE_INTEGER:
|
||||
/*
|
||||
* Integer-to-Buffer conversion.
|
||||
* Convert the Integer to a packed-byte buffer. _MAT and other
|
||||
* objects need this sometimes, if a read has been performed on a
|
||||
* Field object that is less than or equal to the global integer
|
||||
* size (32 or 64 bits).
|
||||
*/
|
||||
status =
|
||||
acpi_ex_convert_to_buffer(original_object, &new_object);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
}
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_STRING:
|
||||
|
||||
/* String-to-Buffer conversion. Simple data copy */
|
||||
|
||||
new_object =
|
||||
acpi_ut_create_buffer_object(original_object->string.
|
||||
length);
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
ACPI_MEMCPY(new_object->buffer.pointer,
|
||||
original_object->string.pointer,
|
||||
original_object->string.length);
|
||||
break;
|
||||
|
||||
case ACPI_TYPE_PACKAGE:
|
||||
/*
|
||||
* This case is often seen for predefined names that must return a
|
||||
* Buffer object with multiple DWORD integers within. For example,
|
||||
* _FDE and _GTM. The Package can be converted to a Buffer.
|
||||
*/
|
||||
|
||||
/* All elements of the Package must be integers */
|
||||
|
||||
elements = original_object->package.elements;
|
||||
count = original_object->package.count;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if ((!*elements) ||
|
||||
((*elements)->common.type != ACPI_TYPE_INTEGER)) {
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
elements++;
|
||||
}
|
||||
|
||||
/* Create the new buffer object to replace the Package */
|
||||
|
||||
new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count));
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Copy the package elements (integers) to the buffer as DWORDs */
|
||||
|
||||
elements = original_object->package.elements;
|
||||
dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer);
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
*dword_buffer = (u32) (*elements)->integer.value;
|
||||
dword_buffer++;
|
||||
elements++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
*return_object = new_object;
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_convert_to_package
|
||||
*
|
||||
* PARAMETERS: original_object - Object to be converted
|
||||
* return_object - Where the new converted object is returned
|
||||
*
|
||||
* RETURN: Status. AE_OK if conversion was successful.
|
||||
*
|
||||
* DESCRIPTION: Attempt to convert a Buffer object to a Package. Each byte of
|
||||
* the buffer is converted to a single integer package element.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_convert_to_package(union acpi_operand_object *original_object,
|
||||
union acpi_operand_object **return_object)
|
||||
{
|
||||
union acpi_operand_object *new_object;
|
||||
union acpi_operand_object **elements;
|
||||
u32 length;
|
||||
u8 *buffer;
|
||||
|
||||
switch (original_object->common.type) {
|
||||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
/* Buffer-to-Package conversion */
|
||||
|
||||
length = original_object->buffer.length;
|
||||
new_object = acpi_ut_create_package_object(length);
|
||||
if (!new_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Convert each buffer byte to an integer package element */
|
||||
|
||||
elements = new_object->package.elements;
|
||||
buffer = original_object->buffer.pointer;
|
||||
|
||||
while (length--) {
|
||||
*elements =
|
||||
acpi_ut_create_integer_object((u64) *buffer);
|
||||
if (!*elements) {
|
||||
acpi_ut_remove_reference(new_object);
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
elements++;
|
||||
buffer++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
*return_object = new_object;
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_repair_package_list
|
||||
|
@ -238,6 +534,8 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data,
|
|||
{
|
||||
union acpi_operand_object *pkg_obj_desc;
|
||||
|
||||
ACPI_FUNCTION_NAME(ns_repair_package_list);
|
||||
|
||||
/*
|
||||
* Create the new outer package and populate it. The new package will
|
||||
* have a single element, the lone subpackage.
|
||||
|
@ -254,8 +552,9 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data,
|
|||
*obj_desc_ptr = pkg_obj_desc;
|
||||
data->flags |= ACPI_OBJECT_REPAIRED;
|
||||
|
||||
ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
|
||||
"Repaired Incorrectly formed Package"));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
|
||||
"%s: Repaired incorrectly formed Package\n",
|
||||
data->pathname));
|
||||
|
||||
return (AE_OK);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include <acpi/acpi.h>
|
||||
#include "accommon.h"
|
||||
#include "acnamesp.h"
|
||||
#include "acpredef.h"
|
||||
|
||||
#define _COMPONENT ACPI_NAMESPACE
|
||||
ACPI_MODULE_NAME("nsrepair2")
|
||||
|
@ -73,6 +74,10 @@ static acpi_status
|
|||
acpi_ns_repair_ALR(struct acpi_predefined_data *data,
|
||||
union acpi_operand_object **return_object_ptr);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_repair_FDE(struct acpi_predefined_data *data,
|
||||
union acpi_operand_object **return_object_ptr);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_repair_PSS(struct acpi_predefined_data *data,
|
||||
union acpi_operand_object **return_object_ptr);
|
||||
|
@ -88,9 +93,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
|
|||
u32 sort_index,
|
||||
u8 sort_direction, char *sort_key_name);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_remove_null_elements(union acpi_operand_object *package);
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_sort_list(union acpi_operand_object **elements,
|
||||
u32 count, u32 index, u8 sort_direction);
|
||||
|
@ -104,17 +106,27 @@ acpi_ns_sort_list(union acpi_operand_object **elements,
|
|||
* This table contains the names of the predefined methods for which we can
|
||||
* perform more complex repairs.
|
||||
*
|
||||
* _ALR: Sort the list ascending by ambient_illuminance if necessary
|
||||
* _PSS: Sort the list descending by Power if necessary
|
||||
* _TSS: Sort the list descending by Power if necessary
|
||||
* As necessary:
|
||||
*
|
||||
* _ALR: Sort the list ascending by ambient_illuminance
|
||||
* _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs
|
||||
* _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs
|
||||
* _PSS: Sort the list descending by Power
|
||||
* _TSS: Sort the list descending by Power
|
||||
*/
|
||||
static const struct acpi_repair_info acpi_ns_repairable_names[] = {
|
||||
{"_ALR", acpi_ns_repair_ALR},
|
||||
{"_FDE", acpi_ns_repair_FDE},
|
||||
{"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */
|
||||
{"_PSS", acpi_ns_repair_PSS},
|
||||
{"_TSS", acpi_ns_repair_TSS},
|
||||
{{0, 0, 0, 0}, NULL} /* Table terminator */
|
||||
};
|
||||
|
||||
#define ACPI_FDE_FIELD_COUNT 5
|
||||
#define ACPI_FDE_BYTE_BUFFER_SIZE 5
|
||||
#define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (u32))
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_complex_repairs
|
||||
|
@ -213,6 +225,94 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data,
|
|||
return (status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_repair_FDE
|
||||
*
|
||||
* PARAMETERS: Data - Pointer to validation data structure
|
||||
* return_object_ptr - Pointer to the object returned from the
|
||||
* evaluation of a method or object
|
||||
*
|
||||
* RETURN: Status. AE_OK if object is OK or was repaired successfully
|
||||
*
|
||||
* DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return
|
||||
* value is a Buffer of 5 DWORDs. This function repairs a common
|
||||
* problem where the return value is a Buffer of BYTEs, not
|
||||
* DWORDs.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_repair_FDE(struct acpi_predefined_data *data,
|
||||
union acpi_operand_object **return_object_ptr)
|
||||
{
|
||||
union acpi_operand_object *return_object = *return_object_ptr;
|
||||
union acpi_operand_object *buffer_object;
|
||||
u8 *byte_buffer;
|
||||
u32 *dword_buffer;
|
||||
u32 i;
|
||||
|
||||
ACPI_FUNCTION_NAME(ns_repair_FDE);
|
||||
|
||||
switch (return_object->common.type) {
|
||||
case ACPI_TYPE_BUFFER:
|
||||
|
||||
/* This is the expected type. Length should be (at least) 5 DWORDs */
|
||||
|
||||
if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/* We can only repair if we have exactly 5 BYTEs */
|
||||
|
||||
if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
|
||||
ACPI_WARN_PREDEFINED((AE_INFO, data->pathname,
|
||||
data->node_flags,
|
||||
"Incorrect return buffer length %u, expected %u",
|
||||
return_object->buffer.length,
|
||||
ACPI_FDE_DWORD_BUFFER_SIZE));
|
||||
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/* Create the new (larger) buffer object */
|
||||
|
||||
buffer_object =
|
||||
acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
|
||||
if (!buffer_object) {
|
||||
return (AE_NO_MEMORY);
|
||||
}
|
||||
|
||||
/* Expand each byte to a DWORD */
|
||||
|
||||
byte_buffer = return_object->buffer.pointer;
|
||||
dword_buffer =
|
||||
ACPI_CAST_PTR(u32, buffer_object->buffer.pointer);
|
||||
|
||||
for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
|
||||
*dword_buffer = (u32) *byte_buffer;
|
||||
dword_buffer++;
|
||||
byte_buffer++;
|
||||
}
|
||||
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
|
||||
"%s Expanded Byte Buffer to expected DWord Buffer\n",
|
||||
data->pathname));
|
||||
break;
|
||||
|
||||
default:
|
||||
return (AE_AML_OPERAND_TYPE);
|
||||
}
|
||||
|
||||
/* Delete the original return object, return the new buffer object */
|
||||
|
||||
acpi_ut_remove_reference(return_object);
|
||||
*return_object_ptr = buffer_object;
|
||||
|
||||
data->flags |= ACPI_OBJECT_REPAIRED;
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_repair_TSS
|
||||
|
@ -345,6 +445,8 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
|
|||
u32 previous_value;
|
||||
acpi_status status;
|
||||
|
||||
ACPI_FUNCTION_NAME(ns_check_sorted_list);
|
||||
|
||||
/* The top-level object must be a package */
|
||||
|
||||
if (return_object->common.type != ACPI_TYPE_PACKAGE) {
|
||||
|
@ -352,24 +454,10 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
|
|||
}
|
||||
|
||||
/*
|
||||
* Detect any NULL package elements and remove them from the
|
||||
* package.
|
||||
*
|
||||
* TBD: We may want to do this for all predefined names that
|
||||
* return a variable-length package of packages.
|
||||
* NOTE: assumes list of sub-packages contains no NULL elements.
|
||||
* Any NULL elements should have been removed by earlier call
|
||||
* to acpi_ns_remove_null_elements.
|
||||
*/
|
||||
status = acpi_ns_remove_null_elements(return_object);
|
||||
if (status == AE_NULL_ENTRY) {
|
||||
ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags,
|
||||
"NULL elements removed from package"));
|
||||
|
||||
/* Exit if package is now zero length */
|
||||
|
||||
if (!return_object->package.count) {
|
||||
return (AE_NULL_ENTRY);
|
||||
}
|
||||
}
|
||||
|
||||
outer_elements = return_object->package.elements;
|
||||
outer_element_count = return_object->package.count;
|
||||
if (!outer_element_count) {
|
||||
|
@ -422,10 +510,9 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
|
|||
|
||||
data->flags |= ACPI_OBJECT_REPAIRED;
|
||||
|
||||
ACPI_INFO_PREDEFINED((AE_INFO, data->pathname,
|
||||
data->node_flags,
|
||||
"Repaired unsorted list - now sorted by %s",
|
||||
sort_key_name));
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
|
||||
"%s: Repaired unsorted list - now sorted by %s\n",
|
||||
data->pathname, sort_key_name));
|
||||
return (AE_OK);
|
||||
}
|
||||
|
||||
|
@ -440,36 +527,63 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data,
|
|||
*
|
||||
* FUNCTION: acpi_ns_remove_null_elements
|
||||
*
|
||||
* PARAMETERS: obj_desc - A Package object
|
||||
* PARAMETERS: Data - Pointer to validation data structure
|
||||
* package_type - An acpi_return_package_types value
|
||||
* obj_desc - A Package object
|
||||
*
|
||||
* RETURN: Status. AE_NULL_ENTRY means that one or more elements were
|
||||
* removed.
|
||||
* RETURN: None.
|
||||
*
|
||||
* DESCRIPTION: Remove all NULL package elements and update the package count.
|
||||
* DESCRIPTION: Remove all NULL package elements from packages that contain
|
||||
* a variable number of sub-packages.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static acpi_status
|
||||
acpi_ns_remove_null_elements(union acpi_operand_object *obj_desc)
|
||||
void
|
||||
acpi_ns_remove_null_elements(struct acpi_predefined_data *data,
|
||||
u8 package_type,
|
||||
union acpi_operand_object *obj_desc)
|
||||
{
|
||||
union acpi_operand_object **source;
|
||||
union acpi_operand_object **dest;
|
||||
acpi_status status = AE_OK;
|
||||
u32 count;
|
||||
u32 new_count;
|
||||
u32 i;
|
||||
|
||||
ACPI_FUNCTION_NAME(ns_remove_null_elements);
|
||||
|
||||
/*
|
||||
* PTYPE1 packages contain no subpackages.
|
||||
* PTYPE2 packages contain a variable number of sub-packages. We can
|
||||
* safely remove all NULL elements from the PTYPE2 packages.
|
||||
*/
|
||||
switch (package_type) {
|
||||
case ACPI_PTYPE1_FIXED:
|
||||
case ACPI_PTYPE1_VAR:
|
||||
case ACPI_PTYPE1_OPTION:
|
||||
return;
|
||||
|
||||
case ACPI_PTYPE2:
|
||||
case ACPI_PTYPE2_COUNT:
|
||||
case ACPI_PTYPE2_PKG_COUNT:
|
||||
case ACPI_PTYPE2_FIXED:
|
||||
case ACPI_PTYPE2_MIN:
|
||||
case ACPI_PTYPE2_REV_FIXED:
|
||||
break;
|
||||
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
count = obj_desc->package.count;
|
||||
new_count = count;
|
||||
|
||||
source = obj_desc->package.elements;
|
||||
dest = source;
|
||||
|
||||
/* Examine all elements of the package object */
|
||||
/* Examine all elements of the package object, remove nulls */
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
if (!*source) {
|
||||
status = AE_NULL_ENTRY;
|
||||
new_count--;
|
||||
} else {
|
||||
*dest = *source;
|
||||
|
@ -478,15 +592,18 @@ acpi_ns_remove_null_elements(union acpi_operand_object *obj_desc)
|
|||
source++;
|
||||
}
|
||||
|
||||
if (status == AE_NULL_ENTRY) {
|
||||
/* Update parent package if any null elements were removed */
|
||||
|
||||
if (new_count < count) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
|
||||
"%s: Found and removed %u NULL elements\n",
|
||||
data->pathname, (count - new_count)));
|
||||
|
||||
/* NULL terminate list and update the package count */
|
||||
|
||||
*dest = NULL;
|
||||
obj_desc->package.count = new_count;
|
||||
}
|
||||
|
||||
return (status);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -671,24 +671,25 @@ acpi_ns_externalize_name(u32 internal_name_length,
|
|||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_map_handle_to_node
|
||||
* FUNCTION: acpi_ns_validate_handle
|
||||
*
|
||||
* PARAMETERS: Handle - Handle to be converted to an Node
|
||||
* PARAMETERS: Handle - Handle to be validated and typecast to a
|
||||
* namespace node.
|
||||
*
|
||||
* RETURN: A Name table entry pointer
|
||||
* RETURN: A pointer to a namespace node
|
||||
*
|
||||
* DESCRIPTION: Convert a namespace handle to a real Node
|
||||
* DESCRIPTION: Convert a namespace handle to a namespace node. Handles special
|
||||
* cases for the root node.
|
||||
*
|
||||
* Note: Real integer handles would allow for more verification
|
||||
* NOTE: Real integer handles would allow for more verification
|
||||
* and keep all pointers within this subsystem - however this introduces
|
||||
* more (and perhaps unnecessary) overhead.
|
||||
*
|
||||
* The current implemenation is basically a placeholder until such time comes
|
||||
* that it is needed.
|
||||
* more overhead and has not been necessary to this point. Drivers
|
||||
* holding handles are typically notified before a node becomes invalid
|
||||
* due to a table unload.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle)
|
||||
struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle)
|
||||
{
|
||||
|
||||
ACPI_FUNCTION_ENTRY();
|
||||
|
@ -708,42 +709,6 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle)
|
|||
return (ACPI_CAST_PTR(struct acpi_namespace_node, handle));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_convert_entry_to_handle
|
||||
*
|
||||
* PARAMETERS: Node - Node to be converted to a Handle
|
||||
*
|
||||
* RETURN: A user handle
|
||||
*
|
||||
* DESCRIPTION: Convert a real Node to a namespace handle
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node)
|
||||
{
|
||||
|
||||
/*
|
||||
* Simple implementation for now;
|
||||
*/
|
||||
return ((acpi_handle) node);
|
||||
|
||||
/* Example future implementation ---------------------
|
||||
|
||||
if (!Node)
|
||||
{
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (Node == acpi_gbl_root_node)
|
||||
{
|
||||
return (ACPI_ROOT_OBJECT);
|
||||
}
|
||||
|
||||
return ((acpi_handle) Node);
|
||||
------------------------------------------------------*/
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* FUNCTION: acpi_ns_terminate
|
||||
|
|
|
@ -190,7 +190,7 @@ acpi_evaluate_object(acpi_handle handle,
|
|||
|
||||
/* Convert and validate the device handle */
|
||||
|
||||
info->prefix_node = acpi_ns_map_handle_to_node(handle);
|
||||
info->prefix_node = acpi_ns_validate_handle(handle);
|
||||
if (!info->prefix_node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto cleanup;
|
||||
|
@ -552,7 +552,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle,
|
|||
return (status);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
node = acpi_ns_validate_handle(obj_handle);
|
||||
status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
return (status);
|
||||
|
@ -729,7 +729,7 @@ acpi_attach_data(acpi_handle obj_handle,
|
|||
|
||||
/* Convert and validate the handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
node = acpi_ns_validate_handle(obj_handle);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -775,7 +775,7 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler)
|
|||
|
||||
/* Convert and validate the handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
node = acpi_ns_validate_handle(obj_handle);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -822,7 +822,7 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data)
|
|||
|
||||
/* Convert and validate the handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(obj_handle);
|
||||
node = acpi_ns_validate_handle(obj_handle);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
|
|
@ -93,7 +93,7 @@ acpi_get_handle(acpi_handle parent,
|
|||
/* Convert a parent handle to a prefix node */
|
||||
|
||||
if (parent) {
|
||||
prefix_node = acpi_ns_map_handle_to_node(parent);
|
||||
prefix_node = acpi_ns_validate_handle(parent);
|
||||
if (!prefix_node) {
|
||||
return (AE_BAD_PARAMETER);
|
||||
}
|
||||
|
@ -114,7 +114,7 @@ acpi_get_handle(acpi_handle parent,
|
|||
|
||||
if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) {
|
||||
*ret_handle =
|
||||
acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
|
||||
ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node);
|
||||
return (AE_OK);
|
||||
}
|
||||
} else if (!prefix_node) {
|
||||
|
@ -129,7 +129,7 @@ acpi_get_handle(acpi_handle parent,
|
|||
status =
|
||||
acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
*ret_handle = acpi_ns_convert_entry_to_handle(node);
|
||||
*ret_handle = ACPI_CAST_PTR(acpi_handle, node);
|
||||
}
|
||||
|
||||
return (status);
|
||||
|
@ -186,7 +186,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer)
|
|||
return (status);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(handle);
|
||||
node = acpi_ns_validate_handle(handle);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -291,7 +291,7 @@ acpi_get_object_info(acpi_handle handle,
|
|||
goto cleanup;
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(handle);
|
||||
node = acpi_ns_validate_handle(handle);
|
||||
if (!node) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return (AE_BAD_PARAMETER);
|
||||
|
|
|
@ -79,7 +79,7 @@ acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id)
|
|||
|
||||
/* Convert and validate the handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(handle);
|
||||
node = acpi_ns_validate_handle(handle);
|
||||
if (!node) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return (AE_BAD_PARAMETER);
|
||||
|
@ -132,7 +132,7 @@ acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type)
|
|||
|
||||
/* Convert and validate the handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(handle);
|
||||
node = acpi_ns_validate_handle(handle);
|
||||
if (!node) {
|
||||
(void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
|
||||
return (AE_BAD_PARAMETER);
|
||||
|
@ -182,7 +182,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
|
|||
|
||||
/* Convert and validate the handle */
|
||||
|
||||
node = acpi_ns_map_handle_to_node(handle);
|
||||
node = acpi_ns_validate_handle(handle);
|
||||
if (!node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -191,7 +191,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle)
|
|||
/* Get the parent entry */
|
||||
|
||||
parent_node = acpi_ns_get_parent_node(node);
|
||||
*ret_handle = acpi_ns_convert_entry_to_handle(parent_node);
|
||||
*ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node);
|
||||
|
||||
/* Return exception if parent is null */
|
||||
|
||||
|
@ -251,7 +251,7 @@ acpi_get_next_object(acpi_object_type type,
|
|||
|
||||
/* Start search at the beginning of the specified scope */
|
||||
|
||||
parent_node = acpi_ns_map_handle_to_node(parent);
|
||||
parent_node = acpi_ns_validate_handle(parent);
|
||||
if (!parent_node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -260,7 +260,7 @@ acpi_get_next_object(acpi_object_type type,
|
|||
/* Non-null handle, ignore the parent */
|
||||
/* Convert and validate the handle */
|
||||
|
||||
child_node = acpi_ns_map_handle_to_node(child);
|
||||
child_node = acpi_ns_validate_handle(child);
|
||||
if (!child_node) {
|
||||
status = AE_BAD_PARAMETER;
|
||||
goto unlock_and_exit;
|
||||
|
@ -276,7 +276,7 @@ acpi_get_next_object(acpi_object_type type,
|
|||
}
|
||||
|
||||
if (ret_handle) {
|
||||
*ret_handle = acpi_ns_convert_entry_to_handle(node);
|
||||
*ret_handle = ACPI_CAST_PTR(acpi_handle, node);
|
||||
}
|
||||
|
||||
unlock_and_exit:
|
||||
|
|
|
@ -287,7 +287,8 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
|
|||
/* Invoke an internal method if necessary */
|
||||
|
||||
if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) {
|
||||
status = info->obj_desc->method.implementation(walk_state);
|
||||
status =
|
||||
info->obj_desc->method.extra.implementation(walk_state);
|
||||
info->return_object = walk_state->return_desc;
|
||||
|
||||
/* Cleanup states */
|
||||
|
|
|
@ -104,7 +104,7 @@ acpi_rs_validate_parameters(acpi_handle device_handle,
|
|||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
||||
node = acpi_ns_map_handle_to_node(device_handle);
|
||||
node = acpi_ns_validate_handle(device_handle);
|
||||
if (!node) {
|
||||
return_ACPI_STATUS(AE_BAD_PARAMETER);
|
||||
}
|
||||
|
|
|
@ -323,11 +323,11 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type,
|
|||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: This function is called to place a package object in a user
|
||||
* buffer. A package object by definition contains other objects.
|
||||
* buffer. A package object by definition contains other objects.
|
||||
*
|
||||
* The buffer is assumed to have sufficient space for the object.
|
||||
* The caller must have verified the buffer length needed using the
|
||||
* acpi_ut_get_object_size function before calling this function.
|
||||
* The caller must have verified the buffer length needed using
|
||||
* the acpi_ut_get_object_size function before calling this function.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -382,12 +382,12 @@ acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object,
|
|||
* FUNCTION: acpi_ut_copy_iobject_to_eobject
|
||||
*
|
||||
* PARAMETERS: internal_object - The internal object to be converted
|
||||
* buffer_ptr - Where the object is returned
|
||||
* ret_buffer - Where the object is returned
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: This function is called to build an API object to be returned to
|
||||
* the caller.
|
||||
* DESCRIPTION: This function is called to build an API object to be returned
|
||||
* to the caller.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
||||
|
@ -626,7 +626,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object,
|
|||
* PARAMETERS: external_object - The external object to be converted
|
||||
* internal_object - Where the internal object is returned
|
||||
*
|
||||
* RETURN: Status - the status of the call
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Converts an external object to an internal object.
|
||||
*
|
||||
|
@ -665,7 +665,7 @@ acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object,
|
|||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: Simple copy of one internal object to another. Reference count
|
||||
* DESCRIPTION: Simple copy of one internal object to another. Reference count
|
||||
* of the destination object is preserved.
|
||||
*
|
||||
******************************************************************************/
|
||||
|
@ -897,10 +897,11 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type,
|
|||
*
|
||||
* FUNCTION: acpi_ut_copy_ipackage_to_ipackage
|
||||
*
|
||||
* PARAMETERS: *source_obj - Pointer to the source package object
|
||||
* *dest_obj - Where the internal object is returned
|
||||
* PARAMETERS: source_obj - Pointer to the source package object
|
||||
* dest_obj - Where the internal object is returned
|
||||
* walk_state - Current Walk state descriptor
|
||||
*
|
||||
* RETURN: Status - the status of the call
|
||||
* RETURN: Status
|
||||
*
|
||||
* DESCRIPTION: This function is called to copy an internal package object
|
||||
* into another internal package object.
|
||||
|
@ -953,9 +954,9 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj,
|
|||
*
|
||||
* FUNCTION: acpi_ut_copy_iobject_to_iobject
|
||||
*
|
||||
* PARAMETERS: walk_state - Current walk state
|
||||
* source_desc - The internal object to be copied
|
||||
* PARAMETERS: source_desc - The internal object to be copied
|
||||
* dest_desc - Where the copied object is returned
|
||||
* walk_state - Current walk state
|
||||
*
|
||||
* RETURN: Status
|
||||
*
|
||||
|
|
|
@ -831,7 +831,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event)
|
|||
dev_name(&device->dev), event,
|
||||
acpi_battery_present(battery));
|
||||
#ifdef CONFIG_ACPI_SYSFS_POWER
|
||||
/* acpi_batter_update could remove power_supply object */
|
||||
/* acpi_battery_update could remove power_supply object */
|
||||
if (battery->bat.dev)
|
||||
kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);
|
||||
#endif
|
||||
|
|
|
@ -344,6 +344,152 @@ bool acpi_bus_can_wakeup(acpi_handle handle)
|
|||
|
||||
EXPORT_SYMBOL(acpi_bus_can_wakeup);
|
||||
|
||||
static void acpi_print_osc_error(acpi_handle handle,
|
||||
struct acpi_osc_context *context, char *error)
|
||||
{
|
||||
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
|
||||
int i;
|
||||
|
||||
if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer)))
|
||||
printk(KERN_DEBUG "%s\n", error);
|
||||
else {
|
||||
printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error);
|
||||
kfree(buffer.pointer);
|
||||
}
|
||||
printk(KERN_DEBUG"_OSC request data:");
|
||||
for (i = 0; i < context->cap.length; i += sizeof(u32))
|
||||
printk("%x ", *((u32 *)(context->cap.pointer + i)));
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
static u8 hex_val(unsigned char c)
|
||||
{
|
||||
return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
|
||||
}
|
||||
|
||||
static acpi_status acpi_str_to_uuid(char *str, u8 *uuid)
|
||||
{
|
||||
int i;
|
||||
static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21,
|
||||
24, 26, 28, 30, 32, 34};
|
||||
|
||||
if (strlen(str) != 36)
|
||||
return AE_BAD_PARAMETER;
|
||||
for (i = 0; i < 36; i++) {
|
||||
if (i == 8 || i == 13 || i == 18 || i == 23) {
|
||||
if (str[i] != '-')
|
||||
return AE_BAD_PARAMETER;
|
||||
} else if (!isxdigit(str[i]))
|
||||
return AE_BAD_PARAMETER;
|
||||
}
|
||||
for (i = 0; i < 16; i++) {
|
||||
uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4;
|
||||
uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]);
|
||||
}
|
||||
return AE_OK;
|
||||
}
|
||||
|
||||
acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object in_params[4];
|
||||
union acpi_object *out_obj;
|
||||
u8 uuid[16];
|
||||
u32 errors;
|
||||
|
||||
if (!context)
|
||||
return AE_ERROR;
|
||||
if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid)))
|
||||
return AE_ERROR;
|
||||
context->ret.length = ACPI_ALLOCATE_BUFFER;
|
||||
context->ret.pointer = NULL;
|
||||
|
||||
/* Setting up input parameters */
|
||||
input.count = 4;
|
||||
input.pointer = in_params;
|
||||
in_params[0].type = ACPI_TYPE_BUFFER;
|
||||
in_params[0].buffer.length = 16;
|
||||
in_params[0].buffer.pointer = uuid;
|
||||
in_params[1].type = ACPI_TYPE_INTEGER;
|
||||
in_params[1].integer.value = context->rev;
|
||||
in_params[2].type = ACPI_TYPE_INTEGER;
|
||||
in_params[2].integer.value = context->cap.length/sizeof(u32);
|
||||
in_params[3].type = ACPI_TYPE_BUFFER;
|
||||
in_params[3].buffer.length = context->cap.length;
|
||||
in_params[3].buffer.pointer = context->cap.pointer;
|
||||
|
||||
status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
/* return buffer should have the same length as cap buffer */
|
||||
if (context->ret.length != context->cap.length)
|
||||
return AE_NULL_OBJECT;
|
||||
|
||||
out_obj = context->ret.pointer;
|
||||
if (out_obj->type != ACPI_TYPE_BUFFER) {
|
||||
acpi_print_osc_error(handle, context,
|
||||
"_OSC evaluation returned wrong type");
|
||||
status = AE_TYPE;
|
||||
goto out_kfree;
|
||||
}
|
||||
/* Need to ignore the bit0 in result code */
|
||||
errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
|
||||
if (errors) {
|
||||
if (errors & OSC_REQUEST_ERROR)
|
||||
acpi_print_osc_error(handle, context,
|
||||
"_OSC request failed");
|
||||
if (errors & OSC_INVALID_UUID_ERROR)
|
||||
acpi_print_osc_error(handle, context,
|
||||
"_OSC invalid UUID");
|
||||
if (errors & OSC_INVALID_REVISION_ERROR)
|
||||
acpi_print_osc_error(handle, context,
|
||||
"_OSC invalid revision");
|
||||
if (errors & OSC_CAPABILITIES_MASK_ERROR) {
|
||||
if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE]
|
||||
& OSC_QUERY_ENABLE)
|
||||
goto out_success;
|
||||
status = AE_SUPPORT;
|
||||
goto out_kfree;
|
||||
}
|
||||
status = AE_ERROR;
|
||||
goto out_kfree;
|
||||
}
|
||||
out_success:
|
||||
return AE_OK;
|
||||
|
||||
out_kfree:
|
||||
kfree(context->ret.pointer);
|
||||
context->ret.pointer = NULL;
|
||||
return status;
|
||||
}
|
||||
EXPORT_SYMBOL(acpi_run_osc);
|
||||
|
||||
static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48";
|
||||
static void acpi_bus_osc_support(void)
|
||||
{
|
||||
u32 capbuf[2];
|
||||
struct acpi_osc_context context = {
|
||||
.uuid_str = sb_uuid_str,
|
||||
.rev = 1,
|
||||
.cap.length = 8,
|
||||
.cap.pointer = capbuf,
|
||||
};
|
||||
acpi_handle handle;
|
||||
|
||||
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */
|
||||
#ifdef CONFIG_ACPI_PROCESSOR_AGGREGATOR
|
||||
capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT;
|
||||
#endif
|
||||
if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle)))
|
||||
return;
|
||||
if (ACPI_SUCCESS(acpi_run_osc(handle, &context)))
|
||||
kfree(context.ret.pointer);
|
||||
/* do we need to check the returned cap? Sounds no */
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Event Management
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -734,6 +880,8 @@ static int __init acpi_bus_init(void)
|
|||
status = acpi_ec_ecdt_probe();
|
||||
/* Ignore result. Not having an ECDT is not fatal. */
|
||||
|
||||
acpi_bus_osc_support();
|
||||
|
||||
status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n");
|
||||
|
|
|
@ -282,6 +282,13 @@ static int acpi_lid_send_state(struct acpi_device *device)
|
|||
if (ret == NOTIFY_DONE)
|
||||
ret = blocking_notifier_call_chain(&acpi_lid_notifier, state,
|
||||
device);
|
||||
if (ret == NOTIFY_DONE || ret == NOTIFY_OK) {
|
||||
/*
|
||||
* It is also regarded as success if the notifier_chain
|
||||
* returns NOTIFY_OK or NOTIFY_DONE.
|
||||
*/
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
|
@ -195,6 +196,80 @@ static int param_get_trace_state(char *buffer, struct kernel_param *kp)
|
|||
module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
|
||||
NULL, 0644);
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
DebugFS Interface
|
||||
-------------------------------------------------------------------------- */
|
||||
|
||||
static ssize_t cm_write(struct file *file, const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
static char *buf;
|
||||
static int uncopied_bytes;
|
||||
struct acpi_table_header table;
|
||||
acpi_status status;
|
||||
|
||||
if (!(*ppos)) {
|
||||
/* parse the table header to get the table length */
|
||||
if (count <= sizeof(struct acpi_table_header))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&table, user_buf,
|
||||
sizeof(struct acpi_table_header)))
|
||||
return -EFAULT;
|
||||
uncopied_bytes = table.length;
|
||||
buf = kzalloc(uncopied_bytes, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (uncopied_bytes < count) {
|
||||
kfree(buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (copy_from_user(buf + (*ppos), user_buf, count)) {
|
||||
kfree(buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
uncopied_bytes -= count;
|
||||
*ppos += count;
|
||||
|
||||
if (!uncopied_bytes) {
|
||||
status = acpi_install_method(buf);
|
||||
kfree(buf);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -EINVAL;
|
||||
add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations cm_fops = {
|
||||
.write = cm_write,
|
||||
};
|
||||
|
||||
static int acpi_debugfs_init(void)
|
||||
{
|
||||
struct dentry *acpi_dir, *cm_dentry;
|
||||
|
||||
acpi_dir = debugfs_create_dir("acpi", NULL);
|
||||
if (!acpi_dir)
|
||||
goto err;
|
||||
|
||||
cm_dentry = debugfs_create_file("custom_method", S_IWUGO,
|
||||
acpi_dir, NULL, &cm_fops);
|
||||
if (!cm_dentry)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
if (acpi_dir)
|
||||
debugfs_remove(acpi_dir);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
FS Interface (/proc)
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -286,7 +361,7 @@ static const struct file_operations acpi_system_debug_proc_fops = {
|
|||
};
|
||||
#endif
|
||||
|
||||
int __init acpi_debug_init(void)
|
||||
int __init acpi_procfs_init(void)
|
||||
{
|
||||
#ifdef CONFIG_ACPI_PROCFS
|
||||
struct proc_dir_entry *entry;
|
||||
|
@ -321,3 +396,10 @@ int __init acpi_debug_init(void)
|
|||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int __init acpi_debug_init(void)
|
||||
{
|
||||
acpi_debugfs_init();
|
||||
acpi_procfs_init();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
|
|||
" before undocking");
|
||||
|
||||
static struct atomic_notifier_head dock_notifier_list;
|
||||
static char dock_device_name[] = "dock";
|
||||
|
||||
static const struct acpi_device_id dock_device_ids[] = {
|
||||
{"LNXDOCK", 0},
|
||||
|
@ -93,40 +92,30 @@ struct dock_dependent_device {
|
|||
* Dock Dependent device functions *
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* alloc_dock_dependent_device - allocate and init a dependent device
|
||||
* @handle: the acpi_handle of the dependent device
|
||||
* add_dock_dependent_device - associate a device with the dock station
|
||||
* @ds: The dock station
|
||||
* @handle: handle of the dependent device
|
||||
*
|
||||
* Allocate memory for a dependent device structure for a device referenced
|
||||
* by the acpi handle
|
||||
* Add the dependent device to the dock's dependent device list.
|
||||
*/
|
||||
static struct dock_dependent_device *
|
||||
alloc_dock_dependent_device(acpi_handle handle)
|
||||
static int
|
||||
add_dock_dependent_device(struct dock_station *ds, acpi_handle handle)
|
||||
{
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
dd = kzalloc(sizeof(*dd), GFP_KERNEL);
|
||||
if (dd) {
|
||||
dd->handle = handle;
|
||||
INIT_LIST_HEAD(&dd->list);
|
||||
INIT_LIST_HEAD(&dd->hotplug_list);
|
||||
}
|
||||
return dd;
|
||||
}
|
||||
if (!dd)
|
||||
return -ENOMEM;
|
||||
|
||||
dd->handle = handle;
|
||||
INIT_LIST_HEAD(&dd->list);
|
||||
INIT_LIST_HEAD(&dd->hotplug_list);
|
||||
|
||||
/**
|
||||
* add_dock_dependent_device - associate a device with the dock station
|
||||
* @ds: The dock station
|
||||
* @dd: The dependent device
|
||||
*
|
||||
* Add the dependent device to the dock's dependent device list.
|
||||
*/
|
||||
static void
|
||||
add_dock_dependent_device(struct dock_station *ds,
|
||||
struct dock_dependent_device *dd)
|
||||
{
|
||||
spin_lock(&ds->dd_lock);
|
||||
list_add_tail(&dd->list, &ds->dependent_devices);
|
||||
spin_unlock(&ds->dd_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,6 +238,7 @@ static int is_battery(acpi_handle handle)
|
|||
static int is_ejectable_bay(acpi_handle handle)
|
||||
{
|
||||
acpi_handle phandle;
|
||||
|
||||
if (!is_ejectable(handle))
|
||||
return 0;
|
||||
if (is_battery(handle) || is_ata(handle))
|
||||
|
@ -275,14 +265,13 @@ int is_dock_device(acpi_handle handle)
|
|||
|
||||
if (is_dock(handle))
|
||||
return 1;
|
||||
list_for_each_entry(dock_station, &dock_stations, sibling) {
|
||||
|
||||
list_for_each_entry(dock_station, &dock_stations, sibling)
|
||||
if (find_dock_dependent_device(dock_station, handle))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(is_dock_device);
|
||||
|
||||
/**
|
||||
|
@ -305,8 +294,6 @@ static int dock_present(struct dock_station *ds)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* dock_create_acpi_device - add new devices to acpi
|
||||
* @handle - handle of the device to add
|
||||
|
@ -320,7 +307,7 @@ static int dock_present(struct dock_station *ds)
|
|||
*/
|
||||
static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
|
||||
{
|
||||
struct acpi_device *device = NULL;
|
||||
struct acpi_device *device;
|
||||
struct acpi_device *parent_device;
|
||||
acpi_handle parent;
|
||||
int ret;
|
||||
|
@ -337,8 +324,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle)
|
|||
ret = acpi_bus_add(&device, parent_device, handle,
|
||||
ACPI_BUS_TYPE_DEVICE);
|
||||
if (ret) {
|
||||
pr_debug("error adding bus, %x\n",
|
||||
-ret);
|
||||
pr_debug("error adding bus, %x\n", -ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
@ -364,7 +350,6 @@ static void dock_remove_acpi_device(acpi_handle handle)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hotplug_dock_devices - insert or remove devices on the dock station
|
||||
* @ds: the dock station
|
||||
|
@ -384,10 +369,9 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event)
|
|||
/*
|
||||
* First call driver specific hotplug functions
|
||||
*/
|
||||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) {
|
||||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
|
||||
if (dd->ops && dd->ops->handler)
|
||||
dd->ops->handler(dd->handle, event, dd->context);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now make sure that an acpi_device is created for each
|
||||
|
@ -426,6 +410,7 @@ static void dock_event(struct dock_station *ds, u32 event, int num)
|
|||
list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list)
|
||||
if (dd->ops && dd->ops->uevent)
|
||||
dd->ops->uevent(dd->handle, event, dd->context);
|
||||
|
||||
if (num != DOCK_EVENT)
|
||||
kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
|
||||
}
|
||||
|
@ -456,8 +441,8 @@ static void eject_dock(struct dock_station *ds)
|
|||
arg.type = ACPI_TYPE_INTEGER;
|
||||
arg.integer.value = 1;
|
||||
|
||||
if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0",
|
||||
&arg_list, NULL)))
|
||||
status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_debug("Failed to evaluate _EJ0!\n");
|
||||
}
|
||||
|
||||
|
@ -577,7 +562,6 @@ int register_dock_notifier(struct notifier_block *nb)
|
|||
|
||||
return atomic_notifier_chain_register(&dock_notifier_list, nb);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(register_dock_notifier);
|
||||
|
||||
/**
|
||||
|
@ -591,7 +575,6 @@ void unregister_dock_notifier(struct notifier_block *nb)
|
|||
|
||||
atomic_notifier_chain_unregister(&dock_notifier_list, nb);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(unregister_dock_notifier);
|
||||
|
||||
/**
|
||||
|
@ -636,7 +619,6 @@ register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops,
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(register_hotplug_dock_device);
|
||||
|
||||
/**
|
||||
|
@ -657,7 +639,6 @@ void unregister_hotplug_dock_device(acpi_handle handle)
|
|||
dock_del_hotplug_device(dock_station, dd);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device);
|
||||
|
||||
/**
|
||||
|
@ -772,7 +753,7 @@ struct dock_data {
|
|||
|
||||
static void acpi_dock_deferred_cb(void *context)
|
||||
{
|
||||
struct dock_data *data = (struct dock_data *)context;
|
||||
struct dock_data *data = context;
|
||||
|
||||
dock_notify(data->handle, data->event, data->ds);
|
||||
kfree(data);
|
||||
|
@ -782,23 +763,22 @@ static int acpi_dock_notifier_call(struct notifier_block *this,
|
|||
unsigned long event, void *data)
|
||||
{
|
||||
struct dock_station *dock_station;
|
||||
acpi_handle handle = (acpi_handle)data;
|
||||
acpi_handle handle = data;
|
||||
|
||||
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
|
||||
&& event != ACPI_NOTIFY_EJECT_REQUEST)
|
||||
return 0;
|
||||
list_for_each_entry(dock_station, &dock_stations, sibling) {
|
||||
if (dock_station->handle == handle) {
|
||||
struct dock_data *dock_data;
|
||||
struct dock_data *dd;
|
||||
|
||||
dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL);
|
||||
if (!dock_data)
|
||||
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
|
||||
if (!dd)
|
||||
return 0;
|
||||
dock_data->handle = handle;
|
||||
dock_data->event = event;
|
||||
dock_data->ds = dock_station;
|
||||
acpi_os_hotplug_execute(acpi_dock_deferred_cb,
|
||||
dock_data);
|
||||
dd->handle = handle;
|
||||
dd->event = event;
|
||||
dd->ds = dock_station;
|
||||
acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
|
||||
return 0 ;
|
||||
}
|
||||
}
|
||||
|
@ -826,7 +806,6 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|||
acpi_status status;
|
||||
acpi_handle tmp, parent;
|
||||
struct dock_station *ds = context;
|
||||
struct dock_dependent_device *dd;
|
||||
|
||||
status = acpi_bus_get_ejd(handle, &tmp);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
|
@ -840,11 +819,9 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|||
goto fdd_out;
|
||||
}
|
||||
|
||||
if (tmp == ds->handle) {
|
||||
dd = alloc_dock_dependent_device(handle);
|
||||
if (dd)
|
||||
add_dock_dependent_device(ds, dd);
|
||||
}
|
||||
if (tmp == ds->handle)
|
||||
add_dock_dependent_device(ds, handle);
|
||||
|
||||
fdd_out:
|
||||
return AE_OK;
|
||||
}
|
||||
|
@ -857,8 +834,7 @@ static ssize_t show_docked(struct device *dev,
|
|||
{
|
||||
struct acpi_device *tmp;
|
||||
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
struct dock_station *dock_station = dev->platform_data;
|
||||
|
||||
if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
|
||||
return snprintf(buf, PAGE_SIZE, "1\n");
|
||||
|
@ -872,8 +848,7 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL);
|
|||
static ssize_t show_flags(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
struct dock_station *dock_station = dev->platform_data;
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags);
|
||||
|
||||
}
|
||||
|
@ -886,8 +861,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr,
|
|||
const char *buf, size_t count)
|
||||
{
|
||||
int ret;
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
struct dock_station *dock_station = dev->platform_data;
|
||||
|
||||
if (!count)
|
||||
return -EINVAL;
|
||||
|
@ -905,8 +879,7 @@ static ssize_t show_dock_uid(struct device *dev,
|
|||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
unsigned long long lbuf;
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
struct dock_station *dock_station = dev->platform_data;
|
||||
acpi_status status = acpi_evaluate_integer(dock_station->handle,
|
||||
"_UID", NULL, &lbuf);
|
||||
if (ACPI_FAILURE(status))
|
||||
|
@ -919,8 +892,7 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL);
|
|||
static ssize_t show_dock_type(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dock_station *dock_station = *((struct dock_station **)
|
||||
dev->platform_data);
|
||||
struct dock_station *dock_station = dev->platform_data;
|
||||
char *type;
|
||||
|
||||
if (dock_station->flags & DOCK_IS_DOCK)
|
||||
|
@ -936,6 +908,19 @@ static ssize_t show_dock_type(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
|
||||
|
||||
static struct attribute *dock_attributes[] = {
|
||||
&dev_attr_docked.attr,
|
||||
&dev_attr_flags.attr,
|
||||
&dev_attr_undock.attr,
|
||||
&dev_attr_uid.attr,
|
||||
&dev_attr_type.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group dock_attribute_group = {
|
||||
.attrs = dock_attributes
|
||||
};
|
||||
|
||||
/**
|
||||
* dock_add - add a new dock station
|
||||
* @handle: the dock station handle
|
||||
|
@ -945,39 +930,30 @@ static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL);
|
|||
*/
|
||||
static int dock_add(acpi_handle handle)
|
||||
{
|
||||
int ret;
|
||||
struct dock_dependent_device *dd;
|
||||
struct dock_station *dock_station;
|
||||
struct platform_device *dock_device;
|
||||
int ret, id;
|
||||
struct dock_station ds, *dock_station;
|
||||
struct platform_device *dd;
|
||||
|
||||
id = dock_station_count;
|
||||
dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds));
|
||||
if (IS_ERR(dd))
|
||||
return PTR_ERR(dd);
|
||||
|
||||
dock_station = dd->dev.platform_data;
|
||||
|
||||
/* allocate & initialize the dock_station private data */
|
||||
dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL);
|
||||
if (!dock_station)
|
||||
return -ENOMEM;
|
||||
dock_station->handle = handle;
|
||||
dock_station->dock_device = dd;
|
||||
dock_station->last_dock_time = jiffies - HZ;
|
||||
INIT_LIST_HEAD(&dock_station->dependent_devices);
|
||||
INIT_LIST_HEAD(&dock_station->hotplug_devices);
|
||||
INIT_LIST_HEAD(&dock_station->sibling);
|
||||
spin_lock_init(&dock_station->dd_lock);
|
||||
mutex_init(&dock_station->hp_lock);
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
||||
|
||||
/* initialize platform device stuff */
|
||||
dock_station->dock_device =
|
||||
platform_device_register_simple(dock_device_name,
|
||||
dock_station_count, NULL, 0);
|
||||
dock_device = dock_station->dock_device;
|
||||
if (IS_ERR(dock_device)) {
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return PTR_ERR(dock_device);
|
||||
}
|
||||
platform_device_add_data(dock_device, &dock_station,
|
||||
sizeof(struct dock_station *));
|
||||
mutex_init(&dock_station->hp_lock);
|
||||
spin_lock_init(&dock_station->dd_lock);
|
||||
INIT_LIST_HEAD(&dock_station->sibling);
|
||||
INIT_LIST_HEAD(&dock_station->hotplug_devices);
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list);
|
||||
INIT_LIST_HEAD(&dock_station->dependent_devices);
|
||||
|
||||
/* we want the dock device to send uevents */
|
||||
dev_set_uevent_suppress(&dock_device->dev, 0);
|
||||
dev_set_uevent_suppress(&dd->dev, 0);
|
||||
|
||||
if (is_dock(handle))
|
||||
dock_station->flags |= DOCK_IS_DOCK;
|
||||
|
@ -986,47 +962,9 @@ static int dock_add(acpi_handle handle)
|
|||
if (is_battery(handle))
|
||||
dock_station->flags |= DOCK_IS_BAT;
|
||||
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_docked);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Error %d adding sysfs file\n", ret);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_undock);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Error %d adding sysfs file\n", ret);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_uid);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Error %d adding sysfs file\n", ret);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_flags);
|
||||
if (ret) {
|
||||
printk(KERN_ERR "Error %d adding sysfs file\n", ret);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return ret;
|
||||
}
|
||||
ret = device_create_file(&dock_device->dev, &dev_attr_type);
|
||||
ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
|
||||
if (ret)
|
||||
printk(KERN_ERR"Error %d adding sysfs file\n", ret);
|
||||
goto err_unregister;
|
||||
|
||||
/* Find dependent devices */
|
||||
acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
|
||||
|
@ -1034,58 +972,43 @@ static int dock_add(acpi_handle handle)
|
|||
dock_station, NULL);
|
||||
|
||||
/* add the dock station as a device dependent on itself */
|
||||
dd = alloc_dock_dependent_device(handle);
|
||||
if (!dd) {
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto dock_add_err_unregister;
|
||||
}
|
||||
add_dock_dependent_device(dock_station, dd);
|
||||
ret = add_dock_dependent_device(dock_station, handle);
|
||||
if (ret)
|
||||
goto err_rmgroup;
|
||||
|
||||
dock_station_count++;
|
||||
list_add(&dock_station->sibling, &dock_stations);
|
||||
return 0;
|
||||
|
||||
dock_add_err_unregister:
|
||||
device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_flags);
|
||||
platform_device_unregister(dock_device);
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
err_rmgroup:
|
||||
sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
|
||||
err_unregister:
|
||||
platform_device_unregister(dd);
|
||||
printk(KERN_ERR "%s encountered error %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dock_remove - free up resources related to the dock station
|
||||
*/
|
||||
static int dock_remove(struct dock_station *dock_station)
|
||||
static int dock_remove(struct dock_station *ds)
|
||||
{
|
||||
struct dock_dependent_device *dd, *tmp;
|
||||
struct platform_device *dock_device = dock_station->dock_device;
|
||||
struct platform_device *dock_device = ds->dock_device;
|
||||
|
||||
if (!dock_station_count)
|
||||
return 0;
|
||||
|
||||
/* remove dependent devices */
|
||||
list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices,
|
||||
list)
|
||||
kfree(dd);
|
||||
list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, list)
|
||||
kfree(dd);
|
||||
|
||||
list_del(&ds->sibling);
|
||||
|
||||
/* cleanup sysfs */
|
||||
device_remove_file(&dock_device->dev, &dev_attr_type);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_docked);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_undock);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_uid);
|
||||
device_remove_file(&dock_device->dev, &dev_attr_flags);
|
||||
sysfs_remove_group(&dock_device->dev.kobj, &dock_attribute_group);
|
||||
platform_device_unregister(dock_device);
|
||||
|
||||
/* free dock station memory */
|
||||
kfree(dock_station);
|
||||
dock_station = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1103,11 +1026,10 @@ find_dock(acpi_handle handle, u32 lvl, void *context, void **rv)
|
|||
{
|
||||
acpi_status status = AE_OK;
|
||||
|
||||
if (is_dock(handle)) {
|
||||
if (dock_add(handle) >= 0) {
|
||||
if (is_dock(handle))
|
||||
if (dock_add(handle) >= 0)
|
||||
status = AE_CTRL_TERMINATE;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1145,8 +1067,7 @@ static int __init dock_init(void)
|
|||
|
||||
static void __exit dock_exit(void)
|
||||
{
|
||||
struct dock_station *dock_station;
|
||||
struct dock_station *tmp;
|
||||
struct dock_station *tmp, *dock_station;
|
||||
|
||||
unregister_acpi_bus_notifier(&dock_acpi_notifier);
|
||||
list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling)
|
||||
|
|
|
@ -267,7 +267,7 @@ static int acpi_fan_add(struct acpi_device *device)
|
|||
goto end;
|
||||
}
|
||||
|
||||
dev_info(&device->dev, "registered as cooling_device%d\n", cdev->id);
|
||||
dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id);
|
||||
|
||||
device->driver_data = cdev;
|
||||
result = sysfs_create_link(&device->dev.kobj,
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/numa.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
|
||||
#define PREFIX "ACPI: "
|
||||
|
@ -40,14 +41,14 @@ static nodemask_t nodes_found_map = NODE_MASK_NONE;
|
|||
|
||||
/* maps to convert between proximity domain and logical node ID */
|
||||
static int pxm_to_node_map[MAX_PXM_DOMAINS]
|
||||
= { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL };
|
||||
= { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE };
|
||||
static int node_to_pxm_map[MAX_NUMNODES]
|
||||
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
|
||||
= { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
|
||||
|
||||
int pxm_to_node(int pxm)
|
||||
{
|
||||
if (pxm < 0)
|
||||
return NID_INVAL;
|
||||
return NUMA_NO_NODE;
|
||||
return pxm_to_node_map[pxm];
|
||||
}
|
||||
|
||||
|
@ -68,9 +69,9 @@ int acpi_map_pxm_to_node(int pxm)
|
|||
{
|
||||
int node = pxm_to_node_map[pxm];
|
||||
|
||||
if (node < 0){
|
||||
if (node < 0) {
|
||||
if (nodes_weight(nodes_found_map) >= MAX_NUMNODES)
|
||||
return NID_INVAL;
|
||||
return NUMA_NO_NODE;
|
||||
node = first_unset_node(nodes_found_map);
|
||||
__acpi_map_pxm_to_node(pxm, node);
|
||||
node_set(node, nodes_found_map);
|
||||
|
@ -79,16 +80,6 @@ int acpi_map_pxm_to_node(int pxm)
|
|||
return node;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void __cpuinit acpi_unmap_pxm_to_node(int node)
|
||||
{
|
||||
int pxm = node_to_pxm_map[node];
|
||||
pxm_to_node_map[pxm] = NID_INVAL;
|
||||
node_to_pxm_map[node] = PXM_INVAL;
|
||||
node_clear(node, nodes_found_map);
|
||||
}
|
||||
#endif /* 0 */
|
||||
|
||||
static void __init
|
||||
acpi_table_print_srat_entry(struct acpi_subtable_header *header)
|
||||
{
|
||||
|
|
|
@ -1118,7 +1118,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
|
|||
|
||||
/* Check for resource conflicts between ACPI OperationRegions and native
|
||||
* drivers */
|
||||
int acpi_check_resource_conflict(struct resource *res)
|
||||
int acpi_check_resource_conflict(const struct resource *res)
|
||||
{
|
||||
struct acpi_res_list *res_list_elem;
|
||||
int ioport;
|
||||
|
|
|
@ -202,72 +202,24 @@ static void acpi_pci_bridge_scan(struct acpi_device *device)
|
|||
}
|
||||
}
|
||||
|
||||
static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40,
|
||||
0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66};
|
||||
static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766";
|
||||
|
||||
static acpi_status acpi_pci_run_osc(acpi_handle handle,
|
||||
const u32 *capbuf, u32 *retval)
|
||||
{
|
||||
struct acpi_osc_context context = {
|
||||
.uuid_str = pci_osc_uuid_str,
|
||||
.rev = 1,
|
||||
.cap.length = 12,
|
||||
.cap.pointer = (void *)capbuf,
|
||||
};
|
||||
acpi_status status;
|
||||
struct acpi_object_list input;
|
||||
union acpi_object in_params[4];
|
||||
struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
|
||||
union acpi_object *out_obj;
|
||||
u32 errors;
|
||||
|
||||
/* Setting up input parameters */
|
||||
input.count = 4;
|
||||
input.pointer = in_params;
|
||||
in_params[0].type = ACPI_TYPE_BUFFER;
|
||||
in_params[0].buffer.length = 16;
|
||||
in_params[0].buffer.pointer = OSC_UUID;
|
||||
in_params[1].type = ACPI_TYPE_INTEGER;
|
||||
in_params[1].integer.value = 1;
|
||||
in_params[2].type = ACPI_TYPE_INTEGER;
|
||||
in_params[2].integer.value = 3;
|
||||
in_params[3].type = ACPI_TYPE_BUFFER;
|
||||
in_params[3].buffer.length = 12;
|
||||
in_params[3].buffer.pointer = (u8 *)capbuf;
|
||||
|
||||
status = acpi_evaluate_object(handle, "_OSC", &input, &output);
|
||||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
if (!output.length)
|
||||
return AE_NULL_OBJECT;
|
||||
|
||||
out_obj = output.pointer;
|
||||
if (out_obj->type != ACPI_TYPE_BUFFER) {
|
||||
printk(KERN_DEBUG "_OSC evaluation returned wrong type\n");
|
||||
status = AE_TYPE;
|
||||
goto out_kfree;
|
||||
status = acpi_run_osc(handle, &context);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
*retval = *((u32 *)(context.ret.pointer + 8));
|
||||
kfree(context.ret.pointer);
|
||||
}
|
||||
/* Need to ignore the bit0 in result code */
|
||||
errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0);
|
||||
if (errors) {
|
||||
if (errors & OSC_REQUEST_ERROR)
|
||||
printk(KERN_DEBUG "_OSC request failed\n");
|
||||
if (errors & OSC_INVALID_UUID_ERROR)
|
||||
printk(KERN_DEBUG "_OSC invalid UUID\n");
|
||||
if (errors & OSC_INVALID_REVISION_ERROR)
|
||||
printk(KERN_DEBUG "_OSC invalid revision\n");
|
||||
if (errors & OSC_CAPABILITIES_MASK_ERROR) {
|
||||
if (capbuf[OSC_QUERY_TYPE] & OSC_QUERY_ENABLE)
|
||||
goto out_success;
|
||||
printk(KERN_DEBUG
|
||||
"Firmware did not grant requested _OSC control\n");
|
||||
status = AE_SUPPORT;
|
||||
goto out_kfree;
|
||||
}
|
||||
status = AE_ERROR;
|
||||
goto out_kfree;
|
||||
}
|
||||
out_success:
|
||||
*retval = *((u32 *)(out_obj->buffer.pointer + 8));
|
||||
status = AE_OK;
|
||||
|
||||
out_kfree:
|
||||
kfree(output.pointer);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -277,10 +229,10 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags)
|
|||
u32 support_set, result, capbuf[3];
|
||||
|
||||
/* do _OSC query for all possible controls */
|
||||
support_set = root->osc_support_set | (flags & OSC_SUPPORT_MASKS);
|
||||
support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);
|
||||
capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE;
|
||||
capbuf[OSC_SUPPORT_TYPE] = support_set;
|
||||
capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS;
|
||||
capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS;
|
||||
|
||||
status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
|
@ -427,7 +379,7 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
|
|||
if (ACPI_FAILURE(status))
|
||||
return status;
|
||||
|
||||
control_req = (flags & OSC_CONTROL_MASKS);
|
||||
control_req = (flags & OSC_PCI_CONTROL_MASKS);
|
||||
if (!control_req)
|
||||
return AE_TYPE;
|
||||
|
||||
|
|
|
@ -353,7 +353,7 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file)
|
|||
PDE(inode)->data);
|
||||
}
|
||||
|
||||
static int acpi_processor_add_fs(struct acpi_device *device)
|
||||
static int __cpuinit acpi_processor_add_fs(struct acpi_device *device)
|
||||
{
|
||||
struct proc_dir_entry *entry = NULL;
|
||||
|
||||
|
@ -722,7 +722,7 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event)
|
|||
switch (event) {
|
||||
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
|
||||
saved = pr->performance_platform_limit;
|
||||
acpi_processor_ppc_has_changed(pr);
|
||||
acpi_processor_ppc_has_changed(pr, 1);
|
||||
if (saved == pr->performance_platform_limit)
|
||||
break;
|
||||
acpi_bus_generate_proc_event(device, event,
|
||||
|
@ -758,7 +758,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
|
|||
struct acpi_processor *pr = per_cpu(processors, cpu);
|
||||
|
||||
if (action == CPU_ONLINE && pr) {
|
||||
acpi_processor_ppc_has_changed(pr);
|
||||
acpi_processor_ppc_has_changed(pr, 0);
|
||||
acpi_processor_cst_has_changed(pr);
|
||||
acpi_processor_tstate_has_changed(pr);
|
||||
}
|
||||
|
@ -830,7 +830,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
|
|||
arch_acpi_processor_cleanup_pdc(pr);
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ
|
||||
acpi_processor_ppc_has_changed(pr);
|
||||
acpi_processor_ppc_has_changed(pr, 0);
|
||||
#endif
|
||||
acpi_processor_get_throttling_info(pr);
|
||||
acpi_processor_get_limit_info(pr);
|
||||
|
@ -845,7 +845,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device)
|
|||
goto err_power_exit;
|
||||
}
|
||||
|
||||
dev_info(&device->dev, "registered as cooling_device%d\n",
|
||||
dev_dbg(&device->dev, "registered as cooling_device%d\n",
|
||||
pr->cdev->id);
|
||||
|
||||
result = sysfs_create_link(&device->dev.kobj,
|
||||
|
|
|
@ -164,7 +164,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr,
|
|||
pr->power.timer_broadcast_on_state = state;
|
||||
}
|
||||
|
||||
static void lapic_timer_propagate_broadcast(void *arg)
|
||||
static void __lapic_timer_propagate_broadcast(void *arg)
|
||||
{
|
||||
struct acpi_processor *pr = (struct acpi_processor *) arg;
|
||||
unsigned long reason;
|
||||
|
@ -175,6 +175,12 @@ static void lapic_timer_propagate_broadcast(void *arg)
|
|||
clockevents_notify(reason, &pr->id);
|
||||
}
|
||||
|
||||
static void lapic_timer_propagate_broadcast(struct acpi_processor *pr)
|
||||
{
|
||||
smp_call_function_single(pr->id, __lapic_timer_propagate_broadcast,
|
||||
(void *)pr, 1);
|
||||
}
|
||||
|
||||
/* Power(C) State timer broadcast control */
|
||||
static void lapic_timer_state_broadcast(struct acpi_processor *pr,
|
||||
struct acpi_processor_cx *cx,
|
||||
|
@ -638,8 +644,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
|
|||
working++;
|
||||
}
|
||||
|
||||
smp_call_function_single(pr->id, lapic_timer_propagate_broadcast,
|
||||
pr, 1);
|
||||
lapic_timer_propagate_broadcast(pr);
|
||||
|
||||
return (working);
|
||||
}
|
||||
|
|
|
@ -152,15 +152,59 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
|
||||
#define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80
|
||||
/*
|
||||
* acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status
|
||||
* @handle: ACPI processor handle
|
||||
* @status: the status code of _PPC evaluation
|
||||
* 0: success. OSPM is now using the performance state specificed.
|
||||
* 1: failure. OSPM has not changed the number of P-states in use
|
||||
*/
|
||||
static void acpi_processor_ppc_ost(acpi_handle handle, int status)
|
||||
{
|
||||
union acpi_object params[2] = {
|
||||
{.type = ACPI_TYPE_INTEGER,},
|
||||
{.type = ACPI_TYPE_INTEGER,},
|
||||
};
|
||||
struct acpi_object_list arg_list = {2, params};
|
||||
acpi_handle temp;
|
||||
|
||||
params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE;
|
||||
params[1].integer.value = status;
|
||||
|
||||
/* when there is no _OST , skip it */
|
||||
if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp)))
|
||||
return;
|
||||
|
||||
acpi_evaluate_object(handle, "_OST", &arg_list, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ignore_ppc)
|
||||
if (ignore_ppc) {
|
||||
/*
|
||||
* Only when it is notification event, the _OST object
|
||||
* will be evaluated. Otherwise it is skipped.
|
||||
*/
|
||||
if (event_flag)
|
||||
acpi_processor_ppc_ost(pr->handle, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = acpi_processor_get_platform_limit(pr);
|
||||
|
||||
/*
|
||||
* Only when it is notification event, the _OST object
|
||||
* will be evaluated. Otherwise it is skipped.
|
||||
*/
|
||||
if (event_flag) {
|
||||
if (ret < 0)
|
||||
acpi_processor_ppc_ost(pr->handle, 1);
|
||||
else
|
||||
acpi_processor_ppc_ost(pr->handle, 0);
|
||||
}
|
||||
if (ret < 0)
|
||||
return (ret);
|
||||
else
|
||||
|
|
|
@ -1052,6 +1052,13 @@ static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset)
|
|||
acpi_device_bid(device));
|
||||
}
|
||||
seq_puts(seq, "\n");
|
||||
} else {
|
||||
seq_printf(seq, "passive (forced):");
|
||||
if (tz->thermal_zone->forced_passive)
|
||||
seq_printf(seq, " %i C\n",
|
||||
tz->thermal_zone->forced_passive / 1000);
|
||||
else
|
||||
seq_printf(seq, "<not set>\n");
|
||||
}
|
||||
|
||||
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
#include <linux/dmi.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/pnp.h>
|
||||
|
||||
#ifdef CONFIG_PPC_OF
|
||||
#include <linux/of_device.h>
|
||||
|
@ -1919,7 +1920,7 @@ struct SPMITable {
|
|||
s8 spmi_id[1]; /* A '\0' terminated array starts here. */
|
||||
};
|
||||
|
||||
static __devinit int try_init_acpi(struct SPMITable *spmi)
|
||||
static __devinit int try_init_spmi(struct SPMITable *spmi)
|
||||
{
|
||||
struct smi_info *info;
|
||||
u8 addr_space;
|
||||
|
@ -1940,7 +1941,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info->addr_source = "ACPI";
|
||||
info->addr_source = "SPMI";
|
||||
|
||||
/* Figure out the interface type. */
|
||||
switch (spmi->InterfaceType) {
|
||||
|
@ -2002,7 +2003,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static __devinit void acpi_find_bmc(void)
|
||||
static __devinit void spmi_find_bmc(void)
|
||||
{
|
||||
acpi_status status;
|
||||
struct SPMITable *spmi;
|
||||
|
@ -2020,9 +2021,106 @@ static __devinit void acpi_find_bmc(void)
|
|||
if (status != AE_OK)
|
||||
return;
|
||||
|
||||
try_init_acpi(spmi);
|
||||
try_init_spmi(spmi);
|
||||
}
|
||||
}
|
||||
|
||||
static int __devinit ipmi_pnp_probe(struct pnp_dev *dev,
|
||||
const struct pnp_device_id *dev_id)
|
||||
{
|
||||
struct acpi_device *acpi_dev;
|
||||
struct smi_info *info;
|
||||
acpi_handle handle;
|
||||
acpi_status status;
|
||||
unsigned long long tmp;
|
||||
|
||||
acpi_dev = pnp_acpi_device(dev);
|
||||
if (!acpi_dev)
|
||||
return -ENODEV;
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
|
||||
info->addr_source = "ACPI";
|
||||
|
||||
handle = acpi_dev->handle;
|
||||
|
||||
/* _IFT tells us the interface type: KCS, BT, etc */
|
||||
status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp);
|
||||
if (ACPI_FAILURE(status))
|
||||
goto err_free;
|
||||
|
||||
switch (tmp) {
|
||||
case 1:
|
||||
info->si_type = SI_KCS;
|
||||
break;
|
||||
case 2:
|
||||
info->si_type = SI_SMIC;
|
||||
break;
|
||||
case 3:
|
||||
info->si_type = SI_BT;
|
||||
break;
|
||||
default:
|
||||
dev_info(&dev->dev, "unknown interface type %lld\n", tmp);
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
if (pnp_port_valid(dev, 0)) {
|
||||
info->io_setup = port_setup;
|
||||
info->io.addr_type = IPMI_IO_ADDR_SPACE;
|
||||
info->io.addr_data = pnp_port_start(dev, 0);
|
||||
} else if (pnp_mem_valid(dev, 0)) {
|
||||
info->io_setup = mem_setup;
|
||||
info->io.addr_type = IPMI_MEM_ADDR_SPACE;
|
||||
info->io.addr_data = pnp_mem_start(dev, 0);
|
||||
} else {
|
||||
dev_err(&dev->dev, "no I/O or memory address\n");
|
||||
goto err_free;
|
||||
}
|
||||
|
||||
info->io.regspacing = DEFAULT_REGSPACING;
|
||||
info->io.regsize = DEFAULT_REGSPACING;
|
||||
info->io.regshift = 0;
|
||||
|
||||
/* If _GPE exists, use it; otherwise use standard interrupts */
|
||||
status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp);
|
||||
if (ACPI_SUCCESS(status)) {
|
||||
info->irq = tmp;
|
||||
info->irq_setup = acpi_gpe_irq_setup;
|
||||
} else if (pnp_irq_valid(dev, 0)) {
|
||||
info->irq = pnp_irq(dev, 0);
|
||||
info->irq_setup = std_irq_setup;
|
||||
}
|
||||
|
||||
info->dev = &acpi_dev->dev;
|
||||
pnp_set_drvdata(dev, info);
|
||||
|
||||
return try_smi_init(info);
|
||||
|
||||
err_free:
|
||||
kfree(info);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void __devexit ipmi_pnp_remove(struct pnp_dev *dev)
|
||||
{
|
||||
struct smi_info *info = pnp_get_drvdata(dev);
|
||||
|
||||
cleanup_one_si(info);
|
||||
}
|
||||
|
||||
static const struct pnp_device_id pnp_dev_table[] = {
|
||||
{"IPI0001", 0},
|
||||
{"", 0},
|
||||
};
|
||||
|
||||
static struct pnp_driver ipmi_pnp_driver = {
|
||||
.name = DEVICE_NAME,
|
||||
.probe = ipmi_pnp_probe,
|
||||
.remove = __devexit_p(ipmi_pnp_remove),
|
||||
.id_table = pnp_dev_table,
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_DMI
|
||||
|
@ -2202,7 +2300,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
|
|||
int rv;
|
||||
int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK;
|
||||
struct smi_info *info;
|
||||
int first_reg_offset = 0;
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
|
@ -2241,9 +2338,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev,
|
|||
info->addr_source_cleanup = ipmi_pci_cleanup;
|
||||
info->addr_source_data = pdev;
|
||||
|
||||
if (pdev->subsystem_vendor == PCI_HP_VENDOR_ID)
|
||||
first_reg_offset = 1;
|
||||
|
||||
if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) {
|
||||
info->io_setup = port_setup;
|
||||
info->io.addr_type = IPMI_IO_ADDR_SPACE;
|
||||
|
@ -3108,7 +3202,10 @@ static __devinit int init_ipmi_si(void)
|
|||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
acpi_find_bmc();
|
||||
spmi_find_bmc();
|
||||
#endif
|
||||
#ifdef CONFIG_PNP
|
||||
pnp_register_driver(&ipmi_pnp_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCI
|
||||
|
@ -3233,6 +3330,9 @@ static __exit void cleanup_ipmi_si(void)
|
|||
#ifdef CONFIG_PCI
|
||||
pci_unregister_driver(&ipmi_pci_driver);
|
||||
#endif
|
||||
#ifdef CONFIG_PNP
|
||||
pnp_unregister_driver(&ipmi_pnp_driver);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PPC_OF
|
||||
of_unregister_platform_driver(&ipmi_of_platform_driver);
|
||||
|
|
|
@ -248,19 +248,6 @@ config SGI_GRU_DEBUG
|
|||
This option enables addition debugging code for the SGI GRU driver. If
|
||||
you are unsure, say N.
|
||||
|
||||
config DELL_LAPTOP
|
||||
tristate "Dell Laptop Extras (EXPERIMENTAL)"
|
||||
depends on X86
|
||||
depends on DCDBAS
|
||||
depends on EXPERIMENTAL
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on RFKILL
|
||||
depends on POWER_SUPPLY
|
||||
default n
|
||||
---help---
|
||||
This driver adds support for rfkill and backlight control to Dell
|
||||
laptops.
|
||||
|
||||
config ISL29003
|
||||
tristate "Intersil ISL29003 ambient light sensor"
|
||||
depends on I2C && SYSFS
|
||||
|
|
|
@ -334,6 +334,8 @@ config EEEPC_LAPTOP
|
|||
depends on HOTPLUG_PCI
|
||||
select BACKLIGHT_CLASS_DEVICE
|
||||
select HWMON
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
---help---
|
||||
This driver supports the Fn-Fx keys on Eee PC laptops.
|
||||
|
||||
|
@ -365,6 +367,18 @@ config ACPI_WMI
|
|||
It is safe to enable this driver even if your DSDT doesn't define
|
||||
any ACPI-WMI devices.
|
||||
|
||||
config MSI_WMI
|
||||
tristate "MSI WMI extras"
|
||||
depends on ACPI_WMI
|
||||
depends on INPUT
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
select INPUT_SPARSEKMAP
|
||||
help
|
||||
Say Y here if you want to support WMI-based hotkeys on MSI laptops.
|
||||
|
||||
To compile this driver as a module, choose M here: the module will
|
||||
be called msi-wmi.
|
||||
|
||||
config ACPI_ASUS
|
||||
tristate "ASUS/Medion Laptop Extras (DEPRECATED)"
|
||||
depends on ACPI
|
||||
|
@ -435,4 +449,19 @@ config ACPI_TOSHIBA
|
|||
|
||||
If you have a legacy free Toshiba laptop (such as the Libretto L1
|
||||
series), say Y.
|
||||
|
||||
config TOSHIBA_BT_RFKILL
|
||||
tristate "Toshiba Bluetooth RFKill switch support"
|
||||
depends on ACPI
|
||||
---help---
|
||||
This driver adds support for Bluetooth events for the RFKill
|
||||
switch on modern Toshiba laptops with full ACPI support and
|
||||
an RFKill switch.
|
||||
|
||||
This driver handles RFKill events for the TOS6205 Bluetooth,
|
||||
and re-enables it when the switch is set back to the 'on'
|
||||
position.
|
||||
|
||||
If you have a modern Toshiba laptop with a Bluetooth and an
|
||||
RFKill switch (such as the Portege R500), say Y.
|
||||
endif # X86_PLATFORM_DEVICES
|
||||
|
|
|
@ -18,6 +18,8 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o
|
|||
obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
|
||||
obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
|
||||
obj-$(CONFIG_ACPI_WMI) += wmi.o
|
||||
obj-$(CONFIG_MSI_WMI) += msi-wmi.o
|
||||
obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o
|
||||
obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o
|
||||
obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o
|
||||
obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
*/
|
||||
#undef START_IN_KERNEL_MODE
|
||||
|
||||
#define DRV_VER "0.5.18"
|
||||
#define DRV_VER "0.5.20"
|
||||
|
||||
/*
|
||||
* According to the Atom N270 datasheet,
|
||||
|
@ -112,12 +112,14 @@ module_param_string(force_product, force_product, 16, 0);
|
|||
MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check");
|
||||
|
||||
/*
|
||||
* cmd_off: to switch the fan completely off / to check if the fan is off
|
||||
* cmd_off: to switch the fan completely off
|
||||
* chk_off: to check if the fan is off
|
||||
* cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then
|
||||
* the fan speed depending on the temperature
|
||||
*/
|
||||
struct fancmd {
|
||||
u8 cmd_off;
|
||||
u8 chk_off;
|
||||
u8 cmd_auto;
|
||||
};
|
||||
|
||||
|
@ -134,32 +136,41 @@ struct bios_settings_t {
|
|||
/* Register addresses and values for different BIOS versions */
|
||||
static const struct bios_settings_t bios_tbl[] = {
|
||||
/* AOA110 */
|
||||
{"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} },
|
||||
{"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} },
|
||||
/* AOA150 */
|
||||
{"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
/* Acer 1410 */
|
||||
{"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} },
|
||||
/* special BIOS / other */
|
||||
{"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} },
|
||||
{"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} },
|
||||
{"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} },
|
||||
{"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} },
|
||||
{"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} },
|
||||
{"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Gateway ", "LT31 ", "v1.3103 ", 0x55, 0x58,
|
||||
{0x10, 0x0f, 0x00} },
|
||||
{"Gateway ", "LT31 ", "v1.3201 ", 0x55, 0x58,
|
||||
{0x10, 0x0f, 0x00} },
|
||||
{"Gateway ", "LT31 ", "v1.3302 ", 0x55, 0x58,
|
||||
{0x10, 0x0f, 0x00} },
|
||||
{"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} },
|
||||
{"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
{"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} },
|
||||
{"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} },
|
||||
/* pewpew-terminator */
|
||||
{"", "", "", 0, 0, {0, 0} }
|
||||
{"", "", "", 0, 0, {0, 0, 0} }
|
||||
};
|
||||
|
||||
static const struct bios_settings_t *bios_cfg __read_mostly;
|
||||
|
@ -183,7 +194,7 @@ static int acerhdf_get_fanstate(int *state)
|
|||
if (ec_read(bios_cfg->fanreg, &fan))
|
||||
return -EINVAL;
|
||||
|
||||
if (fan != bios_cfg->cmd.cmd_off)
|
||||
if (fan != bios_cfg->cmd.chk_off)
|
||||
*state = ACERHDF_FAN_AUTO;
|
||||
else
|
||||
*state = ACERHDF_FAN_OFF;
|
||||
|
|
|
@ -221,6 +221,7 @@ static struct asus_hotk *hotk;
|
|||
*/
|
||||
static const struct acpi_device_id asus_device_ids[] = {
|
||||
{"ATK0100", 0},
|
||||
{"ATK0101", 0},
|
||||
{"", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, asus_device_ids);
|
||||
|
@ -232,6 +233,7 @@ static void asus_hotk_notify(struct acpi_device *device, u32 event);
|
|||
static struct acpi_driver asus_hotk_driver = {
|
||||
.name = ASUS_HOTK_NAME,
|
||||
.class = ASUS_HOTK_CLASS,
|
||||
.owner = THIS_MODULE,
|
||||
.ids = asus_device_ids,
|
||||
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
|
||||
.ops = {
|
||||
|
@ -293,6 +295,11 @@ struct key_entry {
|
|||
enum { KE_KEY, KE_END };
|
||||
|
||||
static struct key_entry asus_keymap[] = {
|
||||
{KE_KEY, 0x02, KEY_SCREENLOCK},
|
||||
{KE_KEY, 0x05, KEY_WLAN},
|
||||
{KE_KEY, 0x08, KEY_F13},
|
||||
{KE_KEY, 0x17, KEY_ZOOM},
|
||||
{KE_KEY, 0x1f, KEY_BATTERY},
|
||||
{KE_KEY, 0x30, KEY_VOLUMEUP},
|
||||
{KE_KEY, 0x31, KEY_VOLUMEDOWN},
|
||||
{KE_KEY, 0x32, KEY_MUTE},
|
||||
|
@ -312,8 +319,11 @@ static struct key_entry asus_keymap[] = {
|
|||
{KE_KEY, 0x5F, KEY_WLAN},
|
||||
{KE_KEY, 0x60, KEY_SWITCHVIDEOMODE},
|
||||
{KE_KEY, 0x61, KEY_SWITCHVIDEOMODE},
|
||||
{KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */
|
||||
{KE_KEY, 0x62, KEY_SWITCHVIDEOMODE},
|
||||
{KE_KEY, 0x63, KEY_SWITCHVIDEOMODE},
|
||||
{KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */
|
||||
{KE_KEY, 0x82, KEY_CAMERA},
|
||||
{KE_KEY, 0x88, KEY_WLAN },
|
||||
{KE_KEY, 0x8A, KEY_PROG1},
|
||||
{KE_KEY, 0x95, KEY_MEDIA},
|
||||
{KE_KEY, 0x99, KEY_PHONE},
|
||||
|
@ -1240,9 +1250,6 @@ static int asus_hotk_add(struct acpi_device *device)
|
|||
{
|
||||
int result;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
pr_notice("Asus Laptop Support version %s\n",
|
||||
ASUS_LAPTOP_VERSION);
|
||||
|
||||
|
@ -1283,8 +1290,8 @@ static int asus_hotk_add(struct acpi_device *device)
|
|||
hotk->ledd_status = 0xFFF;
|
||||
|
||||
/* Set initial values of light sensor and level */
|
||||
hotk->light_switch = 1; /* Default to light sensor disabled */
|
||||
hotk->light_level = 0; /* level 5 for sensor sensitivity */
|
||||
hotk->light_switch = 0; /* Default to light sensor disabled */
|
||||
hotk->light_level = 5; /* level 5 for sensor sensitivity */
|
||||
|
||||
if (ls_switch_handle)
|
||||
set_light_sens_switch(hotk->light_switch);
|
||||
|
@ -1306,9 +1313,6 @@ end:
|
|||
|
||||
static int asus_hotk_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
kfree(hotk->name);
|
||||
kfree(hotk);
|
||||
|
||||
|
@ -1444,9 +1448,6 @@ static int __init asus_laptop_init(void)
|
|||
{
|
||||
int result;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
|
||||
result = acpi_bus_register_driver(&asus_hotk_driver);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
|
|
@ -466,6 +466,7 @@ MODULE_DEVICE_TABLE(acpi, asus_device_ids);
|
|||
static struct acpi_driver asus_hotk_driver = {
|
||||
.name = "asus_acpi",
|
||||
.class = ACPI_HOTK_CLASS,
|
||||
.owner = THIS_MODULE,
|
||||
.ids = asus_device_ids,
|
||||
.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
|
||||
.ops = {
|
||||
|
@ -1334,9 +1335,6 @@ static int asus_hotk_add(struct acpi_device *device)
|
|||
acpi_status status = AE_OK;
|
||||
int result;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
|
||||
ASUS_ACPI_VERSION);
|
||||
|
||||
|
@ -1392,9 +1390,6 @@ end:
|
|||
|
||||
static int asus_hotk_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
asus_hotk_remove_fs(device);
|
||||
|
||||
kfree(hotk);
|
||||
|
@ -1422,21 +1417,17 @@ static int __init asus_acpi_init(void)
|
|||
{
|
||||
int result;
|
||||
|
||||
if (acpi_disabled)
|
||||
return -ENODEV;
|
||||
result = acpi_bus_register_driver(&asus_hotk_driver);
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
|
||||
if (!asus_proc_dir) {
|
||||
printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
|
||||
acpi_bus_unregister_driver(&asus_hotk_driver);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result = acpi_bus_register_driver(&asus_hotk_driver);
|
||||
if (result < 0) {
|
||||
remove_proc_entry(PROC_ASUS, acpi_root_dir);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a bit of a kludge. We only want this module loaded
|
||||
* for ASUS systems, but there's currently no way to probe the
|
||||
|
|
|
@ -58,6 +58,14 @@ static int da_command_code;
|
|||
static int da_num_tokens;
|
||||
static struct calling_interface_token *da_tokens;
|
||||
|
||||
static struct platform_driver platform_driver = {
|
||||
.driver = {
|
||||
.name = "dell-laptop",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
static struct platform_device *platform_device;
|
||||
static struct backlight_device *dell_backlight_device;
|
||||
static struct rfkill *wifi_rfkill;
|
||||
static struct rfkill *bluetooth_rfkill;
|
||||
|
@ -74,7 +82,7 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static void parse_da_table(const struct dmi_header *dm)
|
||||
static void __init parse_da_table(const struct dmi_header *dm)
|
||||
{
|
||||
/* Final token is a terminator, so we don't want to copy it */
|
||||
int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1;
|
||||
|
@ -103,7 +111,7 @@ static void parse_da_table(const struct dmi_header *dm)
|
|||
da_num_tokens += tokens;
|
||||
}
|
||||
|
||||
static void find_tokens(const struct dmi_header *dm, void *dummy)
|
||||
static void __init find_tokens(const struct dmi_header *dm, void *dummy)
|
||||
{
|
||||
switch (dm->type) {
|
||||
case 0xd4: /* Indexed IO */
|
||||
|
@ -197,8 +205,8 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data)
|
|||
dell_send_request(&buffer, 17, 11);
|
||||
status = buffer.output[1];
|
||||
|
||||
if (status & BIT(bit))
|
||||
rfkill_set_hw_state(rfkill, !!(status & BIT(16)));
|
||||
rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
|
||||
rfkill_set_hw_state(rfkill, !(status & BIT(16)));
|
||||
}
|
||||
|
||||
static const struct rfkill_ops dell_rfkill_ops = {
|
||||
|
@ -206,7 +214,7 @@ static const struct rfkill_ops dell_rfkill_ops = {
|
|||
.query = dell_rfkill_query,
|
||||
};
|
||||
|
||||
static int dell_setup_rfkill(void)
|
||||
static int __init dell_setup_rfkill(void)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
int status;
|
||||
|
@ -217,7 +225,8 @@ static int dell_setup_rfkill(void)
|
|||
status = buffer.output[1];
|
||||
|
||||
if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
|
||||
wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN,
|
||||
wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
|
||||
RFKILL_TYPE_WLAN,
|
||||
&dell_rfkill_ops, (void *) 1);
|
||||
if (!wifi_rfkill) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -229,7 +238,8 @@ static int dell_setup_rfkill(void)
|
|||
}
|
||||
|
||||
if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
|
||||
bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL,
|
||||
bluetooth_rfkill = rfkill_alloc("dell-bluetooth",
|
||||
&platform_device->dev,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&dell_rfkill_ops, (void *) 2);
|
||||
if (!bluetooth_rfkill) {
|
||||
|
@ -242,7 +252,9 @@ static int dell_setup_rfkill(void)
|
|||
}
|
||||
|
||||
if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
|
||||
wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN,
|
||||
wwan_rfkill = rfkill_alloc("dell-wwan",
|
||||
&platform_device->dev,
|
||||
RFKILL_TYPE_WWAN,
|
||||
&dell_rfkill_ops, (void *) 3);
|
||||
if (!wwan_rfkill) {
|
||||
ret = -ENOMEM;
|
||||
|
@ -268,6 +280,22 @@ err_wifi:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void dell_cleanup_rfkill(void)
|
||||
{
|
||||
if (wifi_rfkill) {
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
rfkill_destroy(wifi_rfkill);
|
||||
}
|
||||
if (bluetooth_rfkill) {
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
rfkill_destroy(bluetooth_rfkill);
|
||||
}
|
||||
if (wwan_rfkill) {
|
||||
rfkill_unregister(wwan_rfkill);
|
||||
rfkill_destroy(wwan_rfkill);
|
||||
}
|
||||
}
|
||||
|
||||
static int dell_send_intensity(struct backlight_device *bd)
|
||||
{
|
||||
struct calling_interface_buffer buffer;
|
||||
|
@ -326,11 +354,23 @@ static int __init dell_init(void)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
ret = platform_driver_register(&platform_driver);
|
||||
if (ret)
|
||||
goto fail_platform_driver;
|
||||
platform_device = platform_device_alloc("dell-laptop", -1);
|
||||
if (!platform_device) {
|
||||
ret = -ENOMEM;
|
||||
goto fail_platform_device1;
|
||||
}
|
||||
ret = platform_device_add(platform_device);
|
||||
if (ret)
|
||||
goto fail_platform_device2;
|
||||
|
||||
ret = dell_setup_rfkill();
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n");
|
||||
goto out;
|
||||
goto fail_rfkill;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
|
@ -352,13 +392,13 @@ static int __init dell_init(void)
|
|||
if (max_intensity) {
|
||||
dell_backlight_device = backlight_device_register(
|
||||
"dell_backlight",
|
||||
NULL, NULL,
|
||||
&platform_device->dev, NULL,
|
||||
&dell_ops);
|
||||
|
||||
if (IS_ERR(dell_backlight_device)) {
|
||||
ret = PTR_ERR(dell_backlight_device);
|
||||
dell_backlight_device = NULL;
|
||||
goto out;
|
||||
goto fail_backlight;
|
||||
}
|
||||
|
||||
dell_backlight_device->props.max_brightness = max_intensity;
|
||||
|
@ -368,13 +408,16 @@ static int __init dell_init(void)
|
|||
}
|
||||
|
||||
return 0;
|
||||
out:
|
||||
if (wifi_rfkill)
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
if (wwan_rfkill)
|
||||
rfkill_unregister(wwan_rfkill);
|
||||
|
||||
fail_backlight:
|
||||
dell_cleanup_rfkill();
|
||||
fail_rfkill:
|
||||
platform_device_del(platform_device);
|
||||
fail_platform_device2:
|
||||
platform_device_put(platform_device);
|
||||
fail_platform_device1:
|
||||
platform_driver_unregister(&platform_driver);
|
||||
fail_platform_driver:
|
||||
kfree(da_tokens);
|
||||
return ret;
|
||||
}
|
||||
|
@ -382,12 +425,7 @@ out:
|
|||
static void __exit dell_exit(void)
|
||||
{
|
||||
backlight_device_unregister(dell_backlight_device);
|
||||
if (wifi_rfkill)
|
||||
rfkill_unregister(wifi_rfkill);
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_unregister(bluetooth_rfkill);
|
||||
if (wwan_rfkill)
|
||||
rfkill_unregister(wwan_rfkill);
|
||||
dell_cleanup_rfkill();
|
||||
}
|
||||
|
||||
module_init(dell_init);
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <acpi/acpi_drivers.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dmi.h>
|
||||
|
||||
MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>");
|
||||
MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver");
|
||||
|
@ -38,6 +39,8 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
#define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492"
|
||||
|
||||
static int acpi_video;
|
||||
|
||||
MODULE_ALIAS("wmi:"DELL_EVENT_GUID);
|
||||
|
||||
struct key_entry {
|
||||
|
@ -54,7 +57,7 @@ enum { KE_KEY, KE_SW, KE_IGNORE, KE_END };
|
|||
* via the keyboard controller so should not be sent again.
|
||||
*/
|
||||
|
||||
static struct key_entry dell_wmi_keymap[] = {
|
||||
static struct key_entry dell_legacy_wmi_keymap[] = {
|
||||
{KE_KEY, 0xe045, KEY_PROG1},
|
||||
{KE_KEY, 0xe009, KEY_EJECTCD},
|
||||
|
||||
|
@ -72,7 +75,7 @@ static struct key_entry dell_wmi_keymap[] = {
|
|||
|
||||
/* The next device is at offset 6, the active devices are at
|
||||
offset 8 and the attached devices at offset 10 */
|
||||
{KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE},
|
||||
{KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE},
|
||||
|
||||
{KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE},
|
||||
|
||||
|
@ -96,6 +99,47 @@ static struct key_entry dell_wmi_keymap[] = {
|
|||
{KE_END, 0}
|
||||
};
|
||||
|
||||
static bool dell_new_hk_type;
|
||||
|
||||
struct dell_new_keymap_entry {
|
||||
u16 scancode;
|
||||
u16 keycode;
|
||||
};
|
||||
|
||||
struct dell_hotkey_table {
|
||||
struct dmi_header header;
|
||||
struct dell_new_keymap_entry keymap[];
|
||||
|
||||
};
|
||||
|
||||
static struct key_entry *dell_new_wmi_keymap;
|
||||
|
||||
static u16 bios_to_linux_keycode[256] = {
|
||||
|
||||
KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG,
|
||||
KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE,
|
||||
KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD,
|
||||
KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN,
|
||||
KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE,
|
||||
KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN,
|
||||
KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2,
|
||||
KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
KEY_PROG3
|
||||
};
|
||||
|
||||
|
||||
static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap;
|
||||
|
||||
static struct input_dev *dell_wmi_input_dev;
|
||||
|
||||
static struct key_entry *dell_wmi_get_entry_by_scancode(int code)
|
||||
|
@ -164,24 +208,78 @@ static void dell_wmi_notify(u32 value, void *context)
|
|||
obj = (union acpi_object *)response.pointer;
|
||||
|
||||
if (obj && obj->type == ACPI_TYPE_BUFFER) {
|
||||
int *buffer = (int *)obj->buffer.pointer;
|
||||
/*
|
||||
* The upper bytes of the event may contain
|
||||
* additional information, so mask them off for the
|
||||
* scancode lookup
|
||||
*/
|
||||
key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF);
|
||||
if (key) {
|
||||
int reported_key;
|
||||
u16 *buffer_entry = (u16 *)obj->buffer.pointer;
|
||||
if (dell_new_hk_type && (buffer_entry[1] != 0x10)) {
|
||||
printk(KERN_INFO "dell-wmi: Received unknown WMI event"
|
||||
" (0x%x)\n", buffer_entry[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dell_new_hk_type)
|
||||
reported_key = (int)buffer_entry[2];
|
||||
else
|
||||
reported_key = (int)buffer_entry[1] & 0xffff;
|
||||
|
||||
key = dell_wmi_get_entry_by_scancode(reported_key);
|
||||
|
||||
if (!key) {
|
||||
printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
|
||||
reported_key);
|
||||
} else if ((key->keycode == KEY_BRIGHTNESSUP ||
|
||||
key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) {
|
||||
/* Don't report brightness notifications that will also
|
||||
* come via ACPI */
|
||||
return;
|
||||
} else {
|
||||
input_report_key(dell_wmi_input_dev, key->keycode, 1);
|
||||
input_sync(dell_wmi_input_dev);
|
||||
input_report_key(dell_wmi_input_dev, key->keycode, 0);
|
||||
input_sync(dell_wmi_input_dev);
|
||||
} else if (buffer[1] & 0xFFFF)
|
||||
printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n",
|
||||
buffer[1] & 0xFFFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void setup_new_hk_map(const struct dmi_header *dm)
|
||||
{
|
||||
|
||||
int i;
|
||||
int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry);
|
||||
struct dell_hotkey_table *table =
|
||||
container_of(dm, struct dell_hotkey_table, header);
|
||||
|
||||
dell_new_wmi_keymap = kzalloc((hotkey_num+1) *
|
||||
sizeof(struct key_entry), GFP_KERNEL);
|
||||
|
||||
for (i = 0; i < hotkey_num; i++) {
|
||||
dell_new_wmi_keymap[i].type = KE_KEY;
|
||||
dell_new_wmi_keymap[i].code = table->keymap[i].scancode;
|
||||
dell_new_wmi_keymap[i].keycode =
|
||||
(table->keymap[i].keycode > 255) ? 0 :
|
||||
bios_to_linux_keycode[table->keymap[i].keycode];
|
||||
}
|
||||
|
||||
dell_new_wmi_keymap[i].type = KE_END;
|
||||
dell_new_wmi_keymap[i].code = 0;
|
||||
dell_new_wmi_keymap[i].keycode = 0;
|
||||
|
||||
dell_wmi_keymap = dell_new_wmi_keymap;
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void find_hk_type(const struct dmi_header *dm, void *dummy)
|
||||
{
|
||||
|
||||
if ((dm->type == 0xb2) && (dm->length > 6)) {
|
||||
dell_new_hk_type = true;
|
||||
setup_new_hk_map(dm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static int __init dell_wmi_input_setup(void)
|
||||
{
|
||||
struct key_entry *key;
|
||||
|
@ -226,6 +324,9 @@ static int __init dell_wmi_init(void)
|
|||
int err;
|
||||
|
||||
if (wmi_has_guid(DELL_EVENT_GUID)) {
|
||||
|
||||
dmi_walk(find_hk_type, NULL);
|
||||
|
||||
err = dell_wmi_input_setup();
|
||||
|
||||
if (err)
|
||||
|
@ -240,6 +341,8 @@ static int __init dell_wmi_init(void)
|
|||
return err;
|
||||
}
|
||||
|
||||
acpi_video = acpi_video_backlight_support();
|
||||
|
||||
} else
|
||||
printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n");
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -51,6 +51,12 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
|
|||
#define HPWMI_WIRELESS_QUERY 0x5
|
||||
#define HPWMI_HOTKEY_QUERY 0xc
|
||||
|
||||
enum hp_wmi_radio {
|
||||
HPWMI_WIFI = 0,
|
||||
HPWMI_BLUETOOTH = 1,
|
||||
HPWMI_WWAN = 2,
|
||||
};
|
||||
|
||||
static int __init hp_wmi_bios_setup(struct platform_device *device);
|
||||
static int __exit hp_wmi_bios_remove(struct platform_device *device);
|
||||
static int hp_wmi_resume_handler(struct device *device);
|
||||
|
@ -175,8 +181,8 @@ static int hp_wmi_tablet_state(void)
|
|||
|
||||
static int hp_wmi_set_block(void *data, bool blocked)
|
||||
{
|
||||
unsigned long b = (unsigned long) data;
|
||||
int query = BIT(b + 8) | ((!blocked) << b);
|
||||
enum hp_wmi_radio r = (enum hp_wmi_radio) data;
|
||||
int query = BIT(r + 8) | ((!blocked) << r);
|
||||
|
||||
return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query);
|
||||
}
|
||||
|
@ -185,31 +191,23 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = {
|
|||
.set_block = hp_wmi_set_block,
|
||||
};
|
||||
|
||||
static bool hp_wmi_wifi_state(void)
|
||||
static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
|
||||
{
|
||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||
int mask = 0x200 << (r * 8);
|
||||
|
||||
if (wireless & 0x100)
|
||||
if (wireless & mask)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hp_wmi_bluetooth_state(void)
|
||||
static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
|
||||
{
|
||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||
int mask = 0x800 << (r * 8);
|
||||
|
||||
if (wireless & 0x10000)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hp_wmi_wwan_state(void)
|
||||
{
|
||||
int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0);
|
||||
|
||||
if (wireless & 0x1000000)
|
||||
if (wireless & mask)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
|
@ -334,49 +332,55 @@ static void hp_wmi_notify(u32 value, void *context)
|
|||
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
static struct key_entry *key;
|
||||
union acpi_object *obj;
|
||||
int eventcode;
|
||||
|
||||
wmi_get_event_data(value, &response);
|
||||
|
||||
obj = (union acpi_object *)response.pointer;
|
||||
|
||||
if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) {
|
||||
int eventcode = *((u8 *) obj->buffer.pointer);
|
||||
if (eventcode == 0x4)
|
||||
eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
|
||||
0);
|
||||
key = hp_wmi_get_entry_by_scancode(eventcode);
|
||||
if (key) {
|
||||
switch (key->type) {
|
||||
case KE_KEY:
|
||||
input_report_key(hp_wmi_input_dev,
|
||||
key->keycode, 1);
|
||||
input_sync(hp_wmi_input_dev);
|
||||
input_report_key(hp_wmi_input_dev,
|
||||
key->keycode, 0);
|
||||
input_sync(hp_wmi_input_dev);
|
||||
break;
|
||||
}
|
||||
} else if (eventcode == 0x1) {
|
||||
input_report_switch(hp_wmi_input_dev, SW_DOCK,
|
||||
hp_wmi_dock_state());
|
||||
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
|
||||
hp_wmi_tablet_state());
|
||||
input_sync(hp_wmi_input_dev);
|
||||
} else if (eventcode == 0x5) {
|
||||
if (wifi_rfkill)
|
||||
rfkill_set_sw_state(wifi_rfkill,
|
||||
hp_wmi_wifi_state());
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_set_sw_state(bluetooth_rfkill,
|
||||
hp_wmi_bluetooth_state());
|
||||
if (wwan_rfkill)
|
||||
rfkill_set_sw_state(wwan_rfkill,
|
||||
hp_wmi_wwan_state());
|
||||
} else
|
||||
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
|
||||
eventcode);
|
||||
} else
|
||||
if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) {
|
||||
printk(KERN_INFO "HP WMI: Unknown response received\n");
|
||||
return;
|
||||
}
|
||||
|
||||
eventcode = *((u8 *) obj->buffer.pointer);
|
||||
if (eventcode == 0x4)
|
||||
eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
|
||||
0);
|
||||
key = hp_wmi_get_entry_by_scancode(eventcode);
|
||||
if (key) {
|
||||
switch (key->type) {
|
||||
case KE_KEY:
|
||||
input_report_key(hp_wmi_input_dev,
|
||||
key->keycode, 1);
|
||||
input_sync(hp_wmi_input_dev);
|
||||
input_report_key(hp_wmi_input_dev,
|
||||
key->keycode, 0);
|
||||
input_sync(hp_wmi_input_dev);
|
||||
break;
|
||||
}
|
||||
} else if (eventcode == 0x1) {
|
||||
input_report_switch(hp_wmi_input_dev, SW_DOCK,
|
||||
hp_wmi_dock_state());
|
||||
input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
|
||||
hp_wmi_tablet_state());
|
||||
input_sync(hp_wmi_input_dev);
|
||||
} else if (eventcode == 0x5) {
|
||||
if (wifi_rfkill)
|
||||
rfkill_set_states(wifi_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WIFI),
|
||||
hp_wmi_get_hw_state(HPWMI_WIFI));
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_set_states(bluetooth_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
|
||||
hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
|
||||
if (wwan_rfkill)
|
||||
rfkill_set_states(wwan_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WWAN),
|
||||
hp_wmi_get_hw_state(HPWMI_WWAN));
|
||||
} else
|
||||
printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n",
|
||||
eventcode);
|
||||
}
|
||||
|
||||
static int __init hp_wmi_input_setup(void)
|
||||
|
@ -455,7 +459,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
|||
wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
|
||||
RFKILL_TYPE_WLAN,
|
||||
&hp_wmi_rfkill_ops,
|
||||
(void *) 0);
|
||||
(void *) HPWMI_WIFI);
|
||||
rfkill_init_sw_state(wifi_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WIFI));
|
||||
rfkill_set_hw_state(wifi_rfkill,
|
||||
hp_wmi_get_hw_state(HPWMI_WIFI));
|
||||
err = rfkill_register(wifi_rfkill);
|
||||
if (err)
|
||||
goto register_wifi_error;
|
||||
|
@ -465,7 +473,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
|||
bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
|
||||
RFKILL_TYPE_BLUETOOTH,
|
||||
&hp_wmi_rfkill_ops,
|
||||
(void *) 1);
|
||||
(void *) HPWMI_BLUETOOTH);
|
||||
rfkill_init_sw_state(bluetooth_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
|
||||
rfkill_set_hw_state(bluetooth_rfkill,
|
||||
hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
|
||||
err = rfkill_register(bluetooth_rfkill);
|
||||
if (err)
|
||||
goto register_bluetooth_error;
|
||||
|
@ -475,7 +487,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
|||
wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
|
||||
RFKILL_TYPE_WWAN,
|
||||
&hp_wmi_rfkill_ops,
|
||||
(void *) 2);
|
||||
(void *) HPWMI_WWAN);
|
||||
rfkill_init_sw_state(wwan_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WWAN));
|
||||
rfkill_set_hw_state(wwan_rfkill,
|
||||
hp_wmi_get_hw_state(HPWMI_WWAN));
|
||||
err = rfkill_register(wwan_rfkill);
|
||||
if (err)
|
||||
goto register_wwan_err;
|
||||
|
@ -533,6 +549,19 @@ static int hp_wmi_resume_handler(struct device *device)
|
|||
input_sync(hp_wmi_input_dev);
|
||||
}
|
||||
|
||||
if (wifi_rfkill)
|
||||
rfkill_set_states(wifi_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WIFI),
|
||||
hp_wmi_get_hw_state(HPWMI_WIFI));
|
||||
if (bluetooth_rfkill)
|
||||
rfkill_set_states(bluetooth_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
|
||||
hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
|
||||
if (wwan_rfkill)
|
||||
rfkill_set_states(wwan_rfkill,
|
||||
hp_wmi_get_sw_state(HPWMI_WWAN),
|
||||
hp_wmi_get_hw_state(HPWMI_WWAN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
293
drivers/platform/x86/msi-wmi.c
Normal file
293
drivers/platform/x86/msi-wmi.c
Normal file
|
@ -0,0 +1,293 @@
|
|||
/*
|
||||
* MSI WMI hotkeys
|
||||
*
|
||||
* Copyright (C) 2009 Novell <trenn@suse.de>
|
||||
*
|
||||
* Most stuff taken over from hp-wmi
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/input/sparse-keymap.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/backlight.h>
|
||||
|
||||
MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>");
|
||||
MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45");
|
||||
MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2");
|
||||
|
||||
/* Temporary workaround until the WMI sysfs interface goes in
|
||||
{ "svn", DMI_SYS_VENDOR },
|
||||
{ "pn", DMI_PRODUCT_NAME },
|
||||
{ "pvr", DMI_PRODUCT_VERSION },
|
||||
{ "rvn", DMI_BOARD_VENDOR },
|
||||
{ "rn", DMI_BOARD_NAME },
|
||||
*/
|
||||
|
||||
MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-6638:*");
|
||||
|
||||
#define DRV_NAME "msi-wmi"
|
||||
#define DRV_PFX DRV_NAME ": "
|
||||
|
||||
#define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45"
|
||||
#define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"
|
||||
|
||||
#define dprintk(msg...) pr_debug(DRV_PFX msg)
|
||||
|
||||
#define KEYCODE_BASE 0xD0
|
||||
#define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE
|
||||
#define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1)
|
||||
#define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2)
|
||||
#define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3)
|
||||
static struct key_entry msi_wmi_keymap[] = {
|
||||
{ KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} },
|
||||
{ KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} },
|
||||
{ KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} },
|
||||
{ KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} },
|
||||
{ KE_END, 0}
|
||||
};
|
||||
static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1];
|
||||
|
||||
struct backlight_device *backlight;
|
||||
|
||||
static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF };
|
||||
|
||||
static struct input_dev *msi_wmi_input_dev;
|
||||
|
||||
static int msi_wmi_query_block(int instance, int *ret)
|
||||
{
|
||||
acpi_status status;
|
||||
union acpi_object *obj;
|
||||
|
||||
struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
||||
status = wmi_query_block(MSIWMI_BIOS_GUID, instance, &output);
|
||||
|
||||
obj = output.pointer;
|
||||
|
||||
if (!obj || obj->type != ACPI_TYPE_INTEGER) {
|
||||
if (obj) {
|
||||
printk(KERN_ERR DRV_PFX "query block returned object "
|
||||
"type: %d - buffer length:%d\n", obj->type,
|
||||
obj->type == ACPI_TYPE_BUFFER ?
|
||||
obj->buffer.length : 0);
|
||||
}
|
||||
kfree(obj);
|
||||
return -EINVAL;
|
||||
}
|
||||
*ret = obj->integer.value;
|
||||
kfree(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int msi_wmi_set_block(int instance, int value)
|
||||
{
|
||||
acpi_status status;
|
||||
|
||||
struct acpi_buffer input = { sizeof(int), &value };
|
||||
|
||||
dprintk("Going to set block of instance: %d - value: %d\n",
|
||||
instance, value);
|
||||
|
||||
status = wmi_set_block(MSIWMI_BIOS_GUID, instance, &input);
|
||||
|
||||
return ACPI_SUCCESS(status) ? 0 : 1;
|
||||
}
|
||||
|
||||
static int bl_get(struct backlight_device *bd)
|
||||
{
|
||||
int level, err, ret;
|
||||
|
||||
/* Instance 1 is "get backlight", cmp with DSDT */
|
||||
err = msi_wmi_query_block(1, &ret);
|
||||
if (err) {
|
||||
printk(KERN_ERR DRV_PFX "Could not query backlight: %d\n", err);
|
||||
return -EINVAL;
|
||||
}
|
||||
dprintk("Get: Query block returned: %d\n", ret);
|
||||
for (level = 0; level < ARRAY_SIZE(backlight_map); level++) {
|
||||
if (backlight_map[level] == ret) {
|
||||
dprintk("Current backlight level: 0x%X - index: %d\n",
|
||||
backlight_map[level], level);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (level == ARRAY_SIZE(backlight_map)) {
|
||||
printk(KERN_ERR DRV_PFX "get: Invalid brightness value: 0x%X\n",
|
||||
ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
return level;
|
||||
}
|
||||
|
||||
static int bl_set_status(struct backlight_device *bd)
|
||||
{
|
||||
int bright = bd->props.brightness;
|
||||
if (bright >= ARRAY_SIZE(backlight_map) || bright < 0)
|
||||
return -EINVAL;
|
||||
|
||||
/* Instance 0 is "set backlight" */
|
||||
return msi_wmi_set_block(0, backlight_map[bright]);
|
||||
}
|
||||
|
||||
static struct backlight_ops msi_backlight_ops = {
|
||||
.get_brightness = bl_get,
|
||||
.update_status = bl_set_status,
|
||||
};
|
||||
|
||||
static void msi_wmi_notify(u32 value, void *context)
|
||||
{
|
||||
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
static struct key_entry *key;
|
||||
union acpi_object *obj;
|
||||
ktime_t cur;
|
||||
|
||||
wmi_get_event_data(value, &response);
|
||||
|
||||
obj = (union acpi_object *)response.pointer;
|
||||
|
||||
if (obj && obj->type == ACPI_TYPE_INTEGER) {
|
||||
int eventcode = obj->integer.value;
|
||||
dprintk("Eventcode: 0x%x\n", eventcode);
|
||||
key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev,
|
||||
eventcode);
|
||||
if (key) {
|
||||
ktime_t diff;
|
||||
cur = ktime_get_real();
|
||||
diff = ktime_sub(cur, last_pressed[key->code -
|
||||
KEYCODE_BASE]);
|
||||
/* Ignore event if the same event happened in a 50 ms
|
||||
timeframe -> Key press may result in 10-20 GPEs */
|
||||
if (ktime_to_us(diff) < 1000 * 50) {
|
||||
dprintk("Suppressed key event 0x%X - "
|
||||
"Last press was %lld us ago\n",
|
||||
key->code, ktime_to_us(diff));
|
||||
return;
|
||||
}
|
||||
last_pressed[key->code - KEYCODE_BASE] = cur;
|
||||
|
||||
if (key->type == KE_KEY &&
|
||||
/* Brightness is served via acpi video driver */
|
||||
(!acpi_video_backlight_support() ||
|
||||
(key->code != MSI_WMI_BRIGHTNESSUP &&
|
||||
key->code != MSI_WMI_BRIGHTNESSDOWN))) {
|
||||
dprintk("Send key: 0x%X - "
|
||||
"Input layer keycode: %d\n", key->code,
|
||||
key->keycode);
|
||||
sparse_keymap_report_entry(msi_wmi_input_dev,
|
||||
key, 1, true);
|
||||
}
|
||||
} else
|
||||
printk(KERN_INFO "Unknown key pressed - %x\n",
|
||||
eventcode);
|
||||
} else
|
||||
printk(KERN_INFO DRV_PFX "Unknown event received\n");
|
||||
kfree(response.pointer);
|
||||
}
|
||||
|
||||
static int __init msi_wmi_input_setup(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
msi_wmi_input_dev = input_allocate_device();
|
||||
if (!msi_wmi_input_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
msi_wmi_input_dev->name = "MSI WMI hotkeys";
|
||||
msi_wmi_input_dev->phys = "wmi/input0";
|
||||
msi_wmi_input_dev->id.bustype = BUS_HOST;
|
||||
|
||||
err = sparse_keymap_setup(msi_wmi_input_dev, msi_wmi_keymap, NULL);
|
||||
if (err)
|
||||
goto err_free_dev;
|
||||
|
||||
err = input_register_device(msi_wmi_input_dev);
|
||||
|
||||
if (err)
|
||||
goto err_free_keymap;
|
||||
|
||||
memset(last_pressed, 0, sizeof(last_pressed));
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_keymap:
|
||||
sparse_keymap_free(msi_wmi_input_dev);
|
||||
err_free_dev:
|
||||
input_free_device(msi_wmi_input_dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init msi_wmi_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!wmi_has_guid(MSIWMI_EVENT_GUID)) {
|
||||
printk(KERN_ERR
|
||||
"This machine doesn't have MSI-hotkeys through WMI\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
err = wmi_install_notify_handler(MSIWMI_EVENT_GUID,
|
||||
msi_wmi_notify, NULL);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
||||
err = msi_wmi_input_setup();
|
||||
if (err)
|
||||
goto err_uninstall_notifier;
|
||||
|
||||
if (!acpi_video_backlight_support()) {
|
||||
backlight = backlight_device_register(DRV_NAME,
|
||||
NULL, NULL, &msi_backlight_ops);
|
||||
if (IS_ERR(backlight))
|
||||
goto err_free_input;
|
||||
|
||||
backlight->props.max_brightness = ARRAY_SIZE(backlight_map) - 1;
|
||||
err = bl_get(NULL);
|
||||
if (err < 0)
|
||||
goto err_free_backlight;
|
||||
|
||||
backlight->props.brightness = err;
|
||||
}
|
||||
dprintk("Event handler installed\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_backlight:
|
||||
backlight_device_unregister(backlight);
|
||||
err_free_input:
|
||||
input_unregister_device(msi_wmi_input_dev);
|
||||
err_uninstall_notifier:
|
||||
wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit msi_wmi_exit(void)
|
||||
{
|
||||
if (wmi_has_guid(MSIWMI_EVENT_GUID)) {
|
||||
wmi_remove_notify_handler(MSIWMI_EVENT_GUID);
|
||||
sparse_keymap_free(msi_wmi_input_dev);
|
||||
input_unregister_device(msi_wmi_input_dev);
|
||||
backlight_device_unregister(backlight);
|
||||
}
|
||||
}
|
||||
|
||||
module_init(msi_wmi_init);
|
||||
module_exit(msi_wmi_exit);
|
File diff suppressed because it is too large
Load diff
144
drivers/platform/x86/toshiba_bluetooth.c
Normal file
144
drivers/platform/x86/toshiba_bluetooth.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* Toshiba Bluetooth Enable Driver
|
||||
*
|
||||
* Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com>
|
||||
*
|
||||
* Thanks to Matthew Garrett for background info on ACPI innards which
|
||||
* normal people aren't meant to understand :-)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Note the Toshiba Bluetooth RFKill switch seems to be a strange
|
||||
* fish. It only provides a BT event when the switch is flipped to
|
||||
* the 'on' position. When flipping it to 'off', the USB device is
|
||||
* simply pulled away underneath us, without any BT event being
|
||||
* delivered.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
#include <acpi/acpi_drivers.h>
|
||||
|
||||
MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>");
|
||||
MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
|
||||
static int toshiba_bt_rfkill_add(struct acpi_device *device);
|
||||
static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type);
|
||||
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event);
|
||||
static int toshiba_bt_resume(struct acpi_device *device);
|
||||
|
||||
static const struct acpi_device_id bt_device_ids[] = {
|
||||
{ "TOS6205", 0},
|
||||
{ "", 0},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bt_device_ids);
|
||||
|
||||
static struct acpi_driver toshiba_bt_rfkill_driver = {
|
||||
.name = "Toshiba BT",
|
||||
.class = "Toshiba",
|
||||
.ids = bt_device_ids,
|
||||
.ops = {
|
||||
.add = toshiba_bt_rfkill_add,
|
||||
.remove = toshiba_bt_rfkill_remove,
|
||||
.notify = toshiba_bt_rfkill_notify,
|
||||
.resume = toshiba_bt_resume,
|
||||
},
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int toshiba_bluetooth_enable(acpi_handle handle)
|
||||
{
|
||||
acpi_status res1, res2;
|
||||
acpi_integer result;
|
||||
|
||||
/*
|
||||
* Query ACPI to verify RFKill switch is set to 'on'.
|
||||
* If not, we return silently, no need to report it as
|
||||
* an error.
|
||||
*/
|
||||
res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result);
|
||||
if (ACPI_FAILURE(res1))
|
||||
return res1;
|
||||
if (!(result & 0x01))
|
||||
return 0;
|
||||
|
||||
printk(KERN_INFO "toshiba_bluetooth: Re-enabling Toshiba Bluetooth\n");
|
||||
res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL);
|
||||
res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL);
|
||||
if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2))
|
||||
return 0;
|
||||
|
||||
printk(KERN_WARNING "toshiba_bluetooth: Failed to re-enable "
|
||||
"Toshiba Bluetooth\n");
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event)
|
||||
{
|
||||
toshiba_bluetooth_enable(device->handle);
|
||||
}
|
||||
|
||||
static int toshiba_bt_resume(struct acpi_device *device)
|
||||
{
|
||||
return toshiba_bluetooth_enable(device->handle);
|
||||
}
|
||||
|
||||
static int toshiba_bt_rfkill_add(struct acpi_device *device)
|
||||
{
|
||||
acpi_status status;
|
||||
acpi_integer bt_present;
|
||||
int result = -ENODEV;
|
||||
|
||||
/*
|
||||
* Some Toshiba laptops may have a fake TOS6205 device in
|
||||
* their ACPI BIOS, so query the _STA method to see if there
|
||||
* is really anything there, before trying to enable it.
|
||||
*/
|
||||
status = acpi_evaluate_integer(device->handle, "_STA", NULL,
|
||||
&bt_present);
|
||||
|
||||
if (!ACPI_FAILURE(status) && bt_present) {
|
||||
printk(KERN_INFO "Detected Toshiba ACPI Bluetooth device - "
|
||||
"installing RFKill handler\n");
|
||||
result = toshiba_bluetooth_enable(device->handle);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static int __init toshiba_bt_rfkill_init(void)
|
||||
{
|
||||
int result;
|
||||
|
||||
result = acpi_bus_register_driver(&toshiba_bt_rfkill_driver);
|
||||
if (result < 0) {
|
||||
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
|
||||
"Error registering driver\n"));
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
/* clean up */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit toshiba_bt_rfkill_exit(void)
|
||||
{
|
||||
acpi_bus_unregister_driver(&toshiba_bt_rfkill_driver);
|
||||
}
|
||||
|
||||
module_init(toshiba_bt_rfkill_init);
|
||||
module_exit(toshiba_bt_rfkill_exit);
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <acpi/acpi_bus.h>
|
||||
|
@ -65,6 +66,7 @@ struct wmi_block {
|
|||
acpi_handle handle;
|
||||
wmi_notify_handler handler;
|
||||
void *handler_data;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
static struct wmi_block wmi_blocks;
|
||||
|
@ -195,6 +197,34 @@ static bool wmi_parse_guid(const u8 *src, u8 *dest)
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a raw GUID to the ACII string representation
|
||||
*/
|
||||
static int wmi_gtoa(const char *in, char *out)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 3; i >= 0; i--)
|
||||
out += sprintf(out, "%02X", in[i] & 0xFF);
|
||||
|
||||
out += sprintf(out, "-");
|
||||
out += sprintf(out, "%02X", in[5] & 0xFF);
|
||||
out += sprintf(out, "%02X", in[4] & 0xFF);
|
||||
out += sprintf(out, "-");
|
||||
out += sprintf(out, "%02X", in[7] & 0xFF);
|
||||
out += sprintf(out, "%02X", in[6] & 0xFF);
|
||||
out += sprintf(out, "-");
|
||||
out += sprintf(out, "%02X", in[8] & 0xFF);
|
||||
out += sprintf(out, "%02X", in[9] & 0xFF);
|
||||
out += sprintf(out, "-");
|
||||
|
||||
for (i = 10; i <= 15; i++)
|
||||
out += sprintf(out, "%02X", in[i] & 0xFF);
|
||||
|
||||
out = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool find_guid(const char *guid_string, struct wmi_block **out)
|
||||
{
|
||||
char tmp[16], guid_input[16];
|
||||
|
@ -554,6 +584,138 @@ bool wmi_has_guid(const char *guid_string)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(wmi_has_guid);
|
||||
|
||||
/*
|
||||
* sysfs interface
|
||||
*/
|
||||
static ssize_t show_modalias(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
char guid_string[37];
|
||||
struct wmi_block *wblock;
|
||||
|
||||
wblock = dev_get_drvdata(dev);
|
||||
if (!wblock)
|
||||
return -ENOMEM;
|
||||
|
||||
wmi_gtoa(wblock->gblock.guid, guid_string);
|
||||
|
||||
return sprintf(buf, "wmi:%s\n", guid_string);
|
||||
}
|
||||
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
|
||||
|
||||
static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
char guid_string[37];
|
||||
|
||||
struct wmi_block *wblock;
|
||||
|
||||
if (add_uevent_var(env, "MODALIAS="))
|
||||
return -ENOMEM;
|
||||
|
||||
wblock = dev_get_drvdata(dev);
|
||||
if (!wblock)
|
||||
return -ENOMEM;
|
||||
|
||||
wmi_gtoa(wblock->gblock.guid, guid_string);
|
||||
|
||||
strcpy(&env->buf[env->buflen - 1], "wmi:");
|
||||
memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36);
|
||||
env->buflen += 40;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wmi_dev_free(struct device *dev)
|
||||
{
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
static struct class wmi_class = {
|
||||
.name = "wmi",
|
||||
.dev_release = wmi_dev_free,
|
||||
.dev_uevent = wmi_dev_uevent,
|
||||
};
|
||||
|
||||
static int wmi_create_devs(void)
|
||||
{
|
||||
int result;
|
||||
char guid_string[37];
|
||||
struct guid_block *gblock;
|
||||
struct wmi_block *wblock;
|
||||
struct list_head *p;
|
||||
struct device *guid_dev;
|
||||
|
||||
/* Create devices for all the GUIDs */
|
||||
list_for_each(p, &wmi_blocks.list) {
|
||||
wblock = list_entry(p, struct wmi_block, list);
|
||||
|
||||
guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL);
|
||||
if (!guid_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
wblock->dev = guid_dev;
|
||||
|
||||
guid_dev->class = &wmi_class;
|
||||
dev_set_drvdata(guid_dev, wblock);
|
||||
|
||||
gblock = &wblock->gblock;
|
||||
|
||||
wmi_gtoa(gblock->guid, guid_string);
|
||||
dev_set_name(guid_dev, guid_string);
|
||||
|
||||
result = device_register(guid_dev);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
result = device_create_file(guid_dev, &dev_attr_modalias);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void wmi_remove_devs(void)
|
||||
{
|
||||
struct guid_block *gblock;
|
||||
struct wmi_block *wblock;
|
||||
struct list_head *p;
|
||||
struct device *guid_dev;
|
||||
|
||||
/* Delete devices for all the GUIDs */
|
||||
list_for_each(p, &wmi_blocks.list) {
|
||||
wblock = list_entry(p, struct wmi_block, list);
|
||||
|
||||
guid_dev = wblock->dev;
|
||||
gblock = &wblock->gblock;
|
||||
|
||||
device_remove_file(guid_dev, &dev_attr_modalias);
|
||||
|
||||
device_unregister(guid_dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void wmi_class_exit(void)
|
||||
{
|
||||
wmi_remove_devs();
|
||||
class_unregister(&wmi_class);
|
||||
}
|
||||
|
||||
static int wmi_class_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = class_register(&wmi_class);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = wmi_create_devs();
|
||||
if (ret)
|
||||
wmi_class_exit();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Parse the _WDG method for the GUID data blocks
|
||||
*/
|
||||
|
@ -709,10 +871,17 @@ static int __init acpi_wmi_init(void)
|
|||
|
||||
if (result < 0) {
|
||||
printk(KERN_INFO PREFIX "Error loading mapper\n");
|
||||
} else {
|
||||
printk(KERN_INFO PREFIX "Mapper loaded\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
result = wmi_class_init();
|
||||
if (result) {
|
||||
acpi_bus_unregister_driver(&acpi_wmi_driver);
|
||||
return result;
|
||||
}
|
||||
|
||||
printk(KERN_INFO PREFIX "Mapper loaded\n");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -721,6 +890,8 @@ static void __exit acpi_wmi_exit(void)
|
|||
struct list_head *p, *tmp;
|
||||
struct wmi_block *wblock;
|
||||
|
||||
wmi_class_exit();
|
||||
|
||||
acpi_bus_unregister_driver(&acpi_wmi_driver);
|
||||
|
||||
list_for_each_safe(p, tmp, &wmi_blocks.list) {
|
||||
|
|
|
@ -80,7 +80,8 @@ static int pnpacpi_get_resources(struct pnp_dev *dev)
|
|||
|
||||
static int pnpacpi_set_resources(struct pnp_dev *dev)
|
||||
{
|
||||
acpi_handle handle = dev->data;
|
||||
struct acpi_device *acpi_dev = dev->data;
|
||||
acpi_handle handle = acpi_dev->handle;
|
||||
struct acpi_buffer buffer;
|
||||
int ret;
|
||||
|
||||
|
@ -103,7 +104,8 @@ static int pnpacpi_set_resources(struct pnp_dev *dev)
|
|||
|
||||
static int pnpacpi_disable_resources(struct pnp_dev *dev)
|
||||
{
|
||||
acpi_handle handle = dev->data;
|
||||
struct acpi_device *acpi_dev = dev->data;
|
||||
acpi_handle handle = acpi_dev->handle;
|
||||
int ret;
|
||||
|
||||
dev_dbg(&dev->dev, "disable resources\n");
|
||||
|
@ -121,6 +123,8 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev)
|
|||
#ifdef CONFIG_ACPI_SLEEP
|
||||
static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
|
||||
{
|
||||
struct acpi_device *acpi_dev = dev->data;
|
||||
acpi_handle handle = acpi_dev->handle;
|
||||
int power_state;
|
||||
|
||||
power_state = acpi_pm_device_sleep_state(&dev->dev, NULL);
|
||||
|
@ -128,16 +132,19 @@ static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state)
|
|||
power_state = (state.event == PM_EVENT_ON) ?
|
||||
ACPI_STATE_D0 : ACPI_STATE_D3;
|
||||
|
||||
return acpi_bus_set_power((acpi_handle) dev->data, power_state);
|
||||
return acpi_bus_set_power(handle, power_state);
|
||||
}
|
||||
|
||||
static int pnpacpi_resume(struct pnp_dev *dev)
|
||||
{
|
||||
return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0);
|
||||
struct acpi_device *acpi_dev = dev->data;
|
||||
acpi_handle handle = acpi_dev->handle;
|
||||
|
||||
return acpi_bus_set_power(handle, ACPI_STATE_D0);
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct pnp_protocol pnpacpi_protocol = {
|
||||
struct pnp_protocol pnpacpi_protocol = {
|
||||
.name = "Plug and Play ACPI",
|
||||
.get = pnpacpi_get_resources,
|
||||
.set = pnpacpi_set_resources,
|
||||
|
@ -147,6 +154,7 @@ static struct pnp_protocol pnpacpi_protocol = {
|
|||
.resume = pnpacpi_resume,
|
||||
#endif
|
||||
};
|
||||
EXPORT_SYMBOL(pnpacpi_protocol);
|
||||
|
||||
static int __init pnpacpi_add_device(struct acpi_device *device)
|
||||
{
|
||||
|
@ -168,7 +176,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device)
|
|||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
dev->data = device->handle;
|
||||
dev->data = device;
|
||||
/* .enabled means the device can decode the resources */
|
||||
dev->active = device->status.enabled;
|
||||
status = acpi_get_handle(device->handle, "_SRS", &temp);
|
||||
|
|
|
@ -465,7 +465,8 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
|
|||
|
||||
int pnpacpi_parse_allocated_resource(struct pnp_dev *dev)
|
||||
{
|
||||
acpi_handle handle = dev->data;
|
||||
struct acpi_device *acpi_dev = dev->data;
|
||||
acpi_handle handle = acpi_dev->handle;
|
||||
acpi_status status;
|
||||
|
||||
pnp_dbg(&dev->dev, "parse allocated resources\n");
|
||||
|
@ -773,7 +774,8 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res,
|
|||
|
||||
int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev)
|
||||
{
|
||||
acpi_handle handle = dev->data;
|
||||
struct acpi_device *acpi_dev = dev->data;
|
||||
acpi_handle handle = acpi_dev->handle;
|
||||
acpi_status status;
|
||||
struct acpipnp_parse_option_s parse_data;
|
||||
|
||||
|
@ -845,7 +847,8 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data)
|
|||
int pnpacpi_build_resource_template(struct pnp_dev *dev,
|
||||
struct acpi_buffer *buffer)
|
||||
{
|
||||
acpi_handle handle = dev->data;
|
||||
struct acpi_device *acpi_dev = dev->data;
|
||||
acpi_handle handle = acpi_dev->handle;
|
||||
struct acpi_resource *resource;
|
||||
int res_cnt = 0;
|
||||
acpi_status status;
|
||||
|
|
|
@ -225,6 +225,12 @@ passive_store(struct device *dev, struct device_attribute *attr,
|
|||
if (!sscanf(buf, "%d\n", &state))
|
||||
return -EINVAL;
|
||||
|
||||
/* sanity check: values below 1000 millicelcius don't make sense
|
||||
* and can cause the system to go into a thermal heart attack
|
||||
*/
|
||||
if (state && state < 1000)
|
||||
return -EINVAL;
|
||||
|
||||
if (state && !tz->forced_passive) {
|
||||
mutex_lock(&thermal_list_lock);
|
||||
list_for_each_entry(cdev, &thermal_cdev_list, node) {
|
||||
|
@ -235,6 +241,8 @@ passive_store(struct device *dev, struct device_attribute *attr,
|
|||
cdev);
|
||||
}
|
||||
mutex_unlock(&thermal_list_lock);
|
||||
if (!tz->passive_delay)
|
||||
tz->passive_delay = 1000;
|
||||
} else if (!state && tz->forced_passive) {
|
||||
mutex_lock(&thermal_list_lock);
|
||||
list_for_each_entry(cdev, &thermal_cdev_list, node) {
|
||||
|
@ -245,17 +253,12 @@ passive_store(struct device *dev, struct device_attribute *attr,
|
|||
cdev);
|
||||
}
|
||||
mutex_unlock(&thermal_list_lock);
|
||||
tz->passive_delay = 0;
|
||||
}
|
||||
|
||||
tz->tc1 = 1;
|
||||
tz->tc2 = 1;
|
||||
|
||||
if (!tz->passive_delay)
|
||||
tz->passive_delay = 1000;
|
||||
|
||||
if (!tz->polling_delay)
|
||||
tz->polling_delay = 10000;
|
||||
|
||||
tz->forced_passive = state;
|
||||
|
||||
thermal_zone_device_update(tz);
|
||||
|
@ -374,7 +377,7 @@ thermal_cooling_device_cur_state_store(struct device *dev,
|
|||
if (!sscanf(buf, "%ld\n", &state))
|
||||
return -EINVAL;
|
||||
|
||||
if (state < 0)
|
||||
if ((long)state < 0)
|
||||
return -EINVAL;
|
||||
|
||||
result = cdev->ops->set_cur_state(cdev, state);
|
||||
|
@ -1016,6 +1019,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
|
|||
thermal_zone_device_set_polling(tz, tz->passive_delay);
|
||||
else if (tz->polling_delay)
|
||||
thermal_zone_device_set_polling(tz, tz->polling_delay);
|
||||
else
|
||||
thermal_zone_device_set_polling(tz, 0);
|
||||
mutex_unlock(&tz->lock);
|
||||
}
|
||||
EXPORT_SYMBOL(thermal_zone_device_update);
|
||||
|
|
|
@ -85,7 +85,8 @@
|
|||
#define ACPI_LV_INIT 0x00000001
|
||||
#define ACPI_LV_DEBUG_OBJECT 0x00000002
|
||||
#define ACPI_LV_INFO 0x00000004
|
||||
#define ACPI_LV_ALL_EXCEPTIONS 0x00000007
|
||||
#define ACPI_LV_REPAIR 0x00000008
|
||||
#define ACPI_LV_ALL_EXCEPTIONS 0x0000000F
|
||||
|
||||
/* Trace verbosity level 1 [Standard Trace Level] */
|
||||
|
||||
|
@ -143,6 +144,7 @@
|
|||
#define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT)
|
||||
#define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT)
|
||||
#define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO)
|
||||
#define ACPI_DB_REPAIR ACPI_DEBUG_LEVEL (ACPI_LV_REPAIR)
|
||||
#define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS)
|
||||
|
||||
/* Trace level -- also used in the global "DebugLevel" */
|
||||
|
@ -174,8 +176,8 @@
|
|||
|
||||
/* Defaults for debug_level, debug and normal */
|
||||
|
||||
#define ACPI_DEBUG_DEFAULT (ACPI_LV_INFO)
|
||||
#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT)
|
||||
#define ACPI_DEBUG_DEFAULT (ACPI_LV_INFO | ACPI_LV_REPAIR)
|
||||
#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR)
|
||||
#define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL)
|
||||
|
||||
#if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES)
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
/* Current ACPICA subsystem version in YYYYMMDD format */
|
||||
|
||||
#define ACPI_CA_VERSION 0x20091112
|
||||
#define ACPI_CA_VERSION 0x20091214
|
||||
|
||||
#include "actypes.h"
|
||||
#include "actbl.h"
|
||||
|
|
|
@ -294,7 +294,7 @@ static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx
|
|||
#ifdef CONFIG_CPU_FREQ
|
||||
void acpi_processor_ppc_init(void);
|
||||
void acpi_processor_ppc_exit(void);
|
||||
int acpi_processor_ppc_has_changed(struct acpi_processor *pr);
|
||||
int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag);
|
||||
extern int acpi_processor_get_bios_limit(int cpu, unsigned int *limit);
|
||||
#else
|
||||
static inline void acpi_processor_ppc_init(void)
|
||||
|
@ -305,7 +305,8 @@ static inline void acpi_processor_ppc_exit(void)
|
|||
{
|
||||
return;
|
||||
}
|
||||
static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr)
|
||||
static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr,
|
||||
int event_flag)
|
||||
{
|
||||
static unsigned int printout = 1;
|
||||
if (printout) {
|
||||
|
|
|
@ -240,7 +240,7 @@ extern int pnpacpi_disabled;
|
|||
#define PXM_INVAL (-1)
|
||||
#define NID_INVAL (-1)
|
||||
|
||||
int acpi_check_resource_conflict(struct resource *res);
|
||||
int acpi_check_resource_conflict(const struct resource *res);
|
||||
|
||||
int acpi_check_region(resource_size_t start, resource_size_t n,
|
||||
const char *name);
|
||||
|
@ -253,10 +253,16 @@ void __init acpi_old_suspend_ordering(void);
|
|||
void __init acpi_s4_no_nvs(void);
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
struct acpi_osc_context {
|
||||
char *uuid_str; /* uuid string */
|
||||
int rev;
|
||||
struct acpi_buffer cap; /* arg2/arg3 */
|
||||
struct acpi_buffer ret; /* free by caller if success */
|
||||
};
|
||||
|
||||
#define OSC_QUERY_TYPE 0
|
||||
#define OSC_SUPPORT_TYPE 1
|
||||
#define OSC_CONTROL_TYPE 2
|
||||
#define OSC_SUPPORT_MASKS 0x1f
|
||||
|
||||
/* _OSC DW0 Definition */
|
||||
#define OSC_QUERY_ENABLE 1
|
||||
|
@ -265,12 +271,23 @@ void __init acpi_s4_no_nvs(void);
|
|||
#define OSC_INVALID_REVISION_ERROR 8
|
||||
#define OSC_CAPABILITIES_MASK_ERROR 16
|
||||
|
||||
acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
|
||||
|
||||
/* platform-wide _OSC bits */
|
||||
#define OSC_SB_PAD_SUPPORT 1
|
||||
#define OSC_SB_PPC_OST_SUPPORT 2
|
||||
#define OSC_SB_PR3_SUPPORT 4
|
||||
#define OSC_SB_CPUHP_OST_SUPPORT 8
|
||||
#define OSC_SB_APEI_SUPPORT 16
|
||||
|
||||
/* PCI defined _OSC bits */
|
||||
/* _OSC DW1 Definition (OS Support Fields) */
|
||||
#define OSC_EXT_PCI_CONFIG_SUPPORT 1
|
||||
#define OSC_ACTIVE_STATE_PWR_SUPPORT 2
|
||||
#define OSC_CLOCK_PWR_CAPABILITY_SUPPORT 4
|
||||
#define OSC_PCI_SEGMENT_GROUPS_SUPPORT 8
|
||||
#define OSC_MSI_SUPPORT 16
|
||||
#define OSC_PCI_SUPPORT_MASKS 0x1f
|
||||
|
||||
/* _OSC DW1 Definition (OS Control Fields) */
|
||||
#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 1
|
||||
|
@ -279,7 +296,7 @@ void __init acpi_s4_no_nvs(void);
|
|||
#define OSC_PCI_EXPRESS_AER_CONTROL 8
|
||||
#define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL 16
|
||||
|
||||
#define OSC_CONTROL_MASKS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \
|
||||
#define OSC_PCI_CONTROL_MASKS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \
|
||||
OSC_SHPC_NATIVE_HP_CONTROL | \
|
||||
OSC_PCI_EXPRESS_PME_CONTROL | \
|
||||
OSC_PCI_EXPRESS_AER_CONTROL | \
|
||||
|
|
|
@ -334,6 +334,19 @@ extern struct pnp_protocol pnpbios_protocol;
|
|||
#define pnp_device_is_pnpbios(dev) 0
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PNPACPI
|
||||
extern struct pnp_protocol pnpacpi_protocol;
|
||||
|
||||
static inline struct acpi_device *pnp_acpi_device(struct pnp_dev *dev)
|
||||
{
|
||||
if (dev->protocol == &pnpacpi_protocol)
|
||||
return dev->data;
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
#define pnp_acpi_device(dev) 0
|
||||
#endif
|
||||
|
||||
/* status */
|
||||
#define PNP_READY 0x0000
|
||||
#define PNP_ATTACHED 0x0001
|
||||
|
|
Loading…
Reference in a new issue