diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 15:33:19 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-12-16 15:33:19 -0500 |
| commit | 288f02bbb6e9609cbaf1eb7a9cb97ae45ce090b2 (patch) | |
| tree | 4f5e5c9fe6638bdbd246379f64b3541de68f329a | |
| parent | 8aedf8a6ae98d5d4df3254b6afb7e4432d9d8600 (diff) | |
| parent | aa96ce0af8385415a3450bc13e6254a4d6b4a888 (diff) | |
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)
...
66 files changed, 4113 insertions, 1712 deletions
diff --git a/Documentation/acpi/method-customizing.txt b/Documentation/acpi/method-customizing.txt new file mode 100644 index 000000000000..e628cd23ca80 --- /dev/null +++ b/Documentation/acpi/method-customizing.txt | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | Linux ACPI Custom Control Method How To | ||
| 2 | ======================================= | ||
| 3 | |||
| 4 | Written by Zhang Rui <rui.zhang@intel.com> | ||
| 5 | |||
| 6 | |||
| 7 | Linux supports customizing ACPI control methods at runtime. | ||
| 8 | |||
| 9 | Users can use this to | ||
| 10 | 1. override an existing method which may not work correctly, | ||
| 11 | or just for debugging purposes. | ||
| 12 | 2. insert a completely new method in order to create a missing | ||
| 13 | method such as _OFF, _ON, _STA, _INI, etc. | ||
| 14 | For these cases, it is far simpler to dynamically install a single | ||
| 15 | control method rather than override the entire DSDT, because kernel | ||
| 16 | rebuild/reboot is not needed and test result can be got in minutes. | ||
| 17 | |||
| 18 | Note: Only ACPI METHOD can be overridden, any other object types like | ||
| 19 | "Device", "OperationRegion", are not recognized. | ||
| 20 | Note: The same ACPI control method can be overridden for many times, | ||
| 21 | and it's always the latest one that used by Linux/kernel. | ||
| 22 | |||
| 23 | 1. override an existing method | ||
| 24 | a) get the ACPI table via ACPI sysfs I/F. e.g. to get the DSDT, | ||
| 25 | just run "cat /sys/firmware/acpi/tables/DSDT > /tmp/dsdt.dat" | ||
| 26 | b) disassemble the table by running "iasl -d dsdt.dat". | ||
| 27 | c) rewrite the ASL code of the method and save it in a new file, | ||
| 28 | d) package the new file (psr.asl) to an ACPI table format. | ||
| 29 | Here is an example of a customized \_SB._AC._PSR method, | ||
| 30 | |||
| 31 | DefinitionBlock ("", "SSDT", 1, "", "", 0x20080715) | ||
| 32 | { | ||
| 33 | External (ACON) | ||
| 34 | |||
| 35 | Method (\_SB_.AC._PSR, 0, NotSerialized) | ||
| 36 | { | ||
| 37 | Store ("In AC _PSR", Debug) | ||
| 38 | Return (ACON) | ||
| 39 | } | ||
| 40 | } | ||
| 41 | Note that the full pathname of the method in ACPI namespace | ||
| 42 | should be used. | ||
| 43 | And remember to use "External" to declare external objects. | ||
| 44 | e) assemble the file to generate the AML code of the method. | ||
| 45 | e.g. "iasl psr.asl" (psr.aml is generated as a result) | ||
| 46 | f) mount debugfs by "mount -t debugfs none /sys/kernel/debug" | ||
| 47 | g) override the old method via the debugfs by running | ||
| 48 | "cat /tmp/psr.aml > /sys/kernel/debug/acpi/custom_method" | ||
| 49 | |||
| 50 | 2. insert a new method | ||
| 51 | This is easier than overriding an existing method. | ||
| 52 | We just need to create the ASL code of the method we want to | ||
| 53 | insert and then follow the step c) ~ g) in section 1. | ||
| 54 | |||
| 55 | 3. undo your changes | ||
| 56 | The "undo" operation is not supported for a new inserted method | ||
| 57 | right now, i.e. we can not remove a method currently. | ||
| 58 | For an overrided method, in order to undo your changes, please | ||
| 59 | save a copy of the method original ASL code in step c) section 1, | ||
| 60 | and redo step c) ~ g) to override the method with the original one. | ||
| 61 | |||
| 62 | |||
| 63 | Note: We can use a kernel with multiple custom ACPI method running, | ||
| 64 | But each individual write to debugfs can implement a SINGLE | ||
| 65 | method override. i.e. if we want to insert/override multiple | ||
| 66 | ACPI methods, we need to redo step c) ~ g) for multiple times. | ||
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 21ab9357326d..870d190fe617 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt | |||
| @@ -474,3 +474,22 @@ Why: Obsoleted by the adt7475 driver. | |||
| 474 | Who: Jean Delvare <khali@linux-fr.org> | 474 | Who: Jean Delvare <khali@linux-fr.org> |
| 475 | 475 | ||
| 476 | --------------------------- | 476 | --------------------------- |
| 477 | What: Support for lcd_switch and display_get in asus-laptop driver | ||
| 478 | When: March 2010 | ||
| 479 | Why: These two features use non-standard interfaces. There are the | ||
| 480 | only features that really need multiple path to guess what's | ||
| 481 | the right method name on a specific laptop. | ||
| 482 | |||
| 483 | Removing them will allow to remove a lot of code an significantly | ||
| 484 | clean the drivers. | ||
| 485 | |||
| 486 | This will affect the backlight code which won't be able to know | ||
| 487 | if the backlight is on or off. The platform display file will also be | ||
| 488 | write only (like the one in eeepc-laptop). | ||
| 489 | |||
| 490 | This should'nt affect a lot of user because they usually know | ||
| 491 | when their display is on or off. | ||
| 492 | |||
| 493 | Who: Corentin Chary <corentin.chary@gmail.com> | ||
| 494 | |||
| 495 | ---------------------------- | ||
diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index aafcaa634191..169091f75e6d 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | ThinkPad ACPI Extras Driver | 1 | ThinkPad ACPI Extras Driver |
| 2 | 2 | ||
| 3 | Version 0.23 | 3 | Version 0.24 |
| 4 | April 10th, 2009 | 4 | December 11th, 2009 |
| 5 | 5 | ||
| 6 | Borislav Deianov <borislav@users.sf.net> | 6 | Borislav Deianov <borislav@users.sf.net> |
| 7 | Henrique de Moraes Holschuh <hmh@hmh.eng.br> | 7 | Henrique de Moraes Holschuh <hmh@hmh.eng.br> |
| @@ -460,6 +460,8 @@ event code Key Notes | |||
| 460 | For Lenovo ThinkPads with a new | 460 | For Lenovo ThinkPads with a new |
| 461 | BIOS, it has to be handled either | 461 | BIOS, it has to be handled either |
| 462 | by the ACPI OSI, or by userspace. | 462 | by the ACPI OSI, or by userspace. |
| 463 | The driver does the right thing, | ||
| 464 | never mess with this. | ||
| 463 | 0x1011 0x10 FN+END Brightness down. See brightness | 465 | 0x1011 0x10 FN+END Brightness down. See brightness |
| 464 | up for details. | 466 | up for details. |
| 465 | 467 | ||
| @@ -582,46 +584,15 @@ with hotkey_report_mode. | |||
| 582 | 584 | ||
| 583 | Brightness hotkey notes: | 585 | Brightness hotkey notes: |
| 584 | 586 | ||
| 585 | These are the current sane choices for brightness key mapping in | 587 | Don't mess with the brightness hotkeys in a Thinkpad. If you want |
| 586 | thinkpad-acpi: | 588 | notifications for OSD, use the sysfs backlight class event support. |
| 587 | 589 | ||
| 588 | For IBM and Lenovo models *without* ACPI backlight control (the ones on | 590 | The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN events |
| 589 | which thinkpad-acpi will autoload its backlight interface by default, | 591 | automatically for the cases were userspace has to do something to |
| 590 | and on which ACPI video does not export a backlight interface): | 592 | implement brightness changes. When you override these events, you will |
| 591 | 593 | either fail to handle properly the ThinkPads that require explicit | |
| 592 | 1. Don't enable or map the brightness hotkeys in thinkpad-acpi, as | 594 | action to change backlight brightness, or the ThinkPads that require |
| 593 | these older firmware versions unfortunately won't respect the hotkey | 595 | that no action be taken to work properly. |
| 594 | mask for brightness keys anyway, and always reacts to them. This | ||
| 595 | usually work fine, unless X.org drivers are doing something to block | ||
| 596 | the BIOS. In that case, use (3) below. This is the default mode of | ||
| 597 | operation. | ||
| 598 | |||
| 599 | 2. Enable the hotkeys, but map them to something else that is NOT | ||
| 600 | KEY_BRIGHTNESS_UP/DOWN or any other keycode that would cause | ||
| 601 | userspace to try to change the backlight level, and use that as an | ||
| 602 | on-screen-display hint. | ||
| 603 | |||
| 604 | 3. IF AND ONLY IF X.org drivers find a way to block the firmware from | ||
| 605 | automatically changing the brightness, enable the hotkeys and map | ||
| 606 | them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN, and feed that to | ||
| 607 | something that calls xbacklight. thinkpad-acpi will not be able to | ||
| 608 | change brightness in that case either, so you should disable its | ||
| 609 | backlight interface. | ||
| 610 | |||
| 611 | For Lenovo models *with* ACPI backlight control: | ||
| 612 | |||
| 613 | 1. Load up ACPI video and use that. ACPI video will report ACPI | ||
| 614 | events for brightness change keys. Do not mess with thinkpad-acpi | ||
| 615 | defaults in this case. thinkpad-acpi should not have anything to do | ||
| 616 | with backlight events in a scenario where ACPI video is loaded: | ||
| 617 | brightness hotkeys must be disabled, and the backlight interface is | ||
| 618 | to be kept disabled as well. This is the default mode of operation. | ||
| 619 | |||
| 620 | 2. Do *NOT* load up ACPI video, enable the hotkeys in thinkpad-acpi, | ||
| 621 | and map them to KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN. Process | ||
| 622 | these keys on userspace somehow (e.g. by calling xbacklight). | ||
| 623 | The driver will do this automatically if it detects that ACPI video | ||
| 624 | has been disabled. | ||
| 625 | 596 | ||
| 626 | 597 | ||
| 627 | Bluetooth | 598 | Bluetooth |
| @@ -1121,25 +1092,61 @@ WARNING: | |||
| 1121 | its level up and down at every change. | 1092 | its level up and down at every change. |
| 1122 | 1093 | ||
| 1123 | 1094 | ||
| 1124 | Volume control -- /proc/acpi/ibm/volume | 1095 | Volume control |
| 1125 | --------------------------------------- | 1096 | -------------- |
| 1097 | |||
| 1098 | procfs: /proc/acpi/ibm/volume | ||
| 1099 | ALSA: "ThinkPad Console Audio Control", default ID: "ThinkPadEC" | ||
| 1100 | |||
| 1101 | NOTE: by default, the volume control interface operates in read-only | ||
| 1102 | mode, as it is supposed to be used for on-screen-display purposes. | ||
| 1103 | The read/write mode can be enabled through the use of the | ||
| 1104 | "volume_control=1" module parameter. | ||
| 1126 | 1105 | ||
| 1127 | This feature allows volume control on ThinkPad models which don't have | 1106 | NOTE: distros are urged to not enable volume_control by default, this |
| 1128 | a hardware volume knob. The available commands are: | 1107 | should be done by the local admin only. The ThinkPad UI is for the |
| 1108 | console audio control to be done through the volume keys only, and for | ||
| 1109 | the desktop environment to just provide on-screen-display feedback. | ||
| 1110 | Software volume control should be done only in the main AC97/HDA | ||
| 1111 | mixer. | ||
| 1112 | |||
| 1113 | This feature allows volume control on ThinkPad models with a digital | ||
| 1114 | volume knob (when available, not all models have it), as well as | ||
| 1115 | mute/unmute control. The available commands are: | ||
| 1129 | 1116 | ||
| 1130 | echo up >/proc/acpi/ibm/volume | 1117 | echo up >/proc/acpi/ibm/volume |
| 1131 | echo down >/proc/acpi/ibm/volume | 1118 | echo down >/proc/acpi/ibm/volume |
| 1132 | echo mute >/proc/acpi/ibm/volume | 1119 | echo mute >/proc/acpi/ibm/volume |
| 1120 | echo unmute >/proc/acpi/ibm/volume | ||
| 1133 | echo 'level <level>' >/proc/acpi/ibm/volume | 1121 | echo 'level <level>' >/proc/acpi/ibm/volume |
| 1134 | 1122 | ||
| 1135 | The <level> number range is 0 to 15 although not all of them may be | 1123 | The <level> number range is 0 to 14 although not all of them may be |
| 1136 | distinct. The unmute the volume after the mute command, use either the | 1124 | distinct. The unmute the volume after the mute command, use either the |
| 1137 | up or down command (the level command will not unmute the volume). | 1125 | up or down command (the level command will not unmute the volume), or |
| 1126 | the unmute command. | ||
| 1127 | |||
| 1138 | The current volume level and mute state is shown in the file. | 1128 | The current volume level and mute state is shown in the file. |
| 1139 | 1129 | ||
| 1140 | The ALSA mixer interface to this feature is still missing, but patches | 1130 | You can use the volume_capabilities parameter to tell the driver |
| 1141 | to add it exist. That problem should be addressed in the not so | 1131 | whether your thinkpad has volume control or mute-only control: |
| 1142 | distant future. | 1132 | volume_capabilities=1 for mixers with mute and volume control, |
| 1133 | volume_capabilities=2 for mixers with only mute control. | ||
| 1134 | |||
| 1135 | If the driver misdetects the capabilities for your ThinkPad model, | ||
| 1136 | please report this to ibm-acpi-devel@lists.sourceforge.net, so that we | ||
| 1137 | can update the driver. | ||
| 1138 | |||
| 1139 | There are two strategies for volume control. To select which one | ||
| 1140 | should be used, use the volume_mode module parameter: volume_mode=1 | ||
| 1141 | selects EC mode, and volume_mode=3 selects EC mode with NVRAM backing | ||
| 1142 | (so that volume/mute changes are remembered across shutdown/reboot). | ||
| 1143 | |||
| 1144 | The driver will operate in volume_mode=3 by default. If that does not | ||
| 1145 | work well on your ThinkPad model, please report this to | ||
| 1146 | ibm-acpi-devel@lists.sourceforge.net. | ||
| 1147 | |||
| 1148 | The driver supports the standard ALSA module parameters. If the ALSA | ||
| 1149 | mixer is disabled, the driver will disable all volume functionality. | ||
| 1143 | 1150 | ||
| 1144 | 1151 | ||
| 1145 | Fan control and monitoring: fan speed, fan enable/disable | 1152 | Fan control and monitoring: fan speed, fan enable/disable |
| @@ -1405,6 +1412,7 @@ to enable more than one output class, just add their values. | |||
| 1405 | 0x0008 HKEY event interface, hotkeys | 1412 | 0x0008 HKEY event interface, hotkeys |
| 1406 | 0x0010 Fan control | 1413 | 0x0010 Fan control |
| 1407 | 0x0020 Backlight brightness | 1414 | 0x0020 Backlight brightness |
| 1415 | 0x0040 Audio mixer/volume control | ||
| 1408 | 1416 | ||
| 1409 | There is also a kernel build option to enable more debugging | 1417 | There is also a kernel build option to enable more debugging |
| 1410 | information, which may be necessary to debug driver problems. | 1418 | information, which may be necessary to debug driver problems. |
| @@ -1465,3 +1473,9 @@ Sysfs interface changelog: | |||
| 1465 | and it is always able to disable hot keys. Very old | 1473 | and it is always able to disable hot keys. Very old |
| 1466 | thinkpads are properly supported. hotkey_bios_mask | 1474 | thinkpads are properly supported. hotkey_bios_mask |
| 1467 | is deprecated and marked for removal. | 1475 | is deprecated and marked for removal. |
| 1476 | |||
| 1477 | 0x020600: Marker for backlight change event support. | ||
| 1478 | |||
| 1479 | 0x020700: Support for mute-only mixers. | ||
| 1480 | Volume control in read-only mode by default. | ||
| 1481 | Marker for ALSA mixer support. | ||
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index a87dc277a5ca..cb3d15bc1aeb 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt | |||
| @@ -206,6 +206,7 @@ passive | |||
| 206 | passive trip point for the zone. Activation is done by polling with | 206 | passive trip point for the zone. Activation is done by polling with |
| 207 | an interval of 1 second. | 207 | an interval of 1 second. |
| 208 | Unit: millidegrees Celsius | 208 | Unit: millidegrees Celsius |
| 209 | Valid values: 0 (disabled) or greater than 1000 | ||
| 209 | RW, Optional | 210 | RW, Optional |
| 210 | 211 | ||
| 211 | ***************************** | 212 | ***************************** |
diff --git a/arch/x86/kernel/acpi/cstate.c b/arch/x86/kernel/acpi/cstate.c index 59cdfa4686b2..2e837f5080fe 100644 --- a/arch/x86/kernel/acpi/cstate.c +++ b/arch/x86/kernel/acpi/cstate.c | |||
| @@ -48,7 +48,7 @@ void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags, | |||
| 48 | * P4, Core and beyond CPUs | 48 | * P4, Core and beyond CPUs |
| 49 | */ | 49 | */ |
| 50 | if (c->x86_vendor == X86_VENDOR_INTEL && | 50 | if (c->x86_vendor == X86_VENDOR_INTEL && |
| 51 | (c->x86 > 0xf || (c->x86 == 6 && c->x86_model >= 14))) | 51 | (c->x86 > 0xf || (c->x86 == 6 && c->x86_model >= 0x0f))) |
| 52 | flags->bm_control = 0; | 52 | flags->bm_control = 0; |
| 53 | } | 53 | } |
| 54 | EXPORT_SYMBOL(acpi_processor_power_init_bm_check); | 54 | EXPORT_SYMBOL(acpi_processor_power_init_bm_check); |
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c index 0d2cdb86158b..97991ac6f5fc 100644 --- a/drivers/acpi/acpi_pad.c +++ b/drivers/acpi/acpi_pad.c | |||
| @@ -100,7 +100,8 @@ static void round_robin_cpu(unsigned int tsk_index) | |||
| 100 | struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); | 100 | struct cpumask *pad_busy_cpus = to_cpumask(pad_busy_cpus_bits); |
| 101 | cpumask_var_t tmp; | 101 | cpumask_var_t tmp; |
| 102 | int cpu; | 102 | int cpu; |
| 103 | unsigned long min_weight = -1, preferred_cpu; | 103 | unsigned long min_weight = -1; |
| 104 | unsigned long uninitialized_var(preferred_cpu); | ||
| 104 | 105 | ||
| 105 | if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) | 106 | if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) |
| 106 | return; | 107 | return; |
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h index ab83919dda61..61edb156e8d0 100644 --- a/drivers/acpi/acpica/acnamesp.h +++ b/drivers/acpi/acpica/acnamesp.h | |||
| @@ -296,6 +296,11 @@ acpi_ns_complex_repairs(struct acpi_predefined_data *data, | |||
| 296 | acpi_status validate_status, | 296 | acpi_status validate_status, |
| 297 | union acpi_operand_object **return_object_ptr); | 297 | union acpi_operand_object **return_object_ptr); |
| 298 | 298 | ||
| 299 | void | ||
| 300 | acpi_ns_remove_null_elements(struct acpi_predefined_data *data, | ||
| 301 | u8 package_type, | ||
| 302 | union acpi_operand_object *obj_desc); | ||
| 303 | |||
| 299 | /* | 304 | /* |
| 300 | * nssearch - Namespace searching and entry | 305 | * nssearch - Namespace searching and entry |
| 301 | */ | 306 | */ |
| @@ -354,9 +359,7 @@ acpi_ns_externalize_name(u32 internal_name_length, | |||
| 354 | const char *internal_name, | 359 | const char *internal_name, |
| 355 | u32 * converted_name_length, char **converted_name); | 360 | u32 * converted_name_length, char **converted_name); |
| 356 | 361 | ||
| 357 | struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle); | 362 | struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle); |
| 358 | |||
| 359 | acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node); | ||
| 360 | 363 | ||
| 361 | void acpi_ns_terminate(void); | 364 | void acpi_ns_terminate(void); |
| 362 | 365 | ||
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h index b39d682a2140..64062b1be3ee 100644 --- a/drivers/acpi/acpica/acobject.h +++ b/drivers/acpi/acpica/acobject.h | |||
| @@ -180,7 +180,11 @@ struct acpi_object_method { | |||
| 180 | u8 sync_level; | 180 | u8 sync_level; |
| 181 | union acpi_operand_object *mutex; | 181 | union acpi_operand_object *mutex; |
| 182 | u8 *aml_start; | 182 | u8 *aml_start; |
| 183 | ACPI_INTERNAL_METHOD implementation; | 183 | union { |
| 184 | ACPI_INTERNAL_METHOD implementation; | ||
| 185 | union acpi_operand_object *handler; | ||
| 186 | } extra; | ||
| 187 | |||
| 184 | u32 aml_length; | 188 | u32 aml_length; |
| 185 | u8 thread_count; | 189 | u8 thread_count; |
| 186 | acpi_owner_id owner_id; | 190 | acpi_owner_id owner_id; |
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c index 567a4899a018..e786f9fd767f 100644 --- a/drivers/acpi/acpica/dsmethod.c +++ b/drivers/acpi/acpica/dsmethod.c | |||
| @@ -414,7 +414,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread, | |||
| 414 | /* Invoke an internal method if necessary */ | 414 | /* Invoke an internal method if necessary */ |
| 415 | 415 | ||
| 416 | if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { | 416 | if (obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { |
| 417 | status = obj_desc->method.implementation(next_walk_state); | 417 | status = obj_desc->method.extra.implementation(next_walk_state); |
| 418 | if (status == AE_OK) { | 418 | if (status == AE_OK) { |
| 419 | status = AE_CTRL_TERMINATE; | 419 | status = AE_CTRL_TERMINATE; |
| 420 | } | 420 | } |
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c index 10fc78517843..b40513dd6a6a 100644 --- a/drivers/acpi/acpica/dswload.c +++ b/drivers/acpi/acpica/dswload.c | |||
| @@ -212,18 +212,19 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, | |||
| 212 | case ACPI_TYPE_BUFFER: | 212 | case ACPI_TYPE_BUFFER: |
| 213 | 213 | ||
| 214 | /* | 214 | /* |
| 215 | * These types we will allow, but we will change the type. This | 215 | * These types we will allow, but we will change the type. |
| 216 | * enables some existing code of the form: | 216 | * This enables some existing code of the form: |
| 217 | * | 217 | * |
| 218 | * Name (DEB, 0) | 218 | * Name (DEB, 0) |
| 219 | * Scope (DEB) { ... } | 219 | * Scope (DEB) { ... } |
| 220 | * | 220 | * |
| 221 | * Note: silently change the type here. On the second pass, we will report | 221 | * Note: silently change the type here. On the second pass, |
| 222 | * a warning | 222 | * we will report a warning |
| 223 | */ | 223 | */ |
| 224 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 224 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
| 225 | "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n", | 225 | "Type override - [%4.4s] had invalid type (%s) " |
| 226 | path, | 226 | "for Scope operator, changed to type ANY\n", |
| 227 | acpi_ut_get_node_name(node), | ||
| 227 | acpi_ut_get_type_name(node->type))); | 228 | acpi_ut_get_type_name(node->type))); |
| 228 | 229 | ||
| 229 | node->type = ACPI_TYPE_ANY; | 230 | node->type = ACPI_TYPE_ANY; |
| @@ -235,8 +236,10 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state, | |||
| 235 | /* All other types are an error */ | 236 | /* All other types are an error */ |
| 236 | 237 | ||
| 237 | ACPI_ERROR((AE_INFO, | 238 | ACPI_ERROR((AE_INFO, |
| 238 | "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)", | 239 | "Invalid type (%s) for target of " |
| 239 | acpi_ut_get_type_name(node->type), path)); | 240 | "Scope operator [%4.4s] (Cannot override)", |
| 241 | acpi_ut_get_type_name(node->type), | ||
| 242 | acpi_ut_get_node_name(node))); | ||
| 240 | 243 | ||
| 241 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); | 244 | return_ACPI_STATUS(AE_AML_OPERAND_TYPE); |
| 242 | } | 245 | } |
| @@ -697,15 +700,16 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, | |||
| 697 | case ACPI_TYPE_BUFFER: | 700 | case ACPI_TYPE_BUFFER: |
| 698 | 701 | ||
| 699 | /* | 702 | /* |
| 700 | * These types we will allow, but we will change the type. This | 703 | * These types we will allow, but we will change the type. |
| 701 | * enables some existing code of the form: | 704 | * This enables some existing code of the form: |
| 702 | * | 705 | * |
| 703 | * Name (DEB, 0) | 706 | * Name (DEB, 0) |
| 704 | * Scope (DEB) { ... } | 707 | * Scope (DEB) { ... } |
| 705 | */ | 708 | */ |
| 706 | ACPI_WARNING((AE_INFO, | 709 | ACPI_WARNING((AE_INFO, |
| 707 | "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)", | 710 | "Type override - [%4.4s] had invalid type (%s) " |
| 708 | buffer_ptr, | 711 | "for Scope operator, changed to type ANY\n", |
| 712 | acpi_ut_get_node_name(node), | ||
| 709 | acpi_ut_get_type_name(node->type))); | 713 | acpi_ut_get_type_name(node->type))); |
| 710 | 714 | ||
| 711 | node->type = ACPI_TYPE_ANY; | 715 | node->type = ACPI_TYPE_ANY; |
| @@ -717,9 +721,10 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state, | |||
| 717 | /* All other types are an error */ | 721 | /* All other types are an error */ |
| 718 | 722 | ||
| 719 | ACPI_ERROR((AE_INFO, | 723 | ACPI_ERROR((AE_INFO, |
| 720 | "Invalid type (%s) for target of Scope operator [%4.4s]", | 724 | "Invalid type (%s) for target of " |
| 725 | "Scope operator [%4.4s] (Cannot override)", | ||
| 721 | acpi_ut_get_type_name(node->type), | 726 | acpi_ut_get_type_name(node->type), |
| 722 | buffer_ptr)); | 727 | acpi_ut_get_node_name(node))); |
| 723 | 728 | ||
| 724 | return (AE_AML_OPERAND_TYPE); | 729 | return (AE_AML_OPERAND_TYPE); |
| 725 | } | 730 | } |
| @@ -1047,9 +1052,22 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) | |||
| 1047 | } | 1052 | } |
| 1048 | 1053 | ||
| 1049 | /* | 1054 | /* |
| 1050 | * If we are executing a method, initialize the region | 1055 | * The op_region is not fully parsed at this time. The only valid |
| 1056 | * argument is the space_id. (We must save the address of the | ||
| 1057 | * AML of the address and length operands) | ||
| 1058 | * | ||
| 1059 | * If we have a valid region, initialize it. The namespace is | ||
| 1060 | * unlocked at this point. | ||
| 1061 | * | ||
| 1062 | * Need to unlock interpreter if it is locked (if we are running | ||
| 1063 | * a control method), in order to allow _REG methods to be run | ||
| 1064 | * during acpi_ev_initialize_region. | ||
| 1051 | */ | 1065 | */ |
| 1052 | if (walk_state->method_node) { | 1066 | if (walk_state->method_node) { |
| 1067 | /* | ||
| 1068 | * Executing a method: initialize the region and unlock | ||
| 1069 | * the interpreter | ||
| 1070 | */ | ||
| 1053 | status = | 1071 | status = |
| 1054 | acpi_ex_create_region(op->named.data, | 1072 | acpi_ex_create_region(op->named.data, |
| 1055 | op->named.length, | 1073 | op->named.length, |
| @@ -1058,21 +1076,17 @@ acpi_status acpi_ds_load2_end_op(struct acpi_walk_state *walk_state) | |||
| 1058 | if (ACPI_FAILURE(status)) { | 1076 | if (ACPI_FAILURE(status)) { |
| 1059 | return (status); | 1077 | return (status); |
| 1060 | } | 1078 | } |
| 1061 | } | ||
| 1062 | 1079 | ||
| 1063 | /* | 1080 | acpi_ex_exit_interpreter(); |
| 1064 | * The op_region is not fully parsed at this time. Only valid | 1081 | } |
| 1065 | * argument is the space_id. (We must save the address of the | ||
| 1066 | * AML of the address and length operands) | ||
| 1067 | */ | ||
| 1068 | 1082 | ||
| 1069 | /* | ||
| 1070 | * If we have a valid region, initialize it | ||
| 1071 | * Namespace is NOT locked at this point. | ||
| 1072 | */ | ||
| 1073 | status = | 1083 | status = |
| 1074 | acpi_ev_initialize_region | 1084 | acpi_ev_initialize_region |
| 1075 | (acpi_ns_get_attached_object(node), FALSE); | 1085 | (acpi_ns_get_attached_object(node), FALSE); |
| 1086 | if (walk_state->method_node) { | ||
| 1087 | acpi_ex_enter_interpreter(); | ||
| 1088 | } | ||
| 1089 | |||
| 1076 | if (ACPI_FAILURE(status)) { | 1090 | if (ACPI_FAILURE(status)) { |
| 1077 | /* | 1091 | /* |
| 1078 | * If AE_NOT_EXIST is returned, it is not fatal | 1092 | * If AE_NOT_EXIST is returned, it is not fatal |
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c index 0bc807c33a56..5336d911fbf0 100644 --- a/drivers/acpi/acpica/evregion.c +++ b/drivers/acpi/acpica/evregion.c | |||
| @@ -718,7 +718,7 @@ acpi_ev_install_handler(acpi_handle obj_handle, | |||
| 718 | 718 | ||
| 719 | /* Convert and validate the device handle */ | 719 | /* Convert and validate the device handle */ |
| 720 | 720 | ||
| 721 | node = acpi_ns_map_handle_to_node(obj_handle); | 721 | node = acpi_ns_validate_handle(obj_handle); |
| 722 | if (!node) { | 722 | if (!node) { |
| 723 | return (AE_BAD_PARAMETER); | 723 | return (AE_BAD_PARAMETER); |
| 724 | } | 724 | } |
| @@ -1087,7 +1087,7 @@ acpi_ev_reg_run(acpi_handle obj_handle, | |||
| 1087 | 1087 | ||
| 1088 | /* Convert and validate the device handle */ | 1088 | /* Convert and validate the device handle */ |
| 1089 | 1089 | ||
| 1090 | node = acpi_ns_map_handle_to_node(obj_handle); | 1090 | node = acpi_ns_validate_handle(obj_handle); |
| 1091 | if (!node) { | 1091 | if (!node) { |
| 1092 | return (AE_BAD_PARAMETER); | 1092 | return (AE_BAD_PARAMETER); |
| 1093 | } | 1093 | } |
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c index cf29c4953028..ff168052a332 100644 --- a/drivers/acpi/acpica/evrgnini.c +++ b/drivers/acpi/acpica/evrgnini.c | |||
| @@ -575,6 +575,21 @@ acpi_ev_initialize_region(union acpi_operand_object *region_obj, | |||
| 575 | handler_obj = obj_desc->thermal_zone.handler; | 575 | handler_obj = obj_desc->thermal_zone.handler; |
| 576 | break; | 576 | break; |
| 577 | 577 | ||
| 578 | case ACPI_TYPE_METHOD: | ||
| 579 | /* | ||
| 580 | * If we are executing module level code, the original | ||
| 581 | * Node's object was replaced by this Method object and we | ||
| 582 | * saved the handler in the method object. | ||
| 583 | * | ||
| 584 | * See acpi_ns_exec_module_code | ||
| 585 | */ | ||
| 586 | if (obj_desc->method. | ||
| 587 | flags & AOPOBJ_MODULE_LEVEL) { | ||
| 588 | handler_obj = | ||
| 589 | obj_desc->method.extra.handler; | ||
| 590 | } | ||
| 591 | break; | ||
| 592 | |||
| 578 | default: | 593 | default: |
| 579 | /* Ignore other objects */ | 594 | /* Ignore other objects */ |
| 580 | break; | 595 | break; |
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c index 10b8543dd466..2fe0809d4eb2 100644 --- a/drivers/acpi/acpica/evxface.c +++ b/drivers/acpi/acpica/evxface.c | |||
| @@ -259,7 +259,7 @@ acpi_install_notify_handler(acpi_handle device, | |||
| 259 | 259 | ||
| 260 | /* Convert and validate the device handle */ | 260 | /* Convert and validate the device handle */ |
| 261 | 261 | ||
| 262 | node = acpi_ns_map_handle_to_node(device); | 262 | node = acpi_ns_validate_handle(device); |
| 263 | if (!node) { | 263 | if (!node) { |
| 264 | status = AE_BAD_PARAMETER; | 264 | status = AE_BAD_PARAMETER; |
| 265 | goto unlock_and_exit; | 265 | goto unlock_and_exit; |
| @@ -425,7 +425,7 @@ acpi_remove_notify_handler(acpi_handle device, | |||
| 425 | 425 | ||
| 426 | /* Convert and validate the device handle */ | 426 | /* Convert and validate the device handle */ |
| 427 | 427 | ||
| 428 | node = acpi_ns_map_handle_to_node(device); | 428 | node = acpi_ns_validate_handle(device); |
| 429 | if (!node) { | 429 | if (!node) { |
| 430 | status = AE_BAD_PARAMETER; | 430 | status = AE_BAD_PARAMETER; |
| 431 | goto unlock_and_exit; | 431 | goto unlock_and_exit; |
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c index 4721f58fe42c..eed7a38d25f2 100644 --- a/drivers/acpi/acpica/evxfevnt.c +++ b/drivers/acpi/acpica/evxfevnt.c | |||
| @@ -610,7 +610,7 @@ acpi_install_gpe_block(acpi_handle gpe_device, | |||
| 610 | return (status); | 610 | return (status); |
| 611 | } | 611 | } |
| 612 | 612 | ||
| 613 | node = acpi_ns_map_handle_to_node(gpe_device); | 613 | node = acpi_ns_validate_handle(gpe_device); |
| 614 | if (!node) { | 614 | if (!node) { |
| 615 | status = AE_BAD_PARAMETER; | 615 | status = AE_BAD_PARAMETER; |
| 616 | goto unlock_and_exit; | 616 | goto unlock_and_exit; |
| @@ -698,7 +698,7 @@ acpi_status acpi_remove_gpe_block(acpi_handle gpe_device) | |||
| 698 | return (status); | 698 | return (status); |
| 699 | } | 699 | } |
| 700 | 700 | ||
| 701 | node = acpi_ns_map_handle_to_node(gpe_device); | 701 | node = acpi_ns_validate_handle(gpe_device); |
| 702 | if (!node) { | 702 | if (!node) { |
| 703 | status = AE_BAD_PARAMETER; | 703 | status = AE_BAD_PARAMETER; |
| 704 | goto unlock_and_exit; | 704 | goto unlock_and_exit; |
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c index 7c3d2d356ffb..c98aa7c2d67c 100644 --- a/drivers/acpi/acpica/evxfregn.c +++ b/drivers/acpi/acpica/evxfregn.c | |||
| @@ -89,7 +89,7 @@ acpi_install_address_space_handler(acpi_handle device, | |||
| 89 | 89 | ||
| 90 | /* Convert and validate the device handle */ | 90 | /* Convert and validate the device handle */ |
| 91 | 91 | ||
| 92 | node = acpi_ns_map_handle_to_node(device); | 92 | node = acpi_ns_validate_handle(device); |
| 93 | if (!node) { | 93 | if (!node) { |
| 94 | status = AE_BAD_PARAMETER; | 94 | status = AE_BAD_PARAMETER; |
| 95 | goto unlock_and_exit; | 95 | goto unlock_and_exit; |
| @@ -155,7 +155,7 @@ acpi_remove_address_space_handler(acpi_handle device, | |||
| 155 | 155 | ||
| 156 | /* Convert and validate the device handle */ | 156 | /* Convert and validate the device handle */ |
| 157 | 157 | ||
| 158 | node = acpi_ns_map_handle_to_node(device); | 158 | node = acpi_ns_validate_handle(device); |
| 159 | if (!node || | 159 | if (!node || |
| 160 | ((node->type != ACPI_TYPE_DEVICE) && | 160 | ((node->type != ACPI_TYPE_DEVICE) && |
| 161 | (node->type != ACPI_TYPE_PROCESSOR) && | 161 | (node->type != ACPI_TYPE_PROCESSOR) && |
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c index 2f0114202b05..3c456bd575d0 100644 --- a/drivers/acpi/acpica/exmutex.c +++ b/drivers/acpi/acpica/exmutex.c | |||
| @@ -375,6 +375,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
| 375 | return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); | 375 | return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED); |
| 376 | } | 376 | } |
| 377 | 377 | ||
| 378 | /* Must have a valid thread ID */ | ||
| 379 | |||
| 380 | if (!walk_state->thread) { | ||
| 381 | ACPI_ERROR((AE_INFO, | ||
| 382 | "Cannot release Mutex [%4.4s], null thread info", | ||
| 383 | acpi_ut_get_node_name(obj_desc->mutex.node))); | ||
| 384 | return_ACPI_STATUS(AE_AML_INTERNAL); | ||
| 385 | } | ||
| 386 | |||
| 378 | /* | 387 | /* |
| 379 | * The Mutex is owned, but this thread must be the owner. | 388 | * The Mutex is owned, but this thread must be the owner. |
| 380 | * Special case for Global Lock, any thread can release | 389 | * Special case for Global Lock, any thread can release |
| @@ -392,15 +401,6 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc, | |||
| 392 | return_ACPI_STATUS(AE_AML_NOT_OWNER); | 401 | return_ACPI_STATUS(AE_AML_NOT_OWNER); |
| 393 | } | 402 | } |
| 394 | 403 | ||
| 395 | /* Must have a valid thread ID */ | ||
| 396 | |||
| 397 | if (!walk_state->thread) { | ||
| 398 | ACPI_ERROR((AE_INFO, | ||
| 399 | "Cannot release Mutex [%4.4s], null thread info", | ||
| 400 | acpi_ut_get_node_name(obj_desc->mutex.node))); | ||
| 401 | return_ACPI_STATUS(AE_AML_INTERNAL); | ||
| 402 | } | ||
| 403 | |||
| 404 | /* | 404 | /* |
| 405 | * The sync level of the mutex must be equal to the current sync level. In | 405 | * The sync level of the mutex must be equal to the current sync level. In |
| 406 | * other words, the current level means that at least one mutex at that | 406 | * other words, the current level means that at least one mutex at that |
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c index 9c3cdbe2d82a..d622ba770000 100644 --- a/drivers/acpi/acpica/nsaccess.c +++ b/drivers/acpi/acpica/nsaccess.c | |||
| @@ -165,7 +165,7 @@ acpi_status acpi_ns_root_initialize(void) | |||
| 165 | 165 | ||
| 166 | obj_desc->method.method_flags = | 166 | obj_desc->method.method_flags = |
| 167 | AML_METHOD_INTERNAL_ONLY; | 167 | AML_METHOD_INTERNAL_ONLY; |
| 168 | obj_desc->method.implementation = | 168 | obj_desc->method.extra.implementation = |
| 169 | acpi_ut_osi_implementation; | 169 | acpi_ut_osi_implementation; |
| 170 | #endif | 170 | #endif |
| 171 | break; | 171 | break; |
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c index 2deb986861ca..e37836e27e29 100644 --- a/drivers/acpi/acpica/nsdump.c +++ b/drivers/acpi/acpica/nsdump.c | |||
| @@ -180,7 +180,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle, | |||
| 180 | return (AE_OK); | 180 | return (AE_OK); |
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | this_node = acpi_ns_map_handle_to_node(obj_handle); | 183 | this_node = acpi_ns_validate_handle(obj_handle); |
| 184 | if (!this_node) { | 184 | if (!this_node) { |
| 185 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", | 185 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Invalid object handle %p\n", |
| 186 | obj_handle)); | 186 | obj_handle)); |
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c index f771e978c403..af9fe9103734 100644 --- a/drivers/acpi/acpica/nseval.c +++ b/drivers/acpi/acpica/nseval.c | |||
| @@ -381,6 +381,18 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, | |||
| 381 | method_obj->method.next_object); | 381 | method_obj->method.next_object); |
| 382 | type = acpi_ns_get_type(parent_node); | 382 | type = acpi_ns_get_type(parent_node); |
| 383 | 383 | ||
| 384 | /* | ||
| 385 | * Get the region handler and save it in the method object. We may need | ||
| 386 | * this if an operation region declaration causes a _REG method to be run. | ||
| 387 | * | ||
| 388 | * We can't do this in acpi_ps_link_module_code because | ||
| 389 | * acpi_gbl_root_node->Object is NULL at PASS1. | ||
| 390 | */ | ||
| 391 | if ((type == ACPI_TYPE_DEVICE) && parent_node->object) { | ||
| 392 | method_obj->method.extra.handler = | ||
| 393 | parent_node->object->device.handler; | ||
| 394 | } | ||
| 395 | |||
| 384 | /* Must clear next_object (acpi_ns_attach_object needs the field) */ | 396 | /* Must clear next_object (acpi_ns_attach_object needs the field) */ |
| 385 | 397 | ||
| 386 | method_obj->method.next_object = NULL; | 398 | method_obj->method.next_object = NULL; |
| @@ -415,6 +427,12 @@ acpi_ns_exec_module_code(union acpi_operand_object *method_obj, | |||
| 415 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n", | 427 | ACPI_DEBUG_PRINT((ACPI_DB_INIT, "Executed module-level code at %p\n", |
| 416 | method_obj->method.aml_start)); | 428 | method_obj->method.aml_start)); |
| 417 | 429 | ||
| 430 | /* Delete a possible implicit return value (in slack mode) */ | ||
| 431 | |||
| 432 | if (info->return_object) { | ||
| 433 | acpi_ut_remove_reference(info->return_object); | ||
| 434 | } | ||
| 435 | |||
| 418 | /* Detach the temporary method object */ | 436 | /* Detach the temporary method object */ |
| 419 | 437 | ||
| 420 | acpi_ns_detach_object(parent_node); | 438 | acpi_ns_detach_object(parent_node); |
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c index af8e6bcee07e..8f9a4875ce26 100644 --- a/drivers/acpi/acpica/nsnames.c +++ b/drivers/acpi/acpica/nsnames.c | |||
| @@ -232,7 +232,7 @@ acpi_ns_handle_to_pathname(acpi_handle target_handle, | |||
| 232 | 232 | ||
| 233 | ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); | 233 | ACPI_FUNCTION_TRACE_PTR(ns_handle_to_pathname, target_handle); |
| 234 | 234 | ||
| 235 | node = acpi_ns_map_handle_to_node(target_handle); | 235 | node = acpi_ns_validate_handle(target_handle); |
| 236 | if (!node) { | 236 | if (!node) { |
| 237 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 237 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
| 238 | } | 238 | } |
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c index b05f42903c86..d34fa59548f7 100644 --- a/drivers/acpi/acpica/nspredef.c +++ b/drivers/acpi/acpica/nspredef.c | |||
| @@ -216,29 +216,38 @@ acpi_ns_check_predefined_names(struct acpi_namespace_node *node, | |||
| 216 | data->pathname = pathname; | 216 | data->pathname = pathname; |
| 217 | 217 | ||
| 218 | /* | 218 | /* |
| 219 | * Check that the type of the return object is what is expected for | 219 | * Check that the type of the main return object is what is expected |
| 220 | * this predefined name | 220 | * for this predefined name |
| 221 | */ | 221 | */ |
| 222 | status = acpi_ns_check_object_type(data, return_object_ptr, | 222 | status = acpi_ns_check_object_type(data, return_object_ptr, |
| 223 | predefined->info.expected_btypes, | 223 | predefined->info.expected_btypes, |
| 224 | ACPI_NOT_PACKAGE_ELEMENT); | 224 | ACPI_NOT_PACKAGE_ELEMENT); |
| 225 | if (ACPI_FAILURE(status)) { | 225 | if (ACPI_FAILURE(status)) { |
| 226 | goto check_validation_status; | 226 | goto exit; |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | /* For returned Package objects, check the type of all sub-objects */ | 229 | /* |
| 230 | 230 | * For returned Package objects, check the type of all sub-objects. | |
| 231 | if (return_object->common.type == ACPI_TYPE_PACKAGE) { | 231 | * Note: Package may have been newly created by call above. |
| 232 | */ | ||
| 233 | if ((*return_object_ptr)->common.type == ACPI_TYPE_PACKAGE) { | ||
| 232 | status = acpi_ns_check_package(data, return_object_ptr); | 234 | status = acpi_ns_check_package(data, return_object_ptr); |
| 235 | if (ACPI_FAILURE(status)) { | ||
| 236 | goto exit; | ||
| 237 | } | ||
| 233 | } | 238 | } |
| 234 | 239 | ||
| 235 | /* | 240 | /* |
| 236 | * Perform additional, more complicated repairs on a per-name | 241 | * The return object was OK, or it was successfully repaired above. |
| 237 | * basis. | 242 | * Now make some additional checks such as verifying that package |
| 243 | * objects are sorted correctly (if required) or buffer objects have | ||
| 244 | * the correct data width (bytes vs. dwords). These repairs are | ||
| 245 | * performed on a per-name basis, i.e., the code is specific to | ||
| 246 | * particular predefined names. | ||
| 238 | */ | 247 | */ |
| 239 | status = acpi_ns_complex_repairs(data, node, status, return_object_ptr); | 248 | status = acpi_ns_complex_repairs(data, node, status, return_object_ptr); |
| 240 | 249 | ||
| 241 | check_validation_status: | 250 | exit: |
| 242 | /* | 251 | /* |
| 243 | * If the object validation failed or if we successfully repaired one | 252 | * If the object validation failed or if we successfully repaired one |
| 244 | * or more objects, mark the parent node to suppress further warning | 253 | * or more objects, mark the parent node to suppress further warning |
| @@ -427,6 +436,13 @@ acpi_ns_check_package(struct acpi_predefined_data *data, | |||
| 427 | data->pathname, package->ret_info.type, | 436 | data->pathname, package->ret_info.type, |
| 428 | return_object->package.count)); | 437 | return_object->package.count)); |
| 429 | 438 | ||
| 439 | /* | ||
| 440 | * For variable-length Packages, we can safely remove all embedded | ||
| 441 | * and trailing NULL package elements | ||
| 442 | */ | ||
| 443 | acpi_ns_remove_null_elements(data, package->ret_info.type, | ||
| 444 | return_object); | ||
| 445 | |||
| 430 | /* Extract package count and elements array */ | 446 | /* Extract package count and elements array */ |
| 431 | 447 | ||
| 432 | elements = return_object->package.elements; | 448 | elements = return_object->package.elements; |
| @@ -461,11 +477,11 @@ acpi_ns_check_package(struct acpi_predefined_data *data, | |||
| 461 | if (count < expected_count) { | 477 | if (count < expected_count) { |
| 462 | goto package_too_small; | 478 | goto package_too_small; |
| 463 | } else if (count > expected_count) { | 479 | } else if (count > expected_count) { |
| 464 | ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, | 480 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
| 465 | data->node_flags, | 481 | "%s: Return Package is larger than needed - " |
| 466 | "Return Package is larger than needed - " | 482 | "found %u, expected %u\n", |
| 467 | "found %u, expected %u", count, | 483 | data->pathname, count, |
| 468 | expected_count)); | 484 | expected_count)); |
| 469 | } | 485 | } |
| 470 | 486 | ||
| 471 | /* Validate all elements of the returned package */ | 487 | /* Validate all elements of the returned package */ |
| @@ -680,53 +696,18 @@ acpi_ns_check_package_list(struct acpi_predefined_data *data, | |||
| 680 | union acpi_operand_object *sub_package; | 696 | union acpi_operand_object *sub_package; |
| 681 | union acpi_operand_object **sub_elements; | 697 | union acpi_operand_object **sub_elements; |
| 682 | acpi_status status; | 698 | acpi_status status; |
| 683 | u8 non_trailing_null = FALSE; | ||
| 684 | u32 expected_count; | 699 | u32 expected_count; |
| 685 | u32 i; | 700 | u32 i; |
| 686 | u32 j; | 701 | u32 j; |
| 687 | 702 | ||
| 688 | /* Validate each sub-Package in the parent Package */ | 703 | /* |
| 689 | 704 | * Validate each sub-Package in the parent Package | |
| 705 | * | ||
| 706 | * NOTE: assumes list of sub-packages contains no NULL elements. | ||
| 707 | * Any NULL elements should have been removed by earlier call | ||
| 708 | * to acpi_ns_remove_null_elements. | ||
| 709 | */ | ||
| 690 | for (i = 0; i < count; i++) { | 710 | for (i = 0; i < count; i++) { |
| 691 | /* | ||
| 692 | * Handling for NULL package elements. For now, we will simply allow | ||
| 693 | * a parent package with trailing NULL elements. This can happen if | ||
| 694 | * the package was defined to be longer than the initializer list. | ||
| 695 | * This is legal as per the ACPI specification. It is often used | ||
| 696 | * to allow for dynamic initialization of a Package. | ||
| 697 | * | ||
| 698 | * A future enhancement may be to simply truncate the package to | ||
| 699 | * remove the trailing NULL elements. | ||
| 700 | */ | ||
| 701 | if (!(*elements)) { | ||
| 702 | if (!non_trailing_null) { | ||
| 703 | |||
| 704 | /* Ensure the remaining elements are all NULL */ | ||
| 705 | |||
| 706 | for (j = 1; j < (count - i + 1); j++) { | ||
| 707 | if (elements[j]) { | ||
| 708 | non_trailing_null = TRUE; | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | if (!non_trailing_null) { | ||
| 713 | |||
| 714 | /* Ignore the trailing NULL elements */ | ||
| 715 | |||
| 716 | return (AE_OK); | ||
| 717 | } | ||
| 718 | } | ||
| 719 | |||
| 720 | /* There are trailing non-null elements, issue warning */ | ||
| 721 | |||
| 722 | ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, | ||
| 723 | data->node_flags, | ||
| 724 | "Found NULL element at package index %u", | ||
| 725 | i)); | ||
| 726 | elements++; | ||
| 727 | continue; | ||
| 728 | } | ||
| 729 | |||
| 730 | sub_package = *elements; | 711 | sub_package = *elements; |
| 731 | sub_elements = sub_package->package.elements; | 712 | sub_elements = sub_package->package.elements; |
| 732 | 713 | ||
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c index d563f1a564a7..4fd1bdb056b2 100644 --- a/drivers/acpi/acpica/nsrepair.c +++ b/drivers/acpi/acpica/nsrepair.c | |||
| @@ -45,13 +45,52 @@ | |||
| 45 | #include "accommon.h" | 45 | #include "accommon.h" |
| 46 | #include "acnamesp.h" | 46 | #include "acnamesp.h" |
| 47 | #include "acinterp.h" | 47 | #include "acinterp.h" |
| 48 | #include "acpredef.h" | ||
| 49 | 48 | ||
| 50 | #define _COMPONENT ACPI_NAMESPACE | 49 | #define _COMPONENT ACPI_NAMESPACE |
| 51 | ACPI_MODULE_NAME("nsrepair") | 50 | ACPI_MODULE_NAME("nsrepair") |
| 52 | 51 | ||
| 53 | /******************************************************************************* | 52 | /******************************************************************************* |
| 54 | * | 53 | * |
| 54 | * This module attempts to repair or convert objects returned by the | ||
| 55 | * predefined methods to an object type that is expected, as per the ACPI | ||
| 56 | * specification. The need for this code is dictated by the many machines that | ||
| 57 | * return incorrect types for the standard predefined methods. Performing these | ||
| 58 | * conversions here, in one place, eliminates the need for individual ACPI | ||
| 59 | * device drivers to do the same. Note: Most of these conversions are different | ||
| 60 | * than the internal object conversion routines used for implicit object | ||
| 61 | * conversion. | ||
| 62 | * | ||
| 63 | * The following conversions can be performed as necessary: | ||
| 64 | * | ||
| 65 | * Integer -> String | ||
| 66 | * Integer -> Buffer | ||
| 67 | * String -> Integer | ||
| 68 | * String -> Buffer | ||
| 69 | * Buffer -> Integer | ||
| 70 | * Buffer -> String | ||
| 71 | * Buffer -> Package of Integers | ||
| 72 | * Package -> Package of one Package | ||
| 73 | * | ||
| 74 | ******************************************************************************/ | ||
| 75 | /* Local prototypes */ | ||
| 76 | static acpi_status | ||
| 77 | acpi_ns_convert_to_integer(union acpi_operand_object *original_object, | ||
| 78 | union acpi_operand_object **return_object); | ||
| 79 | |||
| 80 | static acpi_status | ||
| 81 | acpi_ns_convert_to_string(union acpi_operand_object *original_object, | ||
| 82 | union acpi_operand_object **return_object); | ||
| 83 | |||
| 84 | static acpi_status | ||
| 85 | acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, | ||
| 86 | union acpi_operand_object **return_object); | ||
| 87 | |||
| 88 | static acpi_status | ||
| 89 | acpi_ns_convert_to_package(union acpi_operand_object *original_object, | ||
| 90 | union acpi_operand_object **return_object); | ||
| 91 | |||
| 92 | /******************************************************************************* | ||
| 93 | * | ||
| 55 | * FUNCTION: acpi_ns_repair_object | 94 | * FUNCTION: acpi_ns_repair_object |
| 56 | * | 95 | * |
| 57 | * PARAMETERS: Data - Pointer to validation data structure | 96 | * PARAMETERS: Data - Pointer to validation data structure |
| @@ -68,6 +107,7 @@ ACPI_MODULE_NAME("nsrepair") | |||
| 68 | * not expected. | 107 | * not expected. |
| 69 | * | 108 | * |
| 70 | ******************************************************************************/ | 109 | ******************************************************************************/ |
| 110 | |||
| 71 | acpi_status | 111 | acpi_status |
| 72 | acpi_ns_repair_object(struct acpi_predefined_data *data, | 112 | acpi_ns_repair_object(struct acpi_predefined_data *data, |
| 73 | u32 expected_btypes, | 113 | u32 expected_btypes, |
| @@ -76,32 +116,206 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, | |||
| 76 | { | 116 | { |
| 77 | union acpi_operand_object *return_object = *return_object_ptr; | 117 | union acpi_operand_object *return_object = *return_object_ptr; |
| 78 | union acpi_operand_object *new_object; | 118 | union acpi_operand_object *new_object; |
| 79 | acpi_size length; | ||
| 80 | acpi_status status; | 119 | acpi_status status; |
| 81 | 120 | ||
| 121 | ACPI_FUNCTION_NAME(ns_repair_object); | ||
| 122 | |||
| 82 | /* | 123 | /* |
| 83 | * At this point, we know that the type of the returned object was not | 124 | * At this point, we know that the type of the returned object was not |
| 84 | * one of the expected types for this predefined name. Attempt to | 125 | * one of the expected types for this predefined name. Attempt to |
| 85 | * repair the object. Only a limited number of repairs are possible. | 126 | * repair the object by converting it to one of the expected object |
| 127 | * types for this predefined name. | ||
| 86 | */ | 128 | */ |
| 87 | switch (return_object->common.type) { | 129 | if (expected_btypes & ACPI_RTYPE_INTEGER) { |
| 130 | status = acpi_ns_convert_to_integer(return_object, &new_object); | ||
| 131 | if (ACPI_SUCCESS(status)) { | ||
| 132 | goto object_repaired; | ||
| 133 | } | ||
| 134 | } | ||
| 135 | if (expected_btypes & ACPI_RTYPE_STRING) { | ||
| 136 | status = acpi_ns_convert_to_string(return_object, &new_object); | ||
| 137 | if (ACPI_SUCCESS(status)) { | ||
| 138 | goto object_repaired; | ||
| 139 | } | ||
| 140 | } | ||
| 141 | if (expected_btypes & ACPI_RTYPE_BUFFER) { | ||
| 142 | status = acpi_ns_convert_to_buffer(return_object, &new_object); | ||
| 143 | if (ACPI_SUCCESS(status)) { | ||
| 144 | goto object_repaired; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | if (expected_btypes & ACPI_RTYPE_PACKAGE) { | ||
| 148 | status = acpi_ns_convert_to_package(return_object, &new_object); | ||
| 149 | if (ACPI_SUCCESS(status)) { | ||
| 150 | goto object_repaired; | ||
| 151 | } | ||
| 152 | } | ||
| 153 | |||
| 154 | /* We cannot repair this object */ | ||
| 155 | |||
| 156 | return (AE_AML_OPERAND_TYPE); | ||
| 157 | |||
| 158 | object_repaired: | ||
| 159 | |||
| 160 | /* Object was successfully repaired */ | ||
| 161 | |||
| 162 | /* | ||
| 163 | * If the original object is a package element, we need to: | ||
| 164 | * 1. Set the reference count of the new object to match the | ||
| 165 | * reference count of the old object. | ||
| 166 | * 2. Decrement the reference count of the original object. | ||
| 167 | */ | ||
| 168 | if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { | ||
| 169 | new_object->common.reference_count = | ||
| 170 | return_object->common.reference_count; | ||
| 171 | |||
| 172 | if (return_object->common.reference_count > 1) { | ||
| 173 | return_object->common.reference_count--; | ||
| 174 | } | ||
| 175 | |||
| 176 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
| 177 | "%s: Converted %s to expected %s at index %u\n", | ||
| 178 | data->pathname, | ||
| 179 | acpi_ut_get_object_type_name(return_object), | ||
| 180 | acpi_ut_get_object_type_name(new_object), | ||
| 181 | package_index)); | ||
| 182 | } else { | ||
| 183 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
| 184 | "%s: Converted %s to expected %s\n", | ||
| 185 | data->pathname, | ||
| 186 | acpi_ut_get_object_type_name(return_object), | ||
| 187 | acpi_ut_get_object_type_name(new_object))); | ||
| 188 | } | ||
| 189 | |||
| 190 | /* Delete old object, install the new return object */ | ||
| 191 | |||
| 192 | acpi_ut_remove_reference(return_object); | ||
| 193 | *return_object_ptr = new_object; | ||
| 194 | data->flags |= ACPI_OBJECT_REPAIRED; | ||
| 195 | return (AE_OK); | ||
| 196 | } | ||
| 197 | |||
| 198 | /******************************************************************************* | ||
| 199 | * | ||
| 200 | * FUNCTION: acpi_ns_convert_to_integer | ||
| 201 | * | ||
| 202 | * PARAMETERS: original_object - Object to be converted | ||
| 203 | * return_object - Where the new converted object is returned | ||
| 204 | * | ||
| 205 | * RETURN: Status. AE_OK if conversion was successful. | ||
| 206 | * | ||
| 207 | * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer. | ||
| 208 | * | ||
| 209 | ******************************************************************************/ | ||
| 210 | |||
| 211 | static acpi_status | ||
| 212 | acpi_ns_convert_to_integer(union acpi_operand_object *original_object, | ||
| 213 | union acpi_operand_object **return_object) | ||
| 214 | { | ||
| 215 | union acpi_operand_object *new_object; | ||
| 216 | acpi_status status; | ||
| 217 | u64 value = 0; | ||
| 218 | u32 i; | ||
| 219 | |||
| 220 | switch (original_object->common.type) { | ||
| 221 | case ACPI_TYPE_STRING: | ||
| 222 | |||
| 223 | /* String-to-Integer conversion */ | ||
| 224 | |||
| 225 | status = acpi_ut_strtoul64(original_object->string.pointer, | ||
| 226 | ACPI_ANY_BASE, &value); | ||
| 227 | if (ACPI_FAILURE(status)) { | ||
| 228 | return (status); | ||
| 229 | } | ||
| 230 | break; | ||
| 231 | |||
| 88 | case ACPI_TYPE_BUFFER: | 232 | case ACPI_TYPE_BUFFER: |
| 89 | 233 | ||
| 90 | /* Does the method/object legally return a string? */ | 234 | /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */ |
| 91 | 235 | ||
| 92 | if (!(expected_btypes & ACPI_RTYPE_STRING)) { | 236 | if (original_object->buffer.length > 8) { |
| 93 | return (AE_AML_OPERAND_TYPE); | 237 | return (AE_AML_OPERAND_TYPE); |
| 94 | } | 238 | } |
| 95 | 239 | ||
| 240 | /* Extract each buffer byte to create the integer */ | ||
| 241 | |||
| 242 | for (i = 0; i < original_object->buffer.length; i++) { | ||
| 243 | value |= | ||
| 244 | ((u64) original_object->buffer. | ||
| 245 | pointer[i] << (i * 8)); | ||
| 246 | } | ||
| 247 | break; | ||
| 248 | |||
| 249 | default: | ||
| 250 | return (AE_AML_OPERAND_TYPE); | ||
| 251 | } | ||
| 252 | |||
| 253 | new_object = acpi_ut_create_integer_object(value); | ||
| 254 | if (!new_object) { | ||
| 255 | return (AE_NO_MEMORY); | ||
| 256 | } | ||
| 257 | |||
| 258 | *return_object = new_object; | ||
| 259 | return (AE_OK); | ||
| 260 | } | ||
| 261 | |||
| 262 | /******************************************************************************* | ||
| 263 | * | ||
| 264 | * FUNCTION: acpi_ns_convert_to_string | ||
| 265 | * | ||
| 266 | * PARAMETERS: original_object - Object to be converted | ||
| 267 | * return_object - Where the new converted object is returned | ||
| 268 | * | ||
| 269 | * RETURN: Status. AE_OK if conversion was successful. | ||
| 270 | * | ||
| 271 | * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String. | ||
| 272 | * | ||
| 273 | ******************************************************************************/ | ||
| 274 | |||
| 275 | static acpi_status | ||
| 276 | acpi_ns_convert_to_string(union acpi_operand_object *original_object, | ||
| 277 | union acpi_operand_object **return_object) | ||
| 278 | { | ||
| 279 | union acpi_operand_object *new_object; | ||
| 280 | acpi_size length; | ||
| 281 | acpi_status status; | ||
| 282 | |||
| 283 | switch (original_object->common.type) { | ||
| 284 | case ACPI_TYPE_INTEGER: | ||
| 285 | /* | ||
| 286 | * Integer-to-String conversion. Commonly, convert | ||
| 287 | * an integer of value 0 to a NULL string. The last element of | ||
| 288 | * _BIF and _BIX packages occasionally need this fix. | ||
| 289 | */ | ||
| 290 | if (original_object->integer.value == 0) { | ||
| 291 | |||
| 292 | /* Allocate a new NULL string object */ | ||
| 293 | |||
| 294 | new_object = acpi_ut_create_string_object(0); | ||
| 295 | if (!new_object) { | ||
| 296 | return (AE_NO_MEMORY); | ||
| 297 | } | ||
| 298 | } else { | ||
| 299 | status = | ||
| 300 | acpi_ex_convert_to_string(original_object, | ||
| 301 | &new_object, | ||
| 302 | ACPI_IMPLICIT_CONVERT_HEX); | ||
| 303 | if (ACPI_FAILURE(status)) { | ||
| 304 | return (status); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | break; | ||
| 308 | |||
| 309 | case ACPI_TYPE_BUFFER: | ||
| 96 | /* | 310 | /* |
| 97 | * Have a Buffer, expected a String, convert. Use a to_string | 311 | * Buffer-to-String conversion. Use a to_string |
| 98 | * conversion, no transform performed on the buffer data. The best | 312 | * conversion, no transform performed on the buffer data. The best |
| 99 | * example of this is the _BIF method, where the string data from | 313 | * example of this is the _BIF method, where the string data from |
| 100 | * the battery is often (incorrectly) returned as buffer object(s). | 314 | * the battery is often (incorrectly) returned as buffer object(s). |
| 101 | */ | 315 | */ |
| 102 | length = 0; | 316 | length = 0; |
| 103 | while ((length < return_object->buffer.length) && | 317 | while ((length < original_object->buffer.length) && |
| 104 | (return_object->buffer.pointer[length])) { | 318 | (original_object->buffer.pointer[length])) { |
| 105 | length++; | 319 | length++; |
| 106 | } | 320 | } |
| 107 | 321 | ||
| @@ -117,94 +331,176 @@ acpi_ns_repair_object(struct acpi_predefined_data *data, | |||
| 117 | * terminated at Length+1. | 331 | * terminated at Length+1. |
| 118 | */ | 332 | */ |
| 119 | ACPI_MEMCPY(new_object->string.pointer, | 333 | ACPI_MEMCPY(new_object->string.pointer, |
| 120 | return_object->buffer.pointer, length); | 334 | original_object->buffer.pointer, length); |
| 121 | break; | 335 | break; |
| 122 | 336 | ||
| 337 | default: | ||
| 338 | return (AE_AML_OPERAND_TYPE); | ||
| 339 | } | ||
| 340 | |||
| 341 | *return_object = new_object; | ||
| 342 | return (AE_OK); | ||
| 343 | } | ||
| 344 | |||
| 345 | /******************************************************************************* | ||
| 346 | * | ||
| 347 | * FUNCTION: acpi_ns_convert_to_buffer | ||
| 348 | * | ||
| 349 | * PARAMETERS: original_object - Object to be converted | ||
| 350 | * return_object - Where the new converted object is returned | ||
| 351 | * | ||
| 352 | * RETURN: Status. AE_OK if conversion was successful. | ||
| 353 | * | ||
| 354 | * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer. | ||
| 355 | * | ||
| 356 | ******************************************************************************/ | ||
| 357 | |||
| 358 | static acpi_status | ||
| 359 | acpi_ns_convert_to_buffer(union acpi_operand_object *original_object, | ||
| 360 | union acpi_operand_object **return_object) | ||
| 361 | { | ||
| 362 | union acpi_operand_object *new_object; | ||
| 363 | acpi_status status; | ||
| 364 | union acpi_operand_object **elements; | ||
| 365 | u32 *dword_buffer; | ||
| 366 | u32 count; | ||
| 367 | u32 i; | ||
| 368 | |||
| 369 | switch (original_object->common.type) { | ||
| 123 | case ACPI_TYPE_INTEGER: | 370 | case ACPI_TYPE_INTEGER: |
| 371 | /* | ||
| 372 | * Integer-to-Buffer conversion. | ||
| 373 | * Convert the Integer to a packed-byte buffer. _MAT and other | ||
| 374 | * objects need this sometimes, if a read has been performed on a | ||
| 375 | * Field object that is less than or equal to the global integer | ||
| 376 | * size (32 or 64 bits). | ||
| 377 | */ | ||
| 378 | status = | ||
| 379 | acpi_ex_convert_to_buffer(original_object, &new_object); | ||
| 380 | if (ACPI_FAILURE(status)) { | ||
| 381 | return (status); | ||
| 382 | } | ||
| 383 | break; | ||
| 124 | 384 | ||
| 125 | /* 1) Does the method/object legally return a buffer? */ | 385 | case ACPI_TYPE_STRING: |
| 126 | 386 | ||
| 127 | if (expected_btypes & ACPI_RTYPE_BUFFER) { | 387 | /* String-to-Buffer conversion. Simple data copy */ |
| 128 | /* | 388 | |
| 129 | * Convert the Integer to a packed-byte buffer. _MAT needs | 389 | new_object = |
| 130 | * this sometimes, if a read has been performed on a Field | 390 | acpi_ut_create_buffer_object(original_object->string. |
| 131 | * object that is less than or equal to the global integer | 391 | length); |
| 132 | * size (32 or 64 bits). | 392 | if (!new_object) { |
| 133 | */ | 393 | return (AE_NO_MEMORY); |
| 134 | status = | ||
| 135 | acpi_ex_convert_to_buffer(return_object, | ||
| 136 | &new_object); | ||
| 137 | if (ACPI_FAILURE(status)) { | ||
| 138 | return (status); | ||
| 139 | } | ||
| 140 | } | 394 | } |
| 141 | 395 | ||
| 142 | /* 2) Does the method/object legally return a string? */ | 396 | ACPI_MEMCPY(new_object->buffer.pointer, |
| 397 | original_object->string.pointer, | ||
| 398 | original_object->string.length); | ||
| 399 | break; | ||
| 400 | |||
| 401 | case ACPI_TYPE_PACKAGE: | ||
| 402 | /* | ||
| 403 | * This case is often seen for predefined names that must return a | ||
| 404 | * Buffer object with multiple DWORD integers within. For example, | ||
| 405 | * _FDE and _GTM. The Package can be converted to a Buffer. | ||
| 406 | */ | ||
| 407 | |||
| 408 | /* All elements of the Package must be integers */ | ||
| 143 | 409 | ||
| 144 | else if (expected_btypes & ACPI_RTYPE_STRING) { | 410 | elements = original_object->package.elements; |
| 145 | /* | 411 | count = original_object->package.count; |
| 146 | * The only supported Integer-to-String conversion is to convert | 412 | |
| 147 | * an integer of value 0 to a NULL string. The last element of | 413 | for (i = 0; i < count; i++) { |
| 148 | * _BIF and _BIX packages occasionally need this fix. | 414 | if ((!*elements) || |
| 149 | */ | 415 | ((*elements)->common.type != ACPI_TYPE_INTEGER)) { |
| 150 | if (return_object->integer.value != 0) { | ||
| 151 | return (AE_AML_OPERAND_TYPE); | 416 | return (AE_AML_OPERAND_TYPE); |
| 152 | } | 417 | } |
| 418 | elements++; | ||
| 419 | } | ||
| 153 | 420 | ||
| 154 | /* Allocate a new NULL string object */ | 421 | /* Create the new buffer object to replace the Package */ |
| 155 | 422 | ||
| 156 | new_object = acpi_ut_create_string_object(0); | 423 | new_object = acpi_ut_create_buffer_object(ACPI_MUL_4(count)); |
| 157 | if (!new_object) { | 424 | if (!new_object) { |
| 158 | return (AE_NO_MEMORY); | 425 | return (AE_NO_MEMORY); |
| 159 | } | ||
| 160 | } else { | ||
| 161 | return (AE_AML_OPERAND_TYPE); | ||
| 162 | } | 426 | } |
| 163 | break; | ||
| 164 | 427 | ||
| 165 | default: | 428 | /* Copy the package elements (integers) to the buffer as DWORDs */ |
| 166 | 429 | ||
| 167 | /* We cannot repair this object */ | 430 | elements = original_object->package.elements; |
| 431 | dword_buffer = ACPI_CAST_PTR(u32, new_object->buffer.pointer); | ||
| 432 | |||
| 433 | for (i = 0; i < count; i++) { | ||
| 434 | *dword_buffer = (u32) (*elements)->integer.value; | ||
| 435 | dword_buffer++; | ||
| 436 | elements++; | ||
| 437 | } | ||
| 438 | break; | ||
| 168 | 439 | ||
| 440 | default: | ||
| 169 | return (AE_AML_OPERAND_TYPE); | 441 | return (AE_AML_OPERAND_TYPE); |
| 170 | } | 442 | } |
| 171 | 443 | ||
| 172 | /* Object was successfully repaired */ | 444 | *return_object = new_object; |
| 445 | return (AE_OK); | ||
| 446 | } | ||
| 173 | 447 | ||
| 174 | /* | 448 | /******************************************************************************* |
| 175 | * If the original object is a package element, we need to: | 449 | * |
| 176 | * 1. Set the reference count of the new object to match the | 450 | * FUNCTION: acpi_ns_convert_to_package |
| 177 | * reference count of the old object. | 451 | * |
| 178 | * 2. Decrement the reference count of the original object. | 452 | * PARAMETERS: original_object - Object to be converted |
| 179 | */ | 453 | * return_object - Where the new converted object is returned |
| 180 | if (package_index != ACPI_NOT_PACKAGE_ELEMENT) { | 454 | * |
| 181 | new_object->common.reference_count = | 455 | * RETURN: Status. AE_OK if conversion was successful. |
| 182 | return_object->common.reference_count; | 456 | * |
| 457 | * DESCRIPTION: Attempt to convert a Buffer object to a Package. Each byte of | ||
| 458 | * the buffer is converted to a single integer package element. | ||
| 459 | * | ||
| 460 | ******************************************************************************/ | ||
| 183 | 461 | ||
| 184 | if (return_object->common.reference_count > 1) { | 462 | static acpi_status |
| 185 | return_object->common.reference_count--; | 463 | acpi_ns_convert_to_package(union acpi_operand_object *original_object, |
| 464 | union acpi_operand_object **return_object) | ||
| 465 | { | ||
| 466 | union acpi_operand_object *new_object; | ||
| 467 | union acpi_operand_object **elements; | ||
| 468 | u32 length; | ||
| 469 | u8 *buffer; | ||
| 470 | |||
| 471 | switch (original_object->common.type) { | ||
| 472 | case ACPI_TYPE_BUFFER: | ||
| 473 | |||
| 474 | /* Buffer-to-Package conversion */ | ||
| 475 | |||
| 476 | length = original_object->buffer.length; | ||
| 477 | new_object = acpi_ut_create_package_object(length); | ||
| 478 | if (!new_object) { | ||
| 479 | return (AE_NO_MEMORY); | ||
| 186 | } | 480 | } |
| 187 | 481 | ||
| 188 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | 482 | /* Convert each buffer byte to an integer package element */ |
| 189 | "Converted %s to expected %s at index %u", | ||
| 190 | acpi_ut_get_object_type_name | ||
| 191 | (return_object), | ||
| 192 | acpi_ut_get_object_type_name(new_object), | ||
| 193 | package_index)); | ||
| 194 | } else { | ||
| 195 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | ||
| 196 | "Converted %s to expected %s", | ||
| 197 | acpi_ut_get_object_type_name | ||
| 198 | (return_object), | ||
| 199 | acpi_ut_get_object_type_name | ||
| 200 | (new_object))); | ||
| 201 | } | ||
| 202 | 483 | ||
| 203 | /* Delete old object, install the new return object */ | 484 | elements = new_object->package.elements; |
| 485 | buffer = original_object->buffer.pointer; | ||
| 204 | 486 | ||
| 205 | acpi_ut_remove_reference(return_object); | 487 | while (length--) { |
| 206 | *return_object_ptr = new_object; | 488 | *elements = |
| 207 | data->flags |= ACPI_OBJECT_REPAIRED; | 489 | acpi_ut_create_integer_object((u64) *buffer); |
| 490 | if (!*elements) { | ||
| 491 | acpi_ut_remove_reference(new_object); | ||
| 492 | return (AE_NO_MEMORY); | ||
| 493 | } | ||
| 494 | elements++; | ||
| 495 | buffer++; | ||
| 496 | } | ||
| 497 | break; | ||
| 498 | |||
| 499 | default: | ||
| 500 | return (AE_AML_OPERAND_TYPE); | ||
| 501 | } | ||
| 502 | |||
| 503 | *return_object = new_object; | ||
| 208 | return (AE_OK); | 504 | return (AE_OK); |
| 209 | } | 505 | } |
| 210 | 506 | ||
| @@ -238,6 +534,8 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data, | |||
| 238 | { | 534 | { |
| 239 | union acpi_operand_object *pkg_obj_desc; | 535 | union acpi_operand_object *pkg_obj_desc; |
| 240 | 536 | ||
| 537 | ACPI_FUNCTION_NAME(ns_repair_package_list); | ||
| 538 | |||
| 241 | /* | 539 | /* |
| 242 | * Create the new outer package and populate it. The new package will | 540 | * Create the new outer package and populate it. The new package will |
| 243 | * have a single element, the lone subpackage. | 541 | * have a single element, the lone subpackage. |
| @@ -254,8 +552,9 @@ acpi_ns_repair_package_list(struct acpi_predefined_data *data, | |||
| 254 | *obj_desc_ptr = pkg_obj_desc; | 552 | *obj_desc_ptr = pkg_obj_desc; |
| 255 | data->flags |= ACPI_OBJECT_REPAIRED; | 553 | data->flags |= ACPI_OBJECT_REPAIRED; |
| 256 | 554 | ||
| 257 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | 555 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
| 258 | "Repaired Incorrectly formed Package")); | 556 | "%s: Repaired incorrectly formed Package\n", |
| 557 | data->pathname)); | ||
| 259 | 558 | ||
| 260 | return (AE_OK); | 559 | return (AE_OK); |
| 261 | } | 560 | } |
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c index d07b68613818..f13691c1cca5 100644 --- a/drivers/acpi/acpica/nsrepair2.c +++ b/drivers/acpi/acpica/nsrepair2.c | |||
| @@ -45,6 +45,7 @@ | |||
| 45 | #include <acpi/acpi.h> | 45 | #include <acpi/acpi.h> |
| 46 | #include "accommon.h" | 46 | #include "accommon.h" |
| 47 | #include "acnamesp.h" | 47 | #include "acnamesp.h" |
| 48 | #include "acpredef.h" | ||
| 48 | 49 | ||
| 49 | #define _COMPONENT ACPI_NAMESPACE | 50 | #define _COMPONENT ACPI_NAMESPACE |
| 50 | ACPI_MODULE_NAME("nsrepair2") | 51 | ACPI_MODULE_NAME("nsrepair2") |
| @@ -74,6 +75,10 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data, | |||
| 74 | union acpi_operand_object **return_object_ptr); | 75 | union acpi_operand_object **return_object_ptr); |
| 75 | 76 | ||
| 76 | static acpi_status | 77 | static acpi_status |
| 78 | acpi_ns_repair_FDE(struct acpi_predefined_data *data, | ||
| 79 | union acpi_operand_object **return_object_ptr); | ||
| 80 | |||
| 81 | static acpi_status | ||
| 77 | acpi_ns_repair_PSS(struct acpi_predefined_data *data, | 82 | acpi_ns_repair_PSS(struct acpi_predefined_data *data, |
| 78 | union acpi_operand_object **return_object_ptr); | 83 | union acpi_operand_object **return_object_ptr); |
| 79 | 84 | ||
| @@ -89,9 +94,6 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
| 89 | u8 sort_direction, char *sort_key_name); | 94 | u8 sort_direction, char *sort_key_name); |
| 90 | 95 | ||
| 91 | static acpi_status | 96 | static acpi_status |
| 92 | acpi_ns_remove_null_elements(union acpi_operand_object *package); | ||
| 93 | |||
| 94 | static acpi_status | ||
| 95 | acpi_ns_sort_list(union acpi_operand_object **elements, | 97 | acpi_ns_sort_list(union acpi_operand_object **elements, |
| 96 | u32 count, u32 index, u8 sort_direction); | 98 | u32 count, u32 index, u8 sort_direction); |
| 97 | 99 | ||
| @@ -104,17 +106,27 @@ acpi_ns_sort_list(union acpi_operand_object **elements, | |||
| 104 | * This table contains the names of the predefined methods for which we can | 106 | * This table contains the names of the predefined methods for which we can |
| 105 | * perform more complex repairs. | 107 | * perform more complex repairs. |
| 106 | * | 108 | * |
| 107 | * _ALR: Sort the list ascending by ambient_illuminance if necessary | 109 | * As necessary: |
| 108 | * _PSS: Sort the list descending by Power if necessary | 110 | * |
| 109 | * _TSS: Sort the list descending by Power if necessary | 111 | * _ALR: Sort the list ascending by ambient_illuminance |
| 112 | * _FDE: Convert Buffer of BYTEs to a Buffer of DWORDs | ||
| 113 | * _GTM: Convert Buffer of BYTEs to a Buffer of DWORDs | ||
| 114 | * _PSS: Sort the list descending by Power | ||
| 115 | * _TSS: Sort the list descending by Power | ||
| 110 | */ | 116 | */ |
| 111 | static const struct acpi_repair_info acpi_ns_repairable_names[] = { | 117 | static const struct acpi_repair_info acpi_ns_repairable_names[] = { |
| 112 | {"_ALR", acpi_ns_repair_ALR}, | 118 | {"_ALR", acpi_ns_repair_ALR}, |
| 119 | {"_FDE", acpi_ns_repair_FDE}, | ||
| 120 | {"_GTM", acpi_ns_repair_FDE}, /* _GTM has same repair as _FDE */ | ||
| 113 | {"_PSS", acpi_ns_repair_PSS}, | 121 | {"_PSS", acpi_ns_repair_PSS}, |
| 114 | {"_TSS", acpi_ns_repair_TSS}, | 122 | {"_TSS", acpi_ns_repair_TSS}, |
| 115 | {{0, 0, 0, 0}, NULL} /* Table terminator */ | 123 | {{0, 0, 0, 0}, NULL} /* Table terminator */ |
| 116 | }; | 124 | }; |
| 117 | 125 | ||
| 126 | #define ACPI_FDE_FIELD_COUNT 5 | ||
| 127 | #define ACPI_FDE_BYTE_BUFFER_SIZE 5 | ||
| 128 | #define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * sizeof (u32)) | ||
| 129 | |||
| 118 | /****************************************************************************** | 130 | /****************************************************************************** |
| 119 | * | 131 | * |
| 120 | * FUNCTION: acpi_ns_complex_repairs | 132 | * FUNCTION: acpi_ns_complex_repairs |
| @@ -215,6 +227,94 @@ acpi_ns_repair_ALR(struct acpi_predefined_data *data, | |||
| 215 | 227 | ||
| 216 | /****************************************************************************** | 228 | /****************************************************************************** |
| 217 | * | 229 | * |
| 230 | * FUNCTION: acpi_ns_repair_FDE | ||
| 231 | * | ||
| 232 | * PARAMETERS: Data - Pointer to validation data structure | ||
| 233 | * return_object_ptr - Pointer to the object returned from the | ||
| 234 | * evaluation of a method or object | ||
| 235 | * | ||
| 236 | * RETURN: Status. AE_OK if object is OK or was repaired successfully | ||
| 237 | * | ||
| 238 | * DESCRIPTION: Repair for the _FDE and _GTM objects. The expected return | ||
| 239 | * value is a Buffer of 5 DWORDs. This function repairs a common | ||
| 240 | * problem where the return value is a Buffer of BYTEs, not | ||
| 241 | * DWORDs. | ||
| 242 | * | ||
| 243 | *****************************************************************************/ | ||
| 244 | |||
| 245 | static acpi_status | ||
| 246 | acpi_ns_repair_FDE(struct acpi_predefined_data *data, | ||
| 247 | union acpi_operand_object **return_object_ptr) | ||
| 248 | { | ||
| 249 | union acpi_operand_object *return_object = *return_object_ptr; | ||
| 250 | union acpi_operand_object *buffer_object; | ||
| 251 | u8 *byte_buffer; | ||
| 252 | u32 *dword_buffer; | ||
| 253 | u32 i; | ||
| 254 | |||
| 255 | ACPI_FUNCTION_NAME(ns_repair_FDE); | ||
| 256 | |||
| 257 | switch (return_object->common.type) { | ||
| 258 | case ACPI_TYPE_BUFFER: | ||
| 259 | |||
| 260 | /* This is the expected type. Length should be (at least) 5 DWORDs */ | ||
| 261 | |||
| 262 | if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) { | ||
| 263 | return (AE_OK); | ||
| 264 | } | ||
| 265 | |||
| 266 | /* We can only repair if we have exactly 5 BYTEs */ | ||
| 267 | |||
| 268 | if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) { | ||
| 269 | ACPI_WARN_PREDEFINED((AE_INFO, data->pathname, | ||
| 270 | data->node_flags, | ||
| 271 | "Incorrect return buffer length %u, expected %u", | ||
| 272 | return_object->buffer.length, | ||
| 273 | ACPI_FDE_DWORD_BUFFER_SIZE)); | ||
| 274 | |||
| 275 | return (AE_AML_OPERAND_TYPE); | ||
| 276 | } | ||
| 277 | |||
| 278 | /* Create the new (larger) buffer object */ | ||
| 279 | |||
| 280 | buffer_object = | ||
| 281 | acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE); | ||
| 282 | if (!buffer_object) { | ||
| 283 | return (AE_NO_MEMORY); | ||
| 284 | } | ||
| 285 | |||
| 286 | /* Expand each byte to a DWORD */ | ||
| 287 | |||
| 288 | byte_buffer = return_object->buffer.pointer; | ||
| 289 | dword_buffer = | ||
| 290 | ACPI_CAST_PTR(u32, buffer_object->buffer.pointer); | ||
| 291 | |||
| 292 | for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) { | ||
| 293 | *dword_buffer = (u32) *byte_buffer; | ||
| 294 | dword_buffer++; | ||
| 295 | byte_buffer++; | ||
| 296 | } | ||
| 297 | |||
| 298 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
| 299 | "%s Expanded Byte Buffer to expected DWord Buffer\n", | ||
| 300 | data->pathname)); | ||
| 301 | break; | ||
| 302 | |||
| 303 | default: | ||
| 304 | return (AE_AML_OPERAND_TYPE); | ||
| 305 | } | ||
| 306 | |||
| 307 | /* Delete the original return object, return the new buffer object */ | ||
| 308 | |||
| 309 | acpi_ut_remove_reference(return_object); | ||
| 310 | *return_object_ptr = buffer_object; | ||
| 311 | |||
| 312 | data->flags |= ACPI_OBJECT_REPAIRED; | ||
| 313 | return (AE_OK); | ||
| 314 | } | ||
| 315 | |||
| 316 | /****************************************************************************** | ||
| 317 | * | ||
| 218 | * FUNCTION: acpi_ns_repair_TSS | 318 | * FUNCTION: acpi_ns_repair_TSS |
| 219 | * | 319 | * |
| 220 | * PARAMETERS: Data - Pointer to validation data structure | 320 | * PARAMETERS: Data - Pointer to validation data structure |
| @@ -345,6 +445,8 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
| 345 | u32 previous_value; | 445 | u32 previous_value; |
| 346 | acpi_status status; | 446 | acpi_status status; |
| 347 | 447 | ||
| 448 | ACPI_FUNCTION_NAME(ns_check_sorted_list); | ||
| 449 | |||
| 348 | /* The top-level object must be a package */ | 450 | /* The top-level object must be a package */ |
| 349 | 451 | ||
| 350 | if (return_object->common.type != ACPI_TYPE_PACKAGE) { | 452 | if (return_object->common.type != ACPI_TYPE_PACKAGE) { |
| @@ -352,24 +454,10 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
| 352 | } | 454 | } |
| 353 | 455 | ||
| 354 | /* | 456 | /* |
| 355 | * Detect any NULL package elements and remove them from the | 457 | * NOTE: assumes list of sub-packages contains no NULL elements. |
| 356 | * package. | 458 | * Any NULL elements should have been removed by earlier call |
| 357 | * | 459 | * to acpi_ns_remove_null_elements. |
| 358 | * TBD: We may want to do this for all predefined names that | ||
| 359 | * return a variable-length package of packages. | ||
| 360 | */ | 460 | */ |
| 361 | status = acpi_ns_remove_null_elements(return_object); | ||
| 362 | if (status == AE_NULL_ENTRY) { | ||
| 363 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, data->node_flags, | ||
| 364 | "NULL elements removed from package")); | ||
| 365 | |||
| 366 | /* Exit if package is now zero length */ | ||
| 367 | |||
| 368 | if (!return_object->package.count) { | ||
| 369 | return (AE_NULL_ENTRY); | ||
| 370 | } | ||
| 371 | } | ||
| 372 | |||
| 373 | outer_elements = return_object->package.elements; | 461 | outer_elements = return_object->package.elements; |
| 374 | outer_element_count = return_object->package.count; | 462 | outer_element_count = return_object->package.count; |
| 375 | if (!outer_element_count) { | 463 | if (!outer_element_count) { |
| @@ -422,10 +510,9 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
| 422 | 510 | ||
| 423 | data->flags |= ACPI_OBJECT_REPAIRED; | 511 | data->flags |= ACPI_OBJECT_REPAIRED; |
| 424 | 512 | ||
| 425 | ACPI_INFO_PREDEFINED((AE_INFO, data->pathname, | 513 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, |
| 426 | data->node_flags, | 514 | "%s: Repaired unsorted list - now sorted by %s\n", |
| 427 | "Repaired unsorted list - now sorted by %s", | 515 | data->pathname, sort_key_name)); |
| 428 | sort_key_name)); | ||
| 429 | return (AE_OK); | 516 | return (AE_OK); |
| 430 | } | 517 | } |
| 431 | 518 | ||
| @@ -440,36 +527,63 @@ acpi_ns_check_sorted_list(struct acpi_predefined_data *data, | |||
| 440 | * | 527 | * |
| 441 | * FUNCTION: acpi_ns_remove_null_elements | 528 | * FUNCTION: acpi_ns_remove_null_elements |
| 442 | * | 529 | * |
| 443 | * PARAMETERS: obj_desc - A Package object | 530 | * PARAMETERS: Data - Pointer to validation data structure |
| 531 | * package_type - An acpi_return_package_types value | ||
| 532 | * obj_desc - A Package object | ||
| 444 | * | 533 | * |
| 445 | * RETURN: Status. AE_NULL_ENTRY means that one or more elements were | 534 | * RETURN: None. |
| 446 | * removed. | ||
| 447 | * | 535 | * |
| 448 | * DESCRIPTION: Remove all NULL package elements and update the package count. | 536 | * DESCRIPTION: Remove all NULL package elements from packages that contain |
| 537 | * a variable number of sub-packages. | ||
| 449 | * | 538 | * |
| 450 | *****************************************************************************/ | 539 | *****************************************************************************/ |
| 451 | 540 | ||
| 452 | static acpi_status | 541 | void |
| 453 | acpi_ns_remove_null_elements(union acpi_operand_object *obj_desc) | 542 | acpi_ns_remove_null_elements(struct acpi_predefined_data *data, |
| 543 | u8 package_type, | ||
| 544 | union acpi_operand_object *obj_desc) | ||
| 454 | { | 545 | { |
| 455 | union acpi_operand_object **source; | 546 | union acpi_operand_object **source; |
| 456 | union acpi_operand_object **dest; | 547 | union acpi_operand_object **dest; |
| 457 | acpi_status status = AE_OK; | ||
| 458 | u32 count; | 548 | u32 count; |
| 459 | u32 new_count; | 549 | u32 new_count; |
| 460 | u32 i; | 550 | u32 i; |
| 461 | 551 | ||
| 552 | ACPI_FUNCTION_NAME(ns_remove_null_elements); | ||
| 553 | |||
| 554 | /* | ||
| 555 | * PTYPE1 packages contain no subpackages. | ||
| 556 | * PTYPE2 packages contain a variable number of sub-packages. We can | ||
| 557 | * safely remove all NULL elements from the PTYPE2 packages. | ||
| 558 | */ | ||
| 559 | switch (package_type) { | ||
| 560 | case ACPI_PTYPE1_FIXED: | ||
| 561 | case ACPI_PTYPE1_VAR: | ||
| 562 | case ACPI_PTYPE1_OPTION: | ||
| 563 | return; | ||
| 564 | |||
| 565 | case ACPI_PTYPE2: | ||
| 566 | case ACPI_PTYPE2_COUNT: | ||
| 567 | case ACPI_PTYPE2_PKG_COUNT: | ||
| 568 | case ACPI_PTYPE2_FIXED: | ||
| 569 | case ACPI_PTYPE2_MIN: | ||
| 570 | case ACPI_PTYPE2_REV_FIXED: | ||
| 571 | break; | ||
| 572 | |||
| 573 | default: | ||
| 574 | return; | ||
| 575 | } | ||
| 576 | |||
| 462 | count = obj_desc->package.count; | 577 | count = obj_desc->package.count; |
| 463 | new_count = count; | 578 | new_count = count; |
| 464 | 579 | ||
| 465 | source = obj_desc->package.elements; | 580 | source = obj_desc->package.elements; |
| 466 | dest = source; | 581 | dest = source; |
| 467 | 582 | ||
| 468 | /* Examine all elements of the package object */ | 583 | /* Examine all elements of the package object, remove nulls */ |
| 469 | 584 | ||
| 470 | for (i = 0; i < count; i++) { | 585 | for (i = 0; i < count; i++) { |
| 471 | if (!*source) { | 586 | if (!*source) { |
| 472 | status = AE_NULL_ENTRY; | ||
| 473 | new_count--; | 587 | new_count--; |
| 474 | } else { | 588 | } else { |
| 475 | *dest = *source; | 589 | *dest = *source; |
| @@ -478,15 +592,18 @@ acpi_ns_remove_null_elements(union acpi_operand_object *obj_desc) | |||
| 478 | source++; | 592 | source++; |
| 479 | } | 593 | } |
| 480 | 594 | ||
| 481 | if (status == AE_NULL_ENTRY) { | 595 | /* Update parent package if any null elements were removed */ |
| 596 | |||
| 597 | if (new_count < count) { | ||
| 598 | ACPI_DEBUG_PRINT((ACPI_DB_REPAIR, | ||
| 599 | "%s: Found and removed %u NULL elements\n", | ||
| 600 | data->pathname, (count - new_count))); | ||
| 482 | 601 | ||
| 483 | /* NULL terminate list and update the package count */ | 602 | /* NULL terminate list and update the package count */ |
| 484 | 603 | ||
| 485 | *dest = NULL; | 604 | *dest = NULL; |
| 486 | obj_desc->package.count = new_count; | 605 | obj_desc->package.count = new_count; |
| 487 | } | 606 | } |
| 488 | |||
| 489 | return (status); | ||
| 490 | } | 607 | } |
| 491 | 608 | ||
| 492 | /****************************************************************************** | 609 | /****************************************************************************** |
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c index ea55ab4f9849..47d91e668a1b 100644 --- a/drivers/acpi/acpica/nsutils.c +++ b/drivers/acpi/acpica/nsutils.c | |||
| @@ -671,24 +671,25 @@ acpi_ns_externalize_name(u32 internal_name_length, | |||
| 671 | 671 | ||
| 672 | /******************************************************************************* | 672 | /******************************************************************************* |
| 673 | * | 673 | * |
| 674 | * FUNCTION: acpi_ns_map_handle_to_node | 674 | * FUNCTION: acpi_ns_validate_handle |
| 675 | * | 675 | * |
| 676 | * PARAMETERS: Handle - Handle to be converted to an Node | 676 | * PARAMETERS: Handle - Handle to be validated and typecast to a |
| 677 | * namespace node. | ||
| 677 | * | 678 | * |
| 678 | * RETURN: A Name table entry pointer | 679 | * RETURN: A pointer to a namespace node |
| 679 | * | 680 | * |
| 680 | * DESCRIPTION: Convert a namespace handle to a real Node | 681 | * DESCRIPTION: Convert a namespace handle to a namespace node. Handles special |
| 682 | * cases for the root node. | ||
| 681 | * | 683 | * |
| 682 | * Note: Real integer handles would allow for more verification | 684 | * NOTE: Real integer handles would allow for more verification |
| 683 | * and keep all pointers within this subsystem - however this introduces | 685 | * and keep all pointers within this subsystem - however this introduces |
| 684 | * more (and perhaps unnecessary) overhead. | 686 | * more overhead and has not been necessary to this point. Drivers |
| 685 | * | 687 | * holding handles are typically notified before a node becomes invalid |
| 686 | * The current implemenation is basically a placeholder until such time comes | 688 | * due to a table unload. |
| 687 | * that it is needed. | ||
| 688 | * | 689 | * |
| 689 | ******************************************************************************/ | 690 | ******************************************************************************/ |
| 690 | 691 | ||
| 691 | struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) | 692 | struct acpi_namespace_node *acpi_ns_validate_handle(acpi_handle handle) |
| 692 | { | 693 | { |
| 693 | 694 | ||
| 694 | ACPI_FUNCTION_ENTRY(); | 695 | ACPI_FUNCTION_ENTRY(); |
| @@ -710,42 +711,6 @@ struct acpi_namespace_node *acpi_ns_map_handle_to_node(acpi_handle handle) | |||
| 710 | 711 | ||
| 711 | /******************************************************************************* | 712 | /******************************************************************************* |
| 712 | * | 713 | * |
| 713 | * FUNCTION: acpi_ns_convert_entry_to_handle | ||
| 714 | * | ||
| 715 | * PARAMETERS: Node - Node to be converted to a Handle | ||
| 716 | * | ||
| 717 | * RETURN: A user handle | ||
| 718 | * | ||
| 719 | * DESCRIPTION: Convert a real Node to a namespace handle | ||
| 720 | * | ||
| 721 | ******************************************************************************/ | ||
| 722 | |||
| 723 | acpi_handle acpi_ns_convert_entry_to_handle(struct acpi_namespace_node *node) | ||
| 724 | { | ||
| 725 | |||
| 726 | /* | ||
| 727 | * Simple implementation for now; | ||
| 728 | */ | ||
| 729 | return ((acpi_handle) node); | ||
| 730 | |||
| 731 | /* Example future implementation --------------------- | ||
| 732 | |||
| 733 | if (!Node) | ||
| 734 | { | ||
| 735 | return (NULL); | ||
| 736 | } | ||
| 737 | |||
| 738 | if (Node == acpi_gbl_root_node) | ||
| 739 | { | ||
| 740 | return (ACPI_ROOT_OBJECT); | ||
| 741 | } | ||
| 742 | |||
| 743 | return ((acpi_handle) Node); | ||
| 744 | ------------------------------------------------------*/ | ||
| 745 | } | ||
| 746 | |||
| 747 | /******************************************************************************* | ||
| 748 | * | ||
| 749 | * FUNCTION: acpi_ns_terminate | 714 | * FUNCTION: acpi_ns_terminate |
| 750 | * | 715 | * |
| 751 | * PARAMETERS: none | 716 | * PARAMETERS: none |
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c index f2bd1da77001..f0c0892bc7e5 100644 --- a/drivers/acpi/acpica/nsxfeval.c +++ b/drivers/acpi/acpica/nsxfeval.c | |||
| @@ -190,7 +190,7 @@ acpi_evaluate_object(acpi_handle handle, | |||
| 190 | 190 | ||
| 191 | /* Convert and validate the device handle */ | 191 | /* Convert and validate the device handle */ |
| 192 | 192 | ||
| 193 | info->prefix_node = acpi_ns_map_handle_to_node(handle); | 193 | info->prefix_node = acpi_ns_validate_handle(handle); |
| 194 | if (!info->prefix_node) { | 194 | if (!info->prefix_node) { |
| 195 | status = AE_BAD_PARAMETER; | 195 | status = AE_BAD_PARAMETER; |
| 196 | goto cleanup; | 196 | goto cleanup; |
| @@ -552,7 +552,7 @@ acpi_ns_get_device_callback(acpi_handle obj_handle, | |||
| 552 | return (status); | 552 | return (status); |
| 553 | } | 553 | } |
| 554 | 554 | ||
| 555 | node = acpi_ns_map_handle_to_node(obj_handle); | 555 | node = acpi_ns_validate_handle(obj_handle); |
| 556 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 556 | status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
| 557 | if (ACPI_FAILURE(status)) { | 557 | if (ACPI_FAILURE(status)) { |
| 558 | return (status); | 558 | return (status); |
| @@ -729,7 +729,7 @@ acpi_attach_data(acpi_handle obj_handle, | |||
| 729 | 729 | ||
| 730 | /* Convert and validate the handle */ | 730 | /* Convert and validate the handle */ |
| 731 | 731 | ||
| 732 | node = acpi_ns_map_handle_to_node(obj_handle); | 732 | node = acpi_ns_validate_handle(obj_handle); |
| 733 | if (!node) { | 733 | if (!node) { |
| 734 | status = AE_BAD_PARAMETER; | 734 | status = AE_BAD_PARAMETER; |
| 735 | goto unlock_and_exit; | 735 | goto unlock_and_exit; |
| @@ -775,7 +775,7 @@ acpi_detach_data(acpi_handle obj_handle, acpi_object_handler handler) | |||
| 775 | 775 | ||
| 776 | /* Convert and validate the handle */ | 776 | /* Convert and validate the handle */ |
| 777 | 777 | ||
| 778 | node = acpi_ns_map_handle_to_node(obj_handle); | 778 | node = acpi_ns_validate_handle(obj_handle); |
| 779 | if (!node) { | 779 | if (!node) { |
| 780 | status = AE_BAD_PARAMETER; | 780 | status = AE_BAD_PARAMETER; |
| 781 | goto unlock_and_exit; | 781 | goto unlock_and_exit; |
| @@ -822,7 +822,7 @@ acpi_get_data(acpi_handle obj_handle, acpi_object_handler handler, void **data) | |||
| 822 | 822 | ||
| 823 | /* Convert and validate the handle */ | 823 | /* Convert and validate the handle */ |
| 824 | 824 | ||
| 825 | node = acpi_ns_map_handle_to_node(obj_handle); | 825 | node = acpi_ns_validate_handle(obj_handle); |
| 826 | if (!node) { | 826 | if (!node) { |
| 827 | status = AE_BAD_PARAMETER; | 827 | status = AE_BAD_PARAMETER; |
| 828 | goto unlock_and_exit; | 828 | goto unlock_and_exit; |
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c index ddc84af6336e..e611dd961b20 100644 --- a/drivers/acpi/acpica/nsxfname.c +++ b/drivers/acpi/acpica/nsxfname.c | |||
| @@ -93,7 +93,7 @@ acpi_get_handle(acpi_handle parent, | |||
| 93 | /* Convert a parent handle to a prefix node */ | 93 | /* Convert a parent handle to a prefix node */ |
| 94 | 94 | ||
| 95 | if (parent) { | 95 | if (parent) { |
| 96 | prefix_node = acpi_ns_map_handle_to_node(parent); | 96 | prefix_node = acpi_ns_validate_handle(parent); |
| 97 | if (!prefix_node) { | 97 | if (!prefix_node) { |
| 98 | return (AE_BAD_PARAMETER); | 98 | return (AE_BAD_PARAMETER); |
| 99 | } | 99 | } |
| @@ -114,7 +114,7 @@ acpi_get_handle(acpi_handle parent, | |||
| 114 | 114 | ||
| 115 | if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { | 115 | if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) { |
| 116 | *ret_handle = | 116 | *ret_handle = |
| 117 | acpi_ns_convert_entry_to_handle(acpi_gbl_root_node); | 117 | ACPI_CAST_PTR(acpi_handle, acpi_gbl_root_node); |
| 118 | return (AE_OK); | 118 | return (AE_OK); |
| 119 | } | 119 | } |
| 120 | } else if (!prefix_node) { | 120 | } else if (!prefix_node) { |
| @@ -129,7 +129,7 @@ acpi_get_handle(acpi_handle parent, | |||
| 129 | status = | 129 | status = |
| 130 | acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); | 130 | acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node); |
| 131 | if (ACPI_SUCCESS(status)) { | 131 | if (ACPI_SUCCESS(status)) { |
| 132 | *ret_handle = acpi_ns_convert_entry_to_handle(node); | 132 | *ret_handle = ACPI_CAST_PTR(acpi_handle, node); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | return (status); | 135 | return (status); |
| @@ -186,7 +186,7 @@ acpi_get_name(acpi_handle handle, u32 name_type, struct acpi_buffer * buffer) | |||
| 186 | return (status); | 186 | return (status); |
| 187 | } | 187 | } |
| 188 | 188 | ||
| 189 | node = acpi_ns_map_handle_to_node(handle); | 189 | node = acpi_ns_validate_handle(handle); |
| 190 | if (!node) { | 190 | if (!node) { |
| 191 | status = AE_BAD_PARAMETER; | 191 | status = AE_BAD_PARAMETER; |
| 192 | goto unlock_and_exit; | 192 | goto unlock_and_exit; |
| @@ -291,7 +291,7 @@ acpi_get_object_info(acpi_handle handle, | |||
| 291 | goto cleanup; | 291 | goto cleanup; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | node = acpi_ns_map_handle_to_node(handle); | 294 | node = acpi_ns_validate_handle(handle); |
| 295 | if (!node) { | 295 | if (!node) { |
| 296 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 296 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
| 297 | return (AE_BAD_PARAMETER); | 297 | return (AE_BAD_PARAMETER); |
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c index 4071bad4458e..0cc6ba01a495 100644 --- a/drivers/acpi/acpica/nsxfobj.c +++ b/drivers/acpi/acpica/nsxfobj.c | |||
| @@ -79,7 +79,7 @@ acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id) | |||
| 79 | 79 | ||
| 80 | /* Convert and validate the handle */ | 80 | /* Convert and validate the handle */ |
| 81 | 81 | ||
| 82 | node = acpi_ns_map_handle_to_node(handle); | 82 | node = acpi_ns_validate_handle(handle); |
| 83 | if (!node) { | 83 | if (!node) { |
| 84 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 84 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
| 85 | return (AE_BAD_PARAMETER); | 85 | return (AE_BAD_PARAMETER); |
| @@ -132,7 +132,7 @@ acpi_status acpi_get_type(acpi_handle handle, acpi_object_type * ret_type) | |||
| 132 | 132 | ||
| 133 | /* Convert and validate the handle */ | 133 | /* Convert and validate the handle */ |
| 134 | 134 | ||
| 135 | node = acpi_ns_map_handle_to_node(handle); | 135 | node = acpi_ns_validate_handle(handle); |
| 136 | if (!node) { | 136 | if (!node) { |
| 137 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); | 137 | (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); |
| 138 | return (AE_BAD_PARAMETER); | 138 | return (AE_BAD_PARAMETER); |
| @@ -182,7 +182,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) | |||
| 182 | 182 | ||
| 183 | /* Convert and validate the handle */ | 183 | /* Convert and validate the handle */ |
| 184 | 184 | ||
| 185 | node = acpi_ns_map_handle_to_node(handle); | 185 | node = acpi_ns_validate_handle(handle); |
| 186 | if (!node) { | 186 | if (!node) { |
| 187 | status = AE_BAD_PARAMETER; | 187 | status = AE_BAD_PARAMETER; |
| 188 | goto unlock_and_exit; | 188 | goto unlock_and_exit; |
| @@ -191,7 +191,7 @@ acpi_status acpi_get_parent(acpi_handle handle, acpi_handle * ret_handle) | |||
| 191 | /* Get the parent entry */ | 191 | /* Get the parent entry */ |
| 192 | 192 | ||
| 193 | parent_node = acpi_ns_get_parent_node(node); | 193 | parent_node = acpi_ns_get_parent_node(node); |
| 194 | *ret_handle = acpi_ns_convert_entry_to_handle(parent_node); | 194 | *ret_handle = ACPI_CAST_PTR(acpi_handle, parent_node); |
| 195 | 195 | ||
| 196 | /* Return exception if parent is null */ | 196 | /* Return exception if parent is null */ |
| 197 | 197 | ||
| @@ -251,7 +251,7 @@ acpi_get_next_object(acpi_object_type type, | |||
| 251 | 251 | ||
| 252 | /* Start search at the beginning of the specified scope */ | 252 | /* Start search at the beginning of the specified scope */ |
| 253 | 253 | ||
| 254 | parent_node = acpi_ns_map_handle_to_node(parent); | 254 | parent_node = acpi_ns_validate_handle(parent); |
| 255 | if (!parent_node) { | 255 | if (!parent_node) { |
| 256 | status = AE_BAD_PARAMETER; | 256 | status = AE_BAD_PARAMETER; |
| 257 | goto unlock_and_exit; | 257 | goto unlock_and_exit; |
| @@ -260,7 +260,7 @@ acpi_get_next_object(acpi_object_type type, | |||
| 260 | /* Non-null handle, ignore the parent */ | 260 | /* Non-null handle, ignore the parent */ |
| 261 | /* Convert and validate the handle */ | 261 | /* Convert and validate the handle */ |
| 262 | 262 | ||
| 263 | child_node = acpi_ns_map_handle_to_node(child); | 263 | child_node = acpi_ns_validate_handle(child); |
| 264 | if (!child_node) { | 264 | if (!child_node) { |
| 265 | status = AE_BAD_PARAMETER; | 265 | status = AE_BAD_PARAMETER; |
| 266 | goto unlock_and_exit; | 266 | goto unlock_and_exit; |
| @@ -276,7 +276,7 @@ acpi_get_next_object(acpi_object_type type, | |||
| 276 | } | 276 | } |
| 277 | 277 | ||
| 278 | if (ret_handle) { | 278 | if (ret_handle) { |
| 279 | *ret_handle = acpi_ns_convert_entry_to_handle(node); | 279 | *ret_handle = ACPI_CAST_PTR(acpi_handle, node); |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | unlock_and_exit: | 282 | unlock_and_exit: |
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c index 12934ad6da8e..d0c1b91eb8ca 100644 --- a/drivers/acpi/acpica/psxface.c +++ b/drivers/acpi/acpica/psxface.c | |||
| @@ -287,7 +287,8 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info) | |||
| 287 | /* Invoke an internal method if necessary */ | 287 | /* Invoke an internal method if necessary */ |
| 288 | 288 | ||
| 289 | if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { | 289 | if (info->obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY) { |
| 290 | status = info->obj_desc->method.implementation(walk_state); | 290 | status = |
| 291 | info->obj_desc->method.extra.implementation(walk_state); | ||
| 291 | info->return_object = walk_state->return_desc; | 292 | info->return_object = walk_state->return_desc; |
| 292 | 293 | ||
| 293 | /* Cleanup states */ | 294 | /* Cleanup states */ |
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c index 395212bcd19b..f27feb4772f6 100644 --- a/drivers/acpi/acpica/rsxface.c +++ b/drivers/acpi/acpica/rsxface.c | |||
| @@ -104,7 +104,7 @@ acpi_rs_validate_parameters(acpi_handle device_handle, | |||
| 104 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 104 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
| 105 | } | 105 | } |
| 106 | 106 | ||
| 107 | node = acpi_ns_map_handle_to_node(device_handle); | 107 | node = acpi_ns_validate_handle(device_handle); |
| 108 | if (!node) { | 108 | if (!node) { |
| 109 | return_ACPI_STATUS(AE_BAD_PARAMETER); | 109 | return_ACPI_STATUS(AE_BAD_PARAMETER); |
| 110 | } | 110 | } |
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c index 0f0c64bf8ac9..f857c5efb79f 100644 --- a/drivers/acpi/acpica/utcopy.c +++ b/drivers/acpi/acpica/utcopy.c | |||
| @@ -323,11 +323,11 @@ acpi_ut_copy_ielement_to_eelement(u8 object_type, | |||
| 323 | * RETURN: Status | 323 | * RETURN: Status |
| 324 | * | 324 | * |
| 325 | * DESCRIPTION: This function is called to place a package object in a user | 325 | * DESCRIPTION: This function is called to place a package object in a user |
| 326 | * buffer. A package object by definition contains other objects. | 326 | * buffer. A package object by definition contains other objects. |
| 327 | * | 327 | * |
| 328 | * The buffer is assumed to have sufficient space for the object. | 328 | * The buffer is assumed to have sufficient space for the object. |
| 329 | * The caller must have verified the buffer length needed using the | 329 | * The caller must have verified the buffer length needed using |
| 330 | * acpi_ut_get_object_size function before calling this function. | 330 | * the acpi_ut_get_object_size function before calling this function. |
| 331 | * | 331 | * |
| 332 | ******************************************************************************/ | 332 | ******************************************************************************/ |
| 333 | 333 | ||
| @@ -382,12 +382,12 @@ acpi_ut_copy_ipackage_to_epackage(union acpi_operand_object *internal_object, | |||
| 382 | * FUNCTION: acpi_ut_copy_iobject_to_eobject | 382 | * FUNCTION: acpi_ut_copy_iobject_to_eobject |
| 383 | * | 383 | * |
| 384 | * PARAMETERS: internal_object - The internal object to be converted | 384 | * PARAMETERS: internal_object - The internal object to be converted |
| 385 | * buffer_ptr - Where the object is returned | 385 | * ret_buffer - Where the object is returned |
| 386 | * | 386 | * |
| 387 | * RETURN: Status | 387 | * RETURN: Status |
| 388 | * | 388 | * |
| 389 | * DESCRIPTION: This function is called to build an API object to be returned to | 389 | * DESCRIPTION: This function is called to build an API object to be returned |
| 390 | * the caller. | 390 | * to the caller. |
| 391 | * | 391 | * |
| 392 | ******************************************************************************/ | 392 | ******************************************************************************/ |
| 393 | 393 | ||
| @@ -626,7 +626,7 @@ acpi_ut_copy_epackage_to_ipackage(union acpi_object *external_object, | |||
| 626 | * PARAMETERS: external_object - The external object to be converted | 626 | * PARAMETERS: external_object - The external object to be converted |
| 627 | * internal_object - Where the internal object is returned | 627 | * internal_object - Where the internal object is returned |
| 628 | * | 628 | * |
| 629 | * RETURN: Status - the status of the call | 629 | * RETURN: Status |
| 630 | * | 630 | * |
| 631 | * DESCRIPTION: Converts an external object to an internal object. | 631 | * DESCRIPTION: Converts an external object to an internal object. |
| 632 | * | 632 | * |
| @@ -665,7 +665,7 @@ acpi_ut_copy_eobject_to_iobject(union acpi_object *external_object, | |||
| 665 | * | 665 | * |
| 666 | * RETURN: Status | 666 | * RETURN: Status |
| 667 | * | 667 | * |
| 668 | * DESCRIPTION: Simple copy of one internal object to another. Reference count | 668 | * DESCRIPTION: Simple copy of one internal object to another. Reference count |
| 669 | * of the destination object is preserved. | 669 | * of the destination object is preserved. |
| 670 | * | 670 | * |
| 671 | ******************************************************************************/ | 671 | ******************************************************************************/ |
| @@ -897,10 +897,11 @@ acpi_ut_copy_ielement_to_ielement(u8 object_type, | |||
| 897 | * | 897 | * |
| 898 | * FUNCTION: acpi_ut_copy_ipackage_to_ipackage | 898 | * FUNCTION: acpi_ut_copy_ipackage_to_ipackage |
| 899 | * | 899 | * |
| 900 | * PARAMETERS: *source_obj - Pointer to the source package object | 900 | * PARAMETERS: source_obj - Pointer to the source package object |
| 901 | * *dest_obj - Where the internal object is returned | 901 | * dest_obj - Where the internal object is returned |
| 902 | * walk_state - Current Walk state descriptor | ||
| 902 | * | 903 | * |
| 903 | * RETURN: Status - the status of the call | 904 | * RETURN: Status |
| 904 | * | 905 | * |
| 905 | * DESCRIPTION: This function is called to copy an internal package object | 906 | * DESCRIPTION: This function is called to copy an internal package object |
| 906 | * into another internal package object. | 907 | * into another internal package object. |
| @@ -953,9 +954,9 @@ acpi_ut_copy_ipackage_to_ipackage(union acpi_operand_object *source_obj, | |||
| 953 | * | 954 | * |
| 954 | * FUNCTION: acpi_ut_copy_iobject_to_iobject | 955 | * FUNCTION: acpi_ut_copy_iobject_to_iobject |
| 955 | * | 956 | * |
| 956 | * PARAMETERS: walk_state - Current walk state | 957 | * PARAMETERS: source_desc - The internal object to be copied |
| 957 | * source_desc - The internal object to be copied | ||
| 958 | * dest_desc - Where the copied object is returned | 958 | * dest_desc - Where the copied object is returned |
| 959 | * walk_state - Current walk state | ||
| 959 | * | 960 | * |
| 960 | * RETURN: Status | 961 | * RETURN: Status |
| 961 | * | 962 | * |
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 3f4602b8f287..cada73ffdfa7 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c | |||
| @@ -831,7 +831,7 @@ static void acpi_battery_notify(struct acpi_device *device, u32 event) | |||
| 831 | dev_name(&device->dev), event, | 831 | dev_name(&device->dev), event, |
| 832 | acpi_battery_present(battery)); | 832 | acpi_battery_present(battery)); |
| 833 | #ifdef CONFIG_ACPI_SYSFS_POWER | 833 | #ifdef CONFIG_ACPI_SYSFS_POWER |
| 834 | /* acpi_batter_update could remove power_supply object */ | 834 | /* acpi_battery_update could remove power_supply object */ |
| 835 | if (battery->bat.dev) | 835 | if (battery->bat.dev) |
| 836 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); | 836 | kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE); |
| 837 | #endif | 837 | #endif |
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 741191524353..65f7e335f122 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
| @@ -344,6 +344,152 @@ bool acpi_bus_can_wakeup(acpi_handle handle) | |||
| 344 | 344 | ||
| 345 | EXPORT_SYMBOL(acpi_bus_can_wakeup); | 345 | EXPORT_SYMBOL(acpi_bus_can_wakeup); |
| 346 | 346 | ||
| 347 | static void acpi_print_osc_error(acpi_handle handle, | ||
| 348 | struct acpi_osc_context *context, char *error) | ||
| 349 | { | ||
| 350 | struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER}; | ||
| 351 | int i; | ||
| 352 | |||
| 353 | if (ACPI_FAILURE(acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer))) | ||
| 354 | printk(KERN_DEBUG "%s\n", error); | ||
| 355 | else { | ||
| 356 | printk(KERN_DEBUG "%s:%s\n", (char *)buffer.pointer, error); | ||
| 357 | kfree(buffer.pointer); | ||
| 358 | } | ||
| 359 | printk(KERN_DEBUG"_OSC request data:"); | ||
| 360 | for (i = 0; i < context->cap.length; i += sizeof(u32)) | ||
| 361 | printk("%x ", *((u32 *)(context->cap.pointer + i))); | ||
| 362 | printk("\n"); | ||
| 363 | } | ||
| 364 | |||
| 365 | static u8 hex_val(unsigned char c) | ||
| 366 | { | ||
| 367 | return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10; | ||
| 368 | } | ||
| 369 | |||
| 370 | static acpi_status acpi_str_to_uuid(char *str, u8 *uuid) | ||
| 371 | { | ||
| 372 | int i; | ||
| 373 | static int opc_map_to_uuid[16] = {6, 4, 2, 0, 11, 9, 16, 14, 19, 21, | ||
| 374 | 24, 26, 28, 30, 32, 34}; | ||
| 375 | |||
| 376 | if (strlen(str) != 36) | ||
| 377 | return AE_BAD_PARAMETER; | ||
| 378 | for (i = 0; i < 36; i++) { | ||
| 379 | if (i == 8 || i == 13 || i == 18 || i == 23) { | ||
| 380 | if (str[i] != '-') | ||
| 381 | return AE_BAD_PARAMETER; | ||
| 382 | } else if (!isxdigit(str[i])) | ||
| 383 | return AE_BAD_PARAMETER; | ||
| 384 | } | ||
| 385 | for (i = 0; i < 16; i++) { | ||
| 386 | uuid[i] = hex_val(str[opc_map_to_uuid[i]]) << 4; | ||
| 387 | uuid[i] |= hex_val(str[opc_map_to_uuid[i] + 1]); | ||
| 388 | } | ||
| 389 | return AE_OK; | ||
| 390 | } | ||
| 391 | |||
| 392 | acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context) | ||
| 393 | { | ||
| 394 | acpi_status status; | ||
| 395 | struct acpi_object_list input; | ||
| 396 | union acpi_object in_params[4]; | ||
| 397 | union acpi_object *out_obj; | ||
| 398 | u8 uuid[16]; | ||
| 399 | u32 errors; | ||
| 400 | |||
| 401 | if (!context) | ||
| 402 | return AE_ERROR; | ||
| 403 | if (ACPI_FAILURE(acpi_str_to_uuid(context->uuid_str, uuid))) | ||
| 404 | return AE_ERROR; | ||
| 405 | context->ret.length = ACPI_ALLOCATE_BUFFER; | ||
| 406 | context->ret.pointer = NULL; | ||
| 407 | |||
| 408 | /* Setting up input parameters */ | ||
| 409 | input.count = 4; | ||
| 410 | input.pointer = in_params; | ||
| 411 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
| 412 | in_params[0].buffer.length = 16; | ||
| 413 | in_params[0].buffer.pointer = uuid; | ||
| 414 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
| 415 | in_params[1].integer.value = context->rev; | ||
| 416 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
| 417 | in_params[2].integer.value = context->cap.length/sizeof(u32); | ||
| 418 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
| 419 | in_params[3].buffer.length = context->cap.length; | ||
| 420 | in_params[3].buffer.pointer = context->cap.pointer; | ||
| 421 | |||
| 422 | status = acpi_evaluate_object(handle, "_OSC", &input, &context->ret); | ||
| 423 | if (ACPI_FAILURE(status)) | ||
| 424 | return status; | ||
| 425 | |||
| 426 | /* return buffer should have the same length as cap buffer */ | ||
| 427 | if (context->ret.length != context->cap.length) | ||
| 428 | return AE_NULL_OBJECT; | ||
| 429 | |||
| 430 | out_obj = context->ret.pointer; | ||
| 431 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
| 432 | acpi_print_osc_error(handle, context, | ||
| 433 | "_OSC evaluation returned wrong type"); | ||
| 434 | status = AE_TYPE; | ||
| 435 | goto out_kfree; | ||
| 436 | } | ||
| 437 | /* Need to ignore the bit0 in result code */ | ||
| 438 | errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); | ||
| 439 | if (errors) { | ||
| 440 | if (errors & OSC_REQUEST_ERROR) | ||
| 441 | acpi_print_osc_error(handle, context, | ||
| 442 | "_OSC request failed"); | ||
| 443 | if (errors & OSC_INVALID_UUID_ERROR) | ||
| 444 | acpi_print_osc_error(handle, context, | ||
| 445 | "_OSC invalid UUID"); | ||
| 446 | if (errors & OSC_INVALID_REVISION_ERROR) | ||
| 447 | acpi_print_osc_error(handle, context, | ||
| 448 | "_OSC invalid revision"); | ||
| 449 | if (errors & OSC_CAPABILITIES_MASK_ERROR) { | ||
| 450 | if (((u32 *)context->cap.pointer)[OSC_QUERY_TYPE] | ||
| 451 | & OSC_QUERY_ENABLE) | ||
| 452 | goto out_success; | ||
| 453 | status = AE_SUPPORT; | ||
| 454 | goto out_kfree; | ||
| 455 | } | ||
| 456 | status = AE_ERROR; | ||
| 457 | goto out_kfree; | ||
| 458 | } | ||
| 459 | out_success: | ||
| 460 | return AE_OK; | ||
| 461 | |||
| 462 | out_kfree: | ||
| 463 | kfree(context->ret.pointer); | ||
| 464 | context->ret.pointer = NULL; | ||
| 465 | return status; | ||
| 466 | } | ||
| 467 | EXPORT_SYMBOL(acpi_run_osc); | ||
| 468 | |||
| 469 | static u8 sb_uuid_str[] = "0811B06E-4A27-44F9-8D60-3CBBC22E7B48"; | ||
| 470 | static void acpi_bus_osc_support(void) | ||
| 471 | { | ||
| 472 | u32 capbuf[2]; | ||
| 473 | struct acpi_osc_context context = { | ||
| 474 | .uuid_str = sb_uuid_str, | ||
| 475 | .rev = 1, | ||
| 476 | .cap.length = 8, | ||
| 477 | .cap.pointer = capbuf, | ||
| 478 | }; | ||
| 479 | acpi_handle handle; | ||
| 480 | |||
| 481 | capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; | ||
| 482 | capbuf[OSC_SUPPORT_TYPE] = OSC_SB_PR3_SUPPORT; /* _PR3 is in use */ | ||
| 483 | #ifdef CONFIG_ACPI_PROCESSOR_AGGREGATOR | ||
| 484 | capbuf[OSC_SUPPORT_TYPE] |= OSC_SB_PAD_SUPPORT; | ||
| 485 | #endif | ||
| 486 | if (ACPI_FAILURE(acpi_get_handle(NULL, "\\_SB", &handle))) | ||
| 487 | return; | ||
| 488 | if (ACPI_SUCCESS(acpi_run_osc(handle, &context))) | ||
| 489 | kfree(context.ret.pointer); | ||
| 490 | /* do we need to check the returned cap? Sounds no */ | ||
| 491 | } | ||
| 492 | |||
| 347 | /* -------------------------------------------------------------------------- | 493 | /* -------------------------------------------------------------------------- |
| 348 | Event Management | 494 | Event Management |
| 349 | -------------------------------------------------------------------------- */ | 495 | -------------------------------------------------------------------------- */ |
| @@ -734,6 +880,8 @@ static int __init acpi_bus_init(void) | |||
| 734 | status = acpi_ec_ecdt_probe(); | 880 | status = acpi_ec_ecdt_probe(); |
| 735 | /* Ignore result. Not having an ECDT is not fatal. */ | 881 | /* Ignore result. Not having an ECDT is not fatal. */ |
| 736 | 882 | ||
| 883 | acpi_bus_osc_support(); | ||
| 884 | |||
| 737 | status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); | 885 | status = acpi_initialize_objects(ACPI_FULL_INITIALIZATION); |
| 738 | if (ACPI_FAILURE(status)) { | 886 | if (ACPI_FAILURE(status)) { |
| 739 | printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n"); | 887 | printk(KERN_ERR PREFIX "Unable to initialize ACPI objects\n"); |
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c index 0c9c6a9a002c..8a95e8329df7 100644 --- a/drivers/acpi/button.c +++ b/drivers/acpi/button.c | |||
| @@ -282,6 +282,13 @@ static int acpi_lid_send_state(struct acpi_device *device) | |||
| 282 | if (ret == NOTIFY_DONE) | 282 | if (ret == NOTIFY_DONE) |
| 283 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, | 283 | ret = blocking_notifier_call_chain(&acpi_lid_notifier, state, |
| 284 | device); | 284 | device); |
| 285 | if (ret == NOTIFY_DONE || ret == NOTIFY_OK) { | ||
| 286 | /* | ||
| 287 | * It is also regarded as success if the notifier_chain | ||
| 288 | * returns NOTIFY_OK or NOTIFY_DONE. | ||
| 289 | */ | ||
| 290 | ret = 0; | ||
| 291 | } | ||
| 285 | return ret; | 292 | return ret; |
| 286 | } | 293 | } |
| 287 | 294 | ||
diff --git a/drivers/acpi/debug.c b/drivers/acpi/debug.c index 8a690c3b8e23..cc421b7ae166 100644 --- a/drivers/acpi/debug.c +++ b/drivers/acpi/debug.c | |||
| @@ -8,6 +8,7 @@ | |||
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/kernel.h> | 9 | #include <linux/kernel.h> |
| 10 | #include <linux/moduleparam.h> | 10 | #include <linux/moduleparam.h> |
| 11 | #include <linux/debugfs.h> | ||
| 11 | #include <asm/uaccess.h> | 12 | #include <asm/uaccess.h> |
| 12 | #include <acpi/acpi_drivers.h> | 13 | #include <acpi/acpi_drivers.h> |
| 13 | 14 | ||
| @@ -196,6 +197,80 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state, | |||
| 196 | NULL, 0644); | 197 | NULL, 0644); |
| 197 | 198 | ||
| 198 | /* -------------------------------------------------------------------------- | 199 | /* -------------------------------------------------------------------------- |
| 200 | DebugFS Interface | ||
| 201 | -------------------------------------------------------------------------- */ | ||
| 202 | |||
| 203 | static ssize_t cm_write(struct file *file, const char __user *user_buf, | ||
| 204 | size_t count, loff_t *ppos) | ||
| 205 | { | ||
| 206 | static char *buf; | ||
| 207 | static int uncopied_bytes; | ||
| 208 | struct acpi_table_header table; | ||
| 209 | acpi_status status; | ||
| 210 | |||
| 211 | if (!(*ppos)) { | ||
| 212 | /* parse the table header to get the table length */ | ||
| 213 | if (count <= sizeof(struct acpi_table_header)) | ||
| 214 | return -EINVAL; | ||
| 215 | if (copy_from_user(&table, user_buf, | ||
| 216 | sizeof(struct acpi_table_header))) | ||
| 217 | return -EFAULT; | ||
| 218 | uncopied_bytes = table.length; | ||
| 219 | buf = kzalloc(uncopied_bytes, GFP_KERNEL); | ||
| 220 | if (!buf) | ||
| 221 | return -ENOMEM; | ||
| 222 | } | ||
| 223 | |||
| 224 | if (uncopied_bytes < count) { | ||
| 225 | kfree(buf); | ||
| 226 | return -EINVAL; | ||
| 227 | } | ||
| 228 | |||
| 229 | if (copy_from_user(buf + (*ppos), user_buf, count)) { | ||
| 230 | kfree(buf); | ||
| 231 | return -EFAULT; | ||
| 232 | } | ||
| 233 | |||
| 234 | uncopied_bytes -= count; | ||
| 235 | *ppos += count; | ||
| 236 | |||
| 237 | if (!uncopied_bytes) { | ||
| 238 | status = acpi_install_method(buf); | ||
| 239 | kfree(buf); | ||
| 240 | if (ACPI_FAILURE(status)) | ||
| 241 | return -EINVAL; | ||
| 242 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); | ||
| 243 | } | ||
| 244 | |||
| 245 | return count; | ||
| 246 | } | ||
| 247 | |||
| 248 | static const struct file_operations cm_fops = { | ||
| 249 | .write = cm_write, | ||
| 250 | }; | ||
| 251 | |||
| 252 | static int acpi_debugfs_init(void) | ||
| 253 | { | ||
| 254 | struct dentry *acpi_dir, *cm_dentry; | ||
| 255 | |||
| 256 | acpi_dir = debugfs_create_dir("acpi", NULL); | ||
| 257 | if (!acpi_dir) | ||
| 258 | goto err; | ||
| 259 | |||
| 260 | cm_dentry = debugfs_create_file("custom_method", S_IWUGO, | ||
| 261 | acpi_dir, NULL, &cm_fops); | ||
| 262 | if (!cm_dentry) | ||
| 263 | goto err; | ||
| 264 | |||
| 265 | return 0; | ||
| 266 | |||
| 267 | err: | ||
| 268 | if (acpi_dir) | ||
| 269 | debugfs_remove(acpi_dir); | ||
| 270 | return -EINVAL; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* -------------------------------------------------------------------------- | ||
| 199 | FS Interface (/proc) | 274 | FS Interface (/proc) |
| 200 | -------------------------------------------------------------------------- */ | 275 | -------------------------------------------------------------------------- */ |
| 201 | #ifdef CONFIG_ACPI_PROCFS | 276 | #ifdef CONFIG_ACPI_PROCFS |
| @@ -286,7 +361,7 @@ static const struct file_operations acpi_system_debug_proc_fops = { | |||
| 286 | }; | 361 | }; |
| 287 | #endif | 362 | #endif |
| 288 | 363 | ||
| 289 | int __init acpi_debug_init(void) | 364 | int __init acpi_procfs_init(void) |
| 290 | { | 365 | { |
| 291 | #ifdef CONFIG_ACPI_PROCFS | 366 | #ifdef CONFIG_ACPI_PROCFS |
| 292 | struct proc_dir_entry *entry; | 367 | struct proc_dir_entry *entry; |
| @@ -321,3 +396,10 @@ int __init acpi_debug_init(void) | |||
| 321 | return 0; | 396 | return 0; |
| 322 | #endif | 397 | #endif |
| 323 | } | 398 | } |
| 399 | |||
| 400 | int __init acpi_debug_init(void) | ||
| 401 | { | ||
| 402 | acpi_debugfs_init(); | ||
| 403 | acpi_procfs_init(); | ||
| 404 | return 0; | ||
| 405 | } | ||
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index 30be3c148f7e..bbc2c1315c47 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c | |||
| @@ -50,7 +50,6 @@ MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to " | |||
| 50 | " before undocking"); | 50 | " before undocking"); |
| 51 | 51 | ||
| 52 | static struct atomic_notifier_head dock_notifier_list; | 52 | static struct atomic_notifier_head dock_notifier_list; |
| 53 | static char dock_device_name[] = "dock"; | ||
| 54 | 53 | ||
| 55 | static const struct acpi_device_id dock_device_ids[] = { | 54 | static const struct acpi_device_id dock_device_ids[] = { |
| 56 | {"LNXDOCK", 0}, | 55 | {"LNXDOCK", 0}, |
| @@ -93,40 +92,30 @@ struct dock_dependent_device { | |||
| 93 | * Dock Dependent device functions * | 92 | * Dock Dependent device functions * |
| 94 | *****************************************************************************/ | 93 | *****************************************************************************/ |
| 95 | /** | 94 | /** |
| 96 | * alloc_dock_dependent_device - allocate and init a dependent device | 95 | * add_dock_dependent_device - associate a device with the dock station |
| 97 | * @handle: the acpi_handle of the dependent device | 96 | * @ds: The dock station |
| 97 | * @handle: handle of the dependent device | ||
| 98 | * | 98 | * |
| 99 | * Allocate memory for a dependent device structure for a device referenced | 99 | * Add the dependent device to the dock's dependent device list. |
| 100 | * by the acpi handle | ||
| 101 | */ | 100 | */ |
| 102 | static struct dock_dependent_device * | 101 | static int |
| 103 | alloc_dock_dependent_device(acpi_handle handle) | 102 | add_dock_dependent_device(struct dock_station *ds, acpi_handle handle) |
| 104 | { | 103 | { |
| 105 | struct dock_dependent_device *dd; | 104 | struct dock_dependent_device *dd; |
| 106 | 105 | ||
| 107 | dd = kzalloc(sizeof(*dd), GFP_KERNEL); | 106 | dd = kzalloc(sizeof(*dd), GFP_KERNEL); |
| 108 | if (dd) { | 107 | if (!dd) |
| 109 | dd->handle = handle; | 108 | return -ENOMEM; |
| 110 | INIT_LIST_HEAD(&dd->list); | 109 | |
| 111 | INIT_LIST_HEAD(&dd->hotplug_list); | 110 | dd->handle = handle; |
| 112 | } | 111 | INIT_LIST_HEAD(&dd->list); |
| 113 | return dd; | 112 | INIT_LIST_HEAD(&dd->hotplug_list); |
| 114 | } | ||
| 115 | 113 | ||
| 116 | /** | ||
| 117 | * add_dock_dependent_device - associate a device with the dock station | ||
| 118 | * @ds: The dock station | ||
| 119 | * @dd: The dependent device | ||
| 120 | * | ||
| 121 | * Add the dependent device to the dock's dependent device list. | ||
| 122 | */ | ||
| 123 | static void | ||
| 124 | add_dock_dependent_device(struct dock_station *ds, | ||
| 125 | struct dock_dependent_device *dd) | ||
| 126 | { | ||
| 127 | spin_lock(&ds->dd_lock); | 114 | spin_lock(&ds->dd_lock); |
| 128 | list_add_tail(&dd->list, &ds->dependent_devices); | 115 | list_add_tail(&dd->list, &ds->dependent_devices); |
| 129 | spin_unlock(&ds->dd_lock); | 116 | spin_unlock(&ds->dd_lock); |
| 117 | |||
| 118 | return 0; | ||
| 130 | } | 119 | } |
| 131 | 120 | ||
| 132 | /** | 121 | /** |
| @@ -249,6 +238,7 @@ static int is_battery(acpi_handle handle) | |||
| 249 | static int is_ejectable_bay(acpi_handle handle) | 238 | static int is_ejectable_bay(acpi_handle handle) |
| 250 | { | 239 | { |
| 251 | acpi_handle phandle; | 240 | acpi_handle phandle; |
| 241 | |||
| 252 | if (!is_ejectable(handle)) | 242 | if (!is_ejectable(handle)) |
| 253 | return 0; | 243 | return 0; |
| 254 | if (is_battery(handle) || is_ata(handle)) | 244 | if (is_battery(handle) || is_ata(handle)) |
| @@ -275,14 +265,13 @@ int is_dock_device(acpi_handle handle) | |||
| 275 | 265 | ||
| 276 | if (is_dock(handle)) | 266 | if (is_dock(handle)) |
| 277 | return 1; | 267 | return 1; |
| 278 | list_for_each_entry(dock_station, &dock_stations, sibling) { | 268 | |
| 269 | list_for_each_entry(dock_station, &dock_stations, sibling) | ||
| 279 | if (find_dock_dependent_device(dock_station, handle)) | 270 | if (find_dock_dependent_device(dock_station, handle)) |
| 280 | return 1; | 271 | return 1; |
| 281 | } | ||
| 282 | 272 | ||
| 283 | return 0; | 273 | return 0; |
| 284 | } | 274 | } |
| 285 | |||
| 286 | EXPORT_SYMBOL_GPL(is_dock_device); | 275 | EXPORT_SYMBOL_GPL(is_dock_device); |
| 287 | 276 | ||
| 288 | /** | 277 | /** |
| @@ -305,8 +294,6 @@ static int dock_present(struct dock_station *ds) | |||
| 305 | return 0; | 294 | return 0; |
| 306 | } | 295 | } |
| 307 | 296 | ||
| 308 | |||
| 309 | |||
| 310 | /** | 297 | /** |
| 311 | * dock_create_acpi_device - add new devices to acpi | 298 | * dock_create_acpi_device - add new devices to acpi |
| 312 | * @handle - handle of the device to add | 299 | * @handle - handle of the device to add |
| @@ -320,7 +307,7 @@ static int dock_present(struct dock_station *ds) | |||
| 320 | */ | 307 | */ |
| 321 | static struct acpi_device * dock_create_acpi_device(acpi_handle handle) | 308 | static struct acpi_device * dock_create_acpi_device(acpi_handle handle) |
| 322 | { | 309 | { |
| 323 | struct acpi_device *device = NULL; | 310 | struct acpi_device *device; |
| 324 | struct acpi_device *parent_device; | 311 | struct acpi_device *parent_device; |
| 325 | acpi_handle parent; | 312 | acpi_handle parent; |
| 326 | int ret; | 313 | int ret; |
| @@ -337,8 +324,7 @@ static struct acpi_device * dock_create_acpi_device(acpi_handle handle) | |||
| 337 | ret = acpi_bus_add(&device, parent_device, handle, | 324 | ret = acpi_bus_add(&device, parent_device, handle, |
| 338 | ACPI_BUS_TYPE_DEVICE); | 325 | ACPI_BUS_TYPE_DEVICE); |
| 339 | if (ret) { | 326 | if (ret) { |
| 340 | pr_debug("error adding bus, %x\n", | 327 | pr_debug("error adding bus, %x\n", -ret); |
| 341 | -ret); | ||
| 342 | return NULL; | 328 | return NULL; |
| 343 | } | 329 | } |
| 344 | } | 330 | } |
| @@ -364,7 +350,6 @@ static void dock_remove_acpi_device(acpi_handle handle) | |||
| 364 | } | 350 | } |
| 365 | } | 351 | } |
| 366 | 352 | ||
| 367 | |||
| 368 | /** | 353 | /** |
| 369 | * hotplug_dock_devices - insert or remove devices on the dock station | 354 | * hotplug_dock_devices - insert or remove devices on the dock station |
| 370 | * @ds: the dock station | 355 | * @ds: the dock station |
| @@ -384,10 +369,9 @@ static void hotplug_dock_devices(struct dock_station *ds, u32 event) | |||
| 384 | /* | 369 | /* |
| 385 | * First call driver specific hotplug functions | 370 | * First call driver specific hotplug functions |
| 386 | */ | 371 | */ |
| 387 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) { | 372 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) |
| 388 | if (dd->ops && dd->ops->handler) | 373 | if (dd->ops && dd->ops->handler) |
| 389 | dd->ops->handler(dd->handle, event, dd->context); | 374 | dd->ops->handler(dd->handle, event, dd->context); |
| 390 | } | ||
| 391 | 375 | ||
| 392 | /* | 376 | /* |
| 393 | * Now make sure that an acpi_device is created for each | 377 | * 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) | |||
| 426 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) | 410 | list_for_each_entry(dd, &ds->hotplug_devices, hotplug_list) |
| 427 | if (dd->ops && dd->ops->uevent) | 411 | if (dd->ops && dd->ops->uevent) |
| 428 | dd->ops->uevent(dd->handle, event, dd->context); | 412 | dd->ops->uevent(dd->handle, event, dd->context); |
| 413 | |||
| 429 | if (num != DOCK_EVENT) | 414 | if (num != DOCK_EVENT) |
| 430 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); | 415 | kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp); |
| 431 | } | 416 | } |
| @@ -456,8 +441,8 @@ static void eject_dock(struct dock_station *ds) | |||
| 456 | arg.type = ACPI_TYPE_INTEGER; | 441 | arg.type = ACPI_TYPE_INTEGER; |
| 457 | arg.integer.value = 1; | 442 | arg.integer.value = 1; |
| 458 | 443 | ||
| 459 | if (ACPI_FAILURE(acpi_evaluate_object(ds->handle, "_EJ0", | 444 | status = acpi_evaluate_object(ds->handle, "_EJ0", &arg_list, NULL); |
| 460 | &arg_list, NULL))) | 445 | if (ACPI_FAILURE(status)) |
| 461 | pr_debug("Failed to evaluate _EJ0!\n"); | 446 | pr_debug("Failed to evaluate _EJ0!\n"); |
| 462 | } | 447 | } |
| 463 | 448 | ||
| @@ -577,7 +562,6 @@ int register_dock_notifier(struct notifier_block *nb) | |||
| 577 | 562 | ||
| 578 | return atomic_notifier_chain_register(&dock_notifier_list, nb); | 563 | return atomic_notifier_chain_register(&dock_notifier_list, nb); |
| 579 | } | 564 | } |
| 580 | |||
| 581 | EXPORT_SYMBOL_GPL(register_dock_notifier); | 565 | EXPORT_SYMBOL_GPL(register_dock_notifier); |
| 582 | 566 | ||
| 583 | /** | 567 | /** |
| @@ -591,7 +575,6 @@ void unregister_dock_notifier(struct notifier_block *nb) | |||
| 591 | 575 | ||
| 592 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); | 576 | atomic_notifier_chain_unregister(&dock_notifier_list, nb); |
| 593 | } | 577 | } |
| 594 | |||
| 595 | EXPORT_SYMBOL_GPL(unregister_dock_notifier); | 578 | EXPORT_SYMBOL_GPL(unregister_dock_notifier); |
| 596 | 579 | ||
| 597 | /** | 580 | /** |
| @@ -636,7 +619,6 @@ register_hotplug_dock_device(acpi_handle handle, struct acpi_dock_ops *ops, | |||
| 636 | 619 | ||
| 637 | return ret; | 620 | return ret; |
| 638 | } | 621 | } |
| 639 | |||
| 640 | EXPORT_SYMBOL_GPL(register_hotplug_dock_device); | 622 | EXPORT_SYMBOL_GPL(register_hotplug_dock_device); |
| 641 | 623 | ||
| 642 | /** | 624 | /** |
| @@ -657,7 +639,6 @@ void unregister_hotplug_dock_device(acpi_handle handle) | |||
| 657 | dock_del_hotplug_device(dock_station, dd); | 639 | dock_del_hotplug_device(dock_station, dd); |
| 658 | } | 640 | } |
| 659 | } | 641 | } |
| 660 | |||
| 661 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); | 642 | EXPORT_SYMBOL_GPL(unregister_hotplug_dock_device); |
| 662 | 643 | ||
| 663 | /** | 644 | /** |
| @@ -772,7 +753,7 @@ struct dock_data { | |||
| 772 | 753 | ||
| 773 | static void acpi_dock_deferred_cb(void *context) | 754 | static void acpi_dock_deferred_cb(void *context) |
| 774 | { | 755 | { |
| 775 | struct dock_data *data = (struct dock_data *)context; | 756 | struct dock_data *data = context; |
| 776 | 757 | ||
| 777 | dock_notify(data->handle, data->event, data->ds); | 758 | dock_notify(data->handle, data->event, data->ds); |
| 778 | kfree(data); | 759 | kfree(data); |
| @@ -782,23 +763,22 @@ static int acpi_dock_notifier_call(struct notifier_block *this, | |||
| 782 | unsigned long event, void *data) | 763 | unsigned long event, void *data) |
| 783 | { | 764 | { |
| 784 | struct dock_station *dock_station; | 765 | struct dock_station *dock_station; |
| 785 | acpi_handle handle = (acpi_handle)data; | 766 | acpi_handle handle = data; |
| 786 | 767 | ||
| 787 | if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK | 768 | if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK |
| 788 | && event != ACPI_NOTIFY_EJECT_REQUEST) | 769 | && event != ACPI_NOTIFY_EJECT_REQUEST) |
| 789 | return 0; | 770 | return 0; |
| 790 | list_for_each_entry(dock_station, &dock_stations, sibling) { | 771 | list_for_each_entry(dock_station, &dock_stations, sibling) { |
| 791 | if (dock_station->handle == handle) { | 772 | if (dock_station->handle == handle) { |
| 792 | struct dock_data *dock_data; | 773 | struct dock_data *dd; |
| 793 | 774 | ||
| 794 | dock_data = kmalloc(sizeof(*dock_data), GFP_KERNEL); | 775 | dd = kmalloc(sizeof(*dd), GFP_KERNEL); |
| 795 | if (!dock_data) | 776 | if (!dd) |
| 796 | return 0; | 777 | return 0; |
| 797 | dock_data->handle = handle; | 778 | dd->handle = handle; |
| 798 | dock_data->event = event; | 779 | dd->event = event; |
| 799 | dock_data->ds = dock_station; | 780 | dd->ds = dock_station; |
| 800 | acpi_os_hotplug_execute(acpi_dock_deferred_cb, | 781 | acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd); |
| 801 | dock_data); | ||
| 802 | return 0 ; | 782 | return 0 ; |
| 803 | } | 783 | } |
| 804 | } | 784 | } |
| @@ -826,7 +806,6 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 826 | acpi_status status; | 806 | acpi_status status; |
| 827 | acpi_handle tmp, parent; | 807 | acpi_handle tmp, parent; |
| 828 | struct dock_station *ds = context; | 808 | struct dock_station *ds = context; |
| 829 | struct dock_dependent_device *dd; | ||
| 830 | 809 | ||
| 831 | status = acpi_bus_get_ejd(handle, &tmp); | 810 | status = acpi_bus_get_ejd(handle, &tmp); |
| 832 | if (ACPI_FAILURE(status)) { | 811 | if (ACPI_FAILURE(status)) { |
| @@ -840,11 +819,9 @@ find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 840 | goto fdd_out; | 819 | goto fdd_out; |
| 841 | } | 820 | } |
| 842 | 821 | ||
| 843 | if (tmp == ds->handle) { | 822 | if (tmp == ds->handle) |
| 844 | dd = alloc_dock_dependent_device(handle); | 823 | add_dock_dependent_device(ds, handle); |
| 845 | if (dd) | 824 | |
| 846 | add_dock_dependent_device(ds, dd); | ||
| 847 | } | ||
| 848 | fdd_out: | 825 | fdd_out: |
| 849 | return AE_OK; | 826 | return AE_OK; |
| 850 | } | 827 | } |
| @@ -857,8 +834,7 @@ static ssize_t show_docked(struct device *dev, | |||
| 857 | { | 834 | { |
| 858 | struct acpi_device *tmp; | 835 | struct acpi_device *tmp; |
| 859 | 836 | ||
| 860 | struct dock_station *dock_station = *((struct dock_station **) | 837 | struct dock_station *dock_station = dev->platform_data; |
| 861 | dev->platform_data); | ||
| 862 | 838 | ||
| 863 | if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp))) | 839 | if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp))) |
| 864 | return snprintf(buf, PAGE_SIZE, "1\n"); | 840 | return snprintf(buf, PAGE_SIZE, "1\n"); |
| @@ -872,8 +848,7 @@ static DEVICE_ATTR(docked, S_IRUGO, show_docked, NULL); | |||
| 872 | static ssize_t show_flags(struct device *dev, | 848 | static ssize_t show_flags(struct device *dev, |
| 873 | struct device_attribute *attr, char *buf) | 849 | struct device_attribute *attr, char *buf) |
| 874 | { | 850 | { |
| 875 | struct dock_station *dock_station = *((struct dock_station **) | 851 | struct dock_station *dock_station = dev->platform_data; |
| 876 | dev->platform_data); | ||
| 877 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); | 852 | return snprintf(buf, PAGE_SIZE, "%d\n", dock_station->flags); |
| 878 | 853 | ||
| 879 | } | 854 | } |
| @@ -886,8 +861,7 @@ static ssize_t write_undock(struct device *dev, struct device_attribute *attr, | |||
| 886 | const char *buf, size_t count) | 861 | const char *buf, size_t count) |
| 887 | { | 862 | { |
| 888 | int ret; | 863 | int ret; |
| 889 | struct dock_station *dock_station = *((struct dock_station **) | 864 | struct dock_station *dock_station = dev->platform_data; |
| 890 | dev->platform_data); | ||
| 891 | 865 | ||
| 892 | if (!count) | 866 | if (!count) |
| 893 | return -EINVAL; | 867 | return -EINVAL; |
| @@ -905,8 +879,7 @@ static ssize_t show_dock_uid(struct device *dev, | |||
| 905 | struct device_attribute *attr, char *buf) | 879 | struct device_attribute *attr, char *buf) |
| 906 | { | 880 | { |
| 907 | unsigned long long lbuf; | 881 | unsigned long long lbuf; |
| 908 | struct dock_station *dock_station = *((struct dock_station **) | 882 | struct dock_station *dock_station = dev->platform_data; |
| 909 | dev->platform_data); | ||
| 910 | acpi_status status = acpi_evaluate_integer(dock_station->handle, | 883 | acpi_status status = acpi_evaluate_integer(dock_station->handle, |
| 911 | "_UID", NULL, &lbuf); | 884 | "_UID", NULL, &lbuf); |
| 912 | if (ACPI_FAILURE(status)) | 885 | if (ACPI_FAILURE(status)) |
| @@ -919,8 +892,7 @@ static DEVICE_ATTR(uid, S_IRUGO, show_dock_uid, NULL); | |||
| 919 | static ssize_t show_dock_type(struct device *dev, | 892 | static ssize_t show_dock_type(struct device *dev, |
| 920 | struct device_attribute *attr, char *buf) | 893 | struct device_attribute *attr, char *buf) |
| 921 | { | 894 | { |
| 922 | struct dock_station *dock_station = *((struct dock_station **) | 895 | struct dock_station *dock_station = dev->platform_data; |
| 923 | dev->platform_data); | ||
| 924 | char *type; | 896 | char *type; |
| 925 | 897 | ||
| 926 | if (dock_station->flags & DOCK_IS_DOCK) | 898 | if (dock_station->flags & DOCK_IS_DOCK) |
| @@ -936,6 +908,19 @@ static ssize_t show_dock_type(struct device *dev, | |||
| 936 | } | 908 | } |
| 937 | static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); | 909 | static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); |
| 938 | 910 | ||
| 911 | static struct attribute *dock_attributes[] = { | ||
| 912 | &dev_attr_docked.attr, | ||
| 913 | &dev_attr_flags.attr, | ||
| 914 | &dev_attr_undock.attr, | ||
| 915 | &dev_attr_uid.attr, | ||
| 916 | &dev_attr_type.attr, | ||
| 917 | NULL | ||
| 918 | }; | ||
| 919 | |||
| 920 | static struct attribute_group dock_attribute_group = { | ||
| 921 | .attrs = dock_attributes | ||
| 922 | }; | ||
| 923 | |||
| 939 | /** | 924 | /** |
| 940 | * dock_add - add a new dock station | 925 | * dock_add - add a new dock station |
| 941 | * @handle: the dock station handle | 926 | * @handle: the dock station handle |
| @@ -945,39 +930,30 @@ static DEVICE_ATTR(type, S_IRUGO, show_dock_type, NULL); | |||
| 945 | */ | 930 | */ |
| 946 | static int dock_add(acpi_handle handle) | 931 | static int dock_add(acpi_handle handle) |
| 947 | { | 932 | { |
| 948 | int ret; | 933 | int ret, id; |
| 949 | struct dock_dependent_device *dd; | 934 | struct dock_station ds, *dock_station; |
| 950 | struct dock_station *dock_station; | 935 | struct platform_device *dd; |
| 951 | struct platform_device *dock_device; | 936 | |
| 937 | id = dock_station_count; | ||
| 938 | dd = platform_device_register_data(NULL, "dock", id, &ds, sizeof(ds)); | ||
| 939 | if (IS_ERR(dd)) | ||
| 940 | return PTR_ERR(dd); | ||
| 941 | |||
| 942 | dock_station = dd->dev.platform_data; | ||
| 952 | 943 | ||
| 953 | /* allocate & initialize the dock_station private data */ | ||
| 954 | dock_station = kzalloc(sizeof(*dock_station), GFP_KERNEL); | ||
| 955 | if (!dock_station) | ||
| 956 | return -ENOMEM; | ||
| 957 | dock_station->handle = handle; | 944 | dock_station->handle = handle; |
| 945 | dock_station->dock_device = dd; | ||
| 958 | dock_station->last_dock_time = jiffies - HZ; | 946 | dock_station->last_dock_time = jiffies - HZ; |
| 959 | INIT_LIST_HEAD(&dock_station->dependent_devices); | 947 | |
| 960 | INIT_LIST_HEAD(&dock_station->hotplug_devices); | ||
| 961 | INIT_LIST_HEAD(&dock_station->sibling); | ||
| 962 | spin_lock_init(&dock_station->dd_lock); | ||
| 963 | mutex_init(&dock_station->hp_lock); | 948 | mutex_init(&dock_station->hp_lock); |
| 949 | spin_lock_init(&dock_station->dd_lock); | ||
| 950 | INIT_LIST_HEAD(&dock_station->sibling); | ||
| 951 | INIT_LIST_HEAD(&dock_station->hotplug_devices); | ||
| 964 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); | 952 | ATOMIC_INIT_NOTIFIER_HEAD(&dock_notifier_list); |
| 965 | 953 | INIT_LIST_HEAD(&dock_station->dependent_devices); | |
| 966 | /* initialize platform device stuff */ | ||
| 967 | dock_station->dock_device = | ||
| 968 | platform_device_register_simple(dock_device_name, | ||
| 969 | dock_station_count, NULL, 0); | ||
| 970 | dock_device = dock_station->dock_device; | ||
| 971 | if (IS_ERR(dock_device)) { | ||
| 972 | kfree(dock_station); | ||
| 973 | dock_station = NULL; | ||
| 974 | return PTR_ERR(dock_device); | ||
| 975 | } | ||
| 976 | platform_device_add_data(dock_device, &dock_station, | ||
| 977 | sizeof(struct dock_station *)); | ||
| 978 | 954 | ||
| 979 | /* we want the dock device to send uevents */ | 955 | /* we want the dock device to send uevents */ |
| 980 | dev_set_uevent_suppress(&dock_device->dev, 0); | 956 | dev_set_uevent_suppress(&dd->dev, 0); |
| 981 | 957 | ||
| 982 | if (is_dock(handle)) | 958 | if (is_dock(handle)) |
| 983 | dock_station->flags |= DOCK_IS_DOCK; | 959 | dock_station->flags |= DOCK_IS_DOCK; |
| @@ -986,47 +962,9 @@ static int dock_add(acpi_handle handle) | |||
| 986 | if (is_battery(handle)) | 962 | if (is_battery(handle)) |
| 987 | dock_station->flags |= DOCK_IS_BAT; | 963 | dock_station->flags |= DOCK_IS_BAT; |
| 988 | 964 | ||
| 989 | ret = device_create_file(&dock_device->dev, &dev_attr_docked); | 965 | ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group); |
| 990 | if (ret) { | ||
| 991 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
| 992 | platform_device_unregister(dock_device); | ||
| 993 | kfree(dock_station); | ||
| 994 | dock_station = NULL; | ||
| 995 | return ret; | ||
| 996 | } | ||
| 997 | ret = device_create_file(&dock_device->dev, &dev_attr_undock); | ||
| 998 | if (ret) { | ||
| 999 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
| 1000 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
| 1001 | platform_device_unregister(dock_device); | ||
| 1002 | kfree(dock_station); | ||
| 1003 | dock_station = NULL; | ||
| 1004 | return ret; | ||
| 1005 | } | ||
| 1006 | ret = device_create_file(&dock_device->dev, &dev_attr_uid); | ||
| 1007 | if (ret) { | ||
| 1008 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
| 1009 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
| 1010 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
| 1011 | platform_device_unregister(dock_device); | ||
| 1012 | kfree(dock_station); | ||
| 1013 | dock_station = NULL; | ||
| 1014 | return ret; | ||
| 1015 | } | ||
| 1016 | ret = device_create_file(&dock_device->dev, &dev_attr_flags); | ||
| 1017 | if (ret) { | ||
| 1018 | printk(KERN_ERR "Error %d adding sysfs file\n", ret); | ||
| 1019 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
| 1020 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
| 1021 | device_remove_file(&dock_device->dev, &dev_attr_uid); | ||
| 1022 | platform_device_unregister(dock_device); | ||
| 1023 | kfree(dock_station); | ||
| 1024 | dock_station = NULL; | ||
| 1025 | return ret; | ||
| 1026 | } | ||
| 1027 | ret = device_create_file(&dock_device->dev, &dev_attr_type); | ||
| 1028 | if (ret) | 966 | if (ret) |
| 1029 | printk(KERN_ERR"Error %d adding sysfs file\n", ret); | 967 | goto err_unregister; |
| 1030 | 968 | ||
| 1031 | /* Find dependent devices */ | 969 | /* Find dependent devices */ |
| 1032 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, | 970 | acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, |
| @@ -1034,58 +972,43 @@ static int dock_add(acpi_handle handle) | |||
| 1034 | dock_station, NULL); | 972 | dock_station, NULL); |
| 1035 | 973 | ||
| 1036 | /* add the dock station as a device dependent on itself */ | 974 | /* add the dock station as a device dependent on itself */ |
| 1037 | dd = alloc_dock_dependent_device(handle); | 975 | ret = add_dock_dependent_device(dock_station, handle); |
| 1038 | if (!dd) { | 976 | if (ret) |
| 1039 | kfree(dock_station); | 977 | goto err_rmgroup; |
| 1040 | dock_station = NULL; | ||
| 1041 | ret = -ENOMEM; | ||
| 1042 | goto dock_add_err_unregister; | ||
| 1043 | } | ||
| 1044 | add_dock_dependent_device(dock_station, dd); | ||
| 1045 | 978 | ||
| 1046 | dock_station_count++; | 979 | dock_station_count++; |
| 1047 | list_add(&dock_station->sibling, &dock_stations); | 980 | list_add(&dock_station->sibling, &dock_stations); |
| 1048 | return 0; | 981 | return 0; |
| 1049 | 982 | ||
| 1050 | dock_add_err_unregister: | 983 | err_rmgroup: |
| 1051 | device_remove_file(&dock_device->dev, &dev_attr_type); | 984 | sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group); |
| 1052 | device_remove_file(&dock_device->dev, &dev_attr_docked); | 985 | err_unregister: |
| 1053 | device_remove_file(&dock_device->dev, &dev_attr_undock); | 986 | platform_device_unregister(dd); |
| 1054 | device_remove_file(&dock_device->dev, &dev_attr_uid); | 987 | printk(KERN_ERR "%s encountered error %d\n", __func__, ret); |
| 1055 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
| 1056 | platform_device_unregister(dock_device); | ||
| 1057 | kfree(dock_station); | ||
| 1058 | dock_station = NULL; | ||
| 1059 | return ret; | 988 | return ret; |
| 1060 | } | 989 | } |
| 1061 | 990 | ||
| 1062 | /** | 991 | /** |
| 1063 | * dock_remove - free up resources related to the dock station | 992 | * dock_remove - free up resources related to the dock station |
| 1064 | */ | 993 | */ |
| 1065 | static int dock_remove(struct dock_station *dock_station) | 994 | static int dock_remove(struct dock_station *ds) |
| 1066 | { | 995 | { |
| 1067 | struct dock_dependent_device *dd, *tmp; | 996 | struct dock_dependent_device *dd, *tmp; |
| 1068 | struct platform_device *dock_device = dock_station->dock_device; | 997 | struct platform_device *dock_device = ds->dock_device; |
| 1069 | 998 | ||
| 1070 | if (!dock_station_count) | 999 | if (!dock_station_count) |
| 1071 | return 0; | 1000 | return 0; |
| 1072 | 1001 | ||
| 1073 | /* remove dependent devices */ | 1002 | /* remove dependent devices */ |
| 1074 | list_for_each_entry_safe(dd, tmp, &dock_station->dependent_devices, | 1003 | list_for_each_entry_safe(dd, tmp, &ds->dependent_devices, list) |
| 1075 | list) | 1004 | kfree(dd); |
| 1076 | kfree(dd); | 1005 | |
| 1006 | list_del(&ds->sibling); | ||
| 1077 | 1007 | ||
| 1078 | /* cleanup sysfs */ | 1008 | /* cleanup sysfs */ |
| 1079 | device_remove_file(&dock_device->dev, &dev_attr_type); | 1009 | sysfs_remove_group(&dock_device->dev.kobj, &dock_attribute_group); |
| 1080 | device_remove_file(&dock_device->dev, &dev_attr_docked); | ||
| 1081 | device_remove_file(&dock_device->dev, &dev_attr_undock); | ||
| 1082 | device_remove_file(&dock_device->dev, &dev_attr_uid); | ||
| 1083 | device_remove_file(&dock_device->dev, &dev_attr_flags); | ||
| 1084 | platform_device_unregister(dock_device); | 1010 | platform_device_unregister(dock_device); |
| 1085 | 1011 | ||
| 1086 | /* free dock station memory */ | ||
| 1087 | kfree(dock_station); | ||
| 1088 | dock_station = NULL; | ||
| 1089 | return 0; | 1012 | return 0; |
| 1090 | } | 1013 | } |
| 1091 | 1014 | ||
| @@ -1103,11 +1026,10 @@ find_dock(acpi_handle handle, u32 lvl, void *context, void **rv) | |||
| 1103 | { | 1026 | { |
| 1104 | acpi_status status = AE_OK; | 1027 | acpi_status status = AE_OK; |
| 1105 | 1028 | ||
| 1106 | if (is_dock(handle)) { | 1029 | if (is_dock(handle)) |
| 1107 | if (dock_add(handle) >= 0) { | 1030 | if (dock_add(handle) >= 0) |
| 1108 | status = AE_CTRL_TERMINATE; | 1031 | status = AE_CTRL_TERMINATE; |
| 1109 | } | 1032 | |
| 1110 | } | ||
| 1111 | return status; | 1033 | return status; |
| 1112 | } | 1034 | } |
| 1113 | 1035 | ||
| @@ -1145,8 +1067,7 @@ static int __init dock_init(void) | |||
| 1145 | 1067 | ||
| 1146 | static void __exit dock_exit(void) | 1068 | static void __exit dock_exit(void) |
| 1147 | { | 1069 | { |
| 1148 | struct dock_station *dock_station; | 1070 | struct dock_station *tmp, *dock_station; |
| 1149 | struct dock_station *tmp; | ||
| 1150 | 1071 | ||
| 1151 | unregister_acpi_bus_notifier(&dock_acpi_notifier); | 1072 | unregister_acpi_bus_notifier(&dock_acpi_notifier); |
| 1152 | list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling) | 1073 | list_for_each_entry_safe(dock_station, tmp, &dock_stations, sibling) |
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index f419849a0d3f..acf2ab249842 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c | |||
| @@ -267,7 +267,7 @@ static int acpi_fan_add(struct acpi_device *device) | |||
| 267 | goto end; | 267 | goto end; |
| 268 | } | 268 | } |
| 269 | 269 | ||
| 270 | dev_info(&device->dev, "registered as cooling_device%d\n", cdev->id); | 270 | dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id); |
| 271 | 271 | ||
| 272 | device->driver_data = cdev; | 272 | device->driver_data = cdev; |
| 273 | result = sysfs_create_link(&device->dev.kobj, | 273 | result = sysfs_create_link(&device->dev.kobj, |
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index 2be2fb66204e..7ad48dfc12db 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c | |||
| @@ -28,6 +28,7 @@ | |||
| 28 | #include <linux/types.h> | 28 | #include <linux/types.h> |
| 29 | #include <linux/errno.h> | 29 | #include <linux/errno.h> |
| 30 | #include <linux/acpi.h> | 30 | #include <linux/acpi.h> |
| 31 | #include <linux/numa.h> | ||
| 31 | #include <acpi/acpi_bus.h> | 32 | #include <acpi/acpi_bus.h> |
| 32 | 33 | ||
| 33 | #define PREFIX "ACPI: " | 34 | #define PREFIX "ACPI: " |
| @@ -40,14 +41,14 @@ static nodemask_t nodes_found_map = NODE_MASK_NONE; | |||
| 40 | 41 | ||
| 41 | /* maps to convert between proximity domain and logical node ID */ | 42 | /* maps to convert between proximity domain and logical node ID */ |
| 42 | static int pxm_to_node_map[MAX_PXM_DOMAINS] | 43 | static int pxm_to_node_map[MAX_PXM_DOMAINS] |
| 43 | = { [0 ... MAX_PXM_DOMAINS - 1] = NID_INVAL }; | 44 | = { [0 ... MAX_PXM_DOMAINS - 1] = NUMA_NO_NODE }; |
| 44 | static int node_to_pxm_map[MAX_NUMNODES] | 45 | static int node_to_pxm_map[MAX_NUMNODES] |
| 45 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; | 46 | = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL }; |
| 46 | 47 | ||
| 47 | int pxm_to_node(int pxm) | 48 | int pxm_to_node(int pxm) |
| 48 | { | 49 | { |
| 49 | if (pxm < 0) | 50 | if (pxm < 0) |
| 50 | return NID_INVAL; | 51 | return NUMA_NO_NODE; |
| 51 | return pxm_to_node_map[pxm]; | 52 | return pxm_to_node_map[pxm]; |
| 52 | } | 53 | } |
| 53 | 54 | ||
| @@ -68,9 +69,9 @@ int acpi_map_pxm_to_node(int pxm) | |||
| 68 | { | 69 | { |
| 69 | int node = pxm_to_node_map[pxm]; | 70 | int node = pxm_to_node_map[pxm]; |
| 70 | 71 | ||
| 71 | if (node < 0){ | 72 | if (node < 0) { |
| 72 | if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) | 73 | if (nodes_weight(nodes_found_map) >= MAX_NUMNODES) |
| 73 | return NID_INVAL; | 74 | return NUMA_NO_NODE; |
| 74 | node = first_unset_node(nodes_found_map); | 75 | node = first_unset_node(nodes_found_map); |
| 75 | __acpi_map_pxm_to_node(pxm, node); | 76 | __acpi_map_pxm_to_node(pxm, node); |
| 76 | node_set(node, nodes_found_map); | 77 | node_set(node, nodes_found_map); |
| @@ -79,16 +80,6 @@ int acpi_map_pxm_to_node(int pxm) | |||
| 79 | return node; | 80 | return node; |
| 80 | } | 81 | } |
| 81 | 82 | ||
| 82 | #if 0 | ||
| 83 | void __cpuinit acpi_unmap_pxm_to_node(int node) | ||
| 84 | { | ||
| 85 | int pxm = node_to_pxm_map[node]; | ||
| 86 | pxm_to_node_map[pxm] = NID_INVAL; | ||
| 87 | node_to_pxm_map[node] = PXM_INVAL; | ||
| 88 | node_clear(node, nodes_found_map); | ||
| 89 | } | ||
| 90 | #endif /* 0 */ | ||
| 91 | |||
| 92 | static void __init | 83 | static void __init |
| 93 | acpi_table_print_srat_entry(struct acpi_subtable_header *header) | 84 | acpi_table_print_srat_entry(struct acpi_subtable_header *header) |
| 94 | { | 85 | { |
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 7c1c59ea9ec6..02e8464e480f 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c | |||
| @@ -1118,7 +1118,7 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); | |||
| 1118 | 1118 | ||
| 1119 | /* Check for resource conflicts between ACPI OperationRegions and native | 1119 | /* Check for resource conflicts between ACPI OperationRegions and native |
| 1120 | * drivers */ | 1120 | * drivers */ |
| 1121 | int acpi_check_resource_conflict(struct resource *res) | 1121 | int acpi_check_resource_conflict(const struct resource *res) |
| 1122 | { | 1122 | { |
| 1123 | struct acpi_res_list *res_list_elem; | 1123 | struct acpi_res_list *res_list_elem; |
| 1124 | int ioport; | 1124 | int ioport; |
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1af808171d46..101cce3681d1 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c | |||
| @@ -202,72 +202,24 @@ static void acpi_pci_bridge_scan(struct acpi_device *device) | |||
| 202 | } | 202 | } |
| 203 | } | 203 | } |
| 204 | 204 | ||
| 205 | static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, | 205 | static u8 pci_osc_uuid_str[] = "33DB4D5B-1FF7-401C-9657-7441C03DD766"; |
| 206 | 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; | ||
| 207 | 206 | ||
| 208 | static acpi_status acpi_pci_run_osc(acpi_handle handle, | 207 | static acpi_status acpi_pci_run_osc(acpi_handle handle, |
| 209 | const u32 *capbuf, u32 *retval) | 208 | const u32 *capbuf, u32 *retval) |
| 210 | { | 209 | { |
| 210 | struct acpi_osc_context context = { | ||
| 211 | .uuid_str = pci_osc_uuid_str, | ||
| 212 | .rev = 1, | ||
| 213 | .cap.length = 12, | ||
| 214 | .cap.pointer = (void *)capbuf, | ||
| 215 | }; | ||
| 211 | acpi_status status; | 216 | acpi_status status; |
| 212 | struct acpi_object_list input; | ||
| 213 | union acpi_object in_params[4]; | ||
| 214 | struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; | ||
| 215 | union acpi_object *out_obj; | ||
| 216 | u32 errors; | ||
| 217 | |||
| 218 | /* Setting up input parameters */ | ||
| 219 | input.count = 4; | ||
| 220 | input.pointer = in_params; | ||
| 221 | in_params[0].type = ACPI_TYPE_BUFFER; | ||
| 222 | in_params[0].buffer.length = 16; | ||
| 223 | in_params[0].buffer.pointer = OSC_UUID; | ||
| 224 | in_params[1].type = ACPI_TYPE_INTEGER; | ||
| 225 | in_params[1].integer.value = 1; | ||
| 226 | in_params[2].type = ACPI_TYPE_INTEGER; | ||
| 227 | in_params[2].integer.value = 3; | ||
| 228 | in_params[3].type = ACPI_TYPE_BUFFER; | ||
| 229 | in_params[3].buffer.length = 12; | ||
| 230 | in_params[3].buffer.pointer = (u8 *)capbuf; | ||
| 231 | |||
| 232 | status = acpi_evaluate_object(handle, "_OSC", &input, &output); | ||
| 233 | if (ACPI_FAILURE(status)) | ||
| 234 | return status; | ||
| 235 | 217 | ||
| 236 | if (!output.length) | 218 | status = acpi_run_osc(handle, &context); |
| 237 | return AE_NULL_OBJECT; | 219 | if (ACPI_SUCCESS(status)) { |
| 238 | 220 | *retval = *((u32 *)(context.ret.pointer + 8)); | |
| 239 | out_obj = output.pointer; | 221 | kfree(context.ret.pointer); |
| 240 | if (out_obj->type != ACPI_TYPE_BUFFER) { | ||
| 241 | printk(KERN_DEBUG "_OSC evaluation returned wrong type\n"); | ||
| 242 | status = AE_TYPE; | ||
| 243 | goto out_kfree; | ||
| 244 | } | ||
| 245 | /* Need to ignore the bit0 in result code */ | ||
| 246 | errors = *((u32 *)out_obj->buffer.pointer) & ~(1 << 0); | ||
| 247 | if (errors) { | ||
| 248 | if (errors & OSC_REQUEST_ERROR) | ||
| 249 | printk(KERN_DEBUG "_OSC request failed\n"); | ||
| 250 | if (errors & OSC_INVALID_UUID_ERROR) | ||
| 251 | printk(KERN_DEBUG "_OSC invalid UUID\n"); | ||
| 252 | if (errors & OSC_INVALID_REVISION_ERROR) | ||
| 253 | printk(KERN_DEBUG "_OSC invalid revision\n"); | ||
| 254 | if (errors & OSC_CAPABILITIES_MASK_ERROR) { | ||
| 255 | if (capbuf[OSC_QUERY_TYPE] & OSC_QUERY_ENABLE) | ||
| 256 | goto out_success; | ||
| 257 | printk(KERN_DEBUG | ||
| 258 | "Firmware did not grant requested _OSC control\n"); | ||
| 259 | status = AE_SUPPORT; | ||
| 260 | goto out_kfree; | ||
| 261 | } | ||
| 262 | status = AE_ERROR; | ||
| 263 | goto out_kfree; | ||
| 264 | } | 222 | } |
| 265 | out_success: | ||
| 266 | *retval = *((u32 *)(out_obj->buffer.pointer + 8)); | ||
| 267 | status = AE_OK; | ||
| 268 | |||
| 269 | out_kfree: | ||
| 270 | kfree(output.pointer); | ||
| 271 | return status; | 223 | return status; |
| 272 | } | 224 | } |
| 273 | 225 | ||
| @@ -277,10 +229,10 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags) | |||
| 277 | u32 support_set, result, capbuf[3]; | 229 | u32 support_set, result, capbuf[3]; |
| 278 | 230 | ||
| 279 | /* do _OSC query for all possible controls */ | 231 | /* do _OSC query for all possible controls */ |
| 280 | support_set = root->osc_support_set | (flags & OSC_SUPPORT_MASKS); | 232 | support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS); |
| 281 | capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; | 233 | capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; |
| 282 | capbuf[OSC_SUPPORT_TYPE] = support_set; | 234 | capbuf[OSC_SUPPORT_TYPE] = support_set; |
| 283 | capbuf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; | 235 | capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; |
| 284 | 236 | ||
| 285 | status = acpi_pci_run_osc(root->device->handle, capbuf, &result); | 237 | status = acpi_pci_run_osc(root->device->handle, capbuf, &result); |
| 286 | if (ACPI_SUCCESS(status)) { | 238 | if (ACPI_SUCCESS(status)) { |
| @@ -427,7 +379,7 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) | |||
| 427 | if (ACPI_FAILURE(status)) | 379 | if (ACPI_FAILURE(status)) |
| 428 | return status; | 380 | return status; |
| 429 | 381 | ||
| 430 | control_req = (flags & OSC_CONTROL_MASKS); | 382 | control_req = (flags & OSC_PCI_CONTROL_MASKS); |
| 431 | if (!control_req) | 383 | if (!control_req) |
| 432 | return AE_TYPE; | 384 | return AE_TYPE; |
| 433 | 385 | ||
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index cb4283f5a79d..41731236f9a1 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c | |||
| @@ -353,7 +353,7 @@ static int acpi_processor_info_open_fs(struct inode *inode, struct file *file) | |||
| 353 | PDE(inode)->data); | 353 | PDE(inode)->data); |
| 354 | } | 354 | } |
| 355 | 355 | ||
| 356 | static int acpi_processor_add_fs(struct acpi_device *device) | 356 | static int __cpuinit acpi_processor_add_fs(struct acpi_device *device) |
| 357 | { | 357 | { |
| 358 | struct proc_dir_entry *entry = NULL; | 358 | struct proc_dir_entry *entry = NULL; |
| 359 | 359 | ||
| @@ -722,7 +722,7 @@ static void acpi_processor_notify(struct acpi_device *device, u32 event) | |||
| 722 | switch (event) { | 722 | switch (event) { |
| 723 | case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: | 723 | case ACPI_PROCESSOR_NOTIFY_PERFORMANCE: |
| 724 | saved = pr->performance_platform_limit; | 724 | saved = pr->performance_platform_limit; |
| 725 | acpi_processor_ppc_has_changed(pr); | 725 | acpi_processor_ppc_has_changed(pr, 1); |
| 726 | if (saved == pr->performance_platform_limit) | 726 | if (saved == pr->performance_platform_limit) |
| 727 | break; | 727 | break; |
| 728 | acpi_bus_generate_proc_event(device, event, | 728 | acpi_bus_generate_proc_event(device, event, |
| @@ -758,7 +758,7 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb, | |||
| 758 | struct acpi_processor *pr = per_cpu(processors, cpu); | 758 | struct acpi_processor *pr = per_cpu(processors, cpu); |
| 759 | 759 | ||
| 760 | if (action == CPU_ONLINE && pr) { | 760 | if (action == CPU_ONLINE && pr) { |
| 761 | acpi_processor_ppc_has_changed(pr); | 761 | acpi_processor_ppc_has_changed(pr, 0); |
| 762 | acpi_processor_cst_has_changed(pr); | 762 | acpi_processor_cst_has_changed(pr); |
| 763 | acpi_processor_tstate_has_changed(pr); | 763 | acpi_processor_tstate_has_changed(pr); |
| 764 | } | 764 | } |
| @@ -830,7 +830,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) | |||
| 830 | arch_acpi_processor_cleanup_pdc(pr); | 830 | arch_acpi_processor_cleanup_pdc(pr); |
| 831 | 831 | ||
| 832 | #ifdef CONFIG_CPU_FREQ | 832 | #ifdef CONFIG_CPU_FREQ |
| 833 | acpi_processor_ppc_has_changed(pr); | 833 | acpi_processor_ppc_has_changed(pr, 0); |
| 834 | #endif | 834 | #endif |
| 835 | acpi_processor_get_throttling_info(pr); | 835 | acpi_processor_get_throttling_info(pr); |
| 836 | acpi_processor_get_limit_info(pr); | 836 | acpi_processor_get_limit_info(pr); |
| @@ -845,7 +845,7 @@ static int __cpuinit acpi_processor_add(struct acpi_device *device) | |||
| 845 | goto err_power_exit; | 845 | goto err_power_exit; |
| 846 | } | 846 | } |
| 847 | 847 | ||
| 848 | dev_info(&device->dev, "registered as cooling_device%d\n", | 848 | dev_dbg(&device->dev, "registered as cooling_device%d\n", |
| 849 | pr->cdev->id); | 849 | pr->cdev->id); |
| 850 | 850 | ||
| 851 | result = sysfs_create_link(&device->dev.kobj, | 851 | result = sysfs_create_link(&device->dev.kobj, |
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index bbd066e7f854..d1676b1754d9 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c | |||
| @@ -164,7 +164,7 @@ static void lapic_timer_check_state(int state, struct acpi_processor *pr, | |||
| 164 | pr->power.timer_broadcast_on_state = state; | 164 | pr->power.timer_broadcast_on_state = state; |
| 165 | } | 165 | } |
| 166 | 166 | ||
| 167 | static void lapic_timer_propagate_broadcast(void *arg) | 167 | static void __lapic_timer_propagate_broadcast(void *arg) |
| 168 | { | 168 | { |
| 169 | struct acpi_processor *pr = (struct acpi_processor *) arg; | 169 | struct acpi_processor *pr = (struct acpi_processor *) arg; |
| 170 | unsigned long reason; | 170 | unsigned long reason; |
| @@ -175,6 +175,12 @@ static void lapic_timer_propagate_broadcast(void *arg) | |||
| 175 | clockevents_notify(reason, &pr->id); | 175 | clockevents_notify(reason, &pr->id); |
| 176 | } | 176 | } |
| 177 | 177 | ||
| 178 | static void lapic_timer_propagate_broadcast(struct acpi_processor *pr) | ||
| 179 | { | ||
| 180 | smp_call_function_single(pr->id, __lapic_timer_propagate_broadcast, | ||
| 181 | (void *)pr, 1); | ||
| 182 | } | ||
| 183 | |||
| 178 | /* Power(C) State timer broadcast control */ | 184 | /* Power(C) State timer broadcast control */ |
| 179 | static void lapic_timer_state_broadcast(struct acpi_processor *pr, | 185 | static void lapic_timer_state_broadcast(struct acpi_processor *pr, |
| 180 | struct acpi_processor_cx *cx, | 186 | struct acpi_processor_cx *cx, |
| @@ -638,8 +644,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr) | |||
| 638 | working++; | 644 | working++; |
| 639 | } | 645 | } |
| 640 | 646 | ||
| 641 | smp_call_function_single(pr->id, lapic_timer_propagate_broadcast, | 647 | lapic_timer_propagate_broadcast(pr); |
| 642 | pr, 1); | ||
| 643 | 648 | ||
| 644 | return (working); | 649 | return (working); |
| 645 | } | 650 | } |
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c index 01e366d2b6fb..2cabadcc4d8c 100644 --- a/drivers/acpi/processor_perflib.c +++ b/drivers/acpi/processor_perflib.c | |||
| @@ -152,15 +152,59 @@ static int acpi_processor_get_platform_limit(struct acpi_processor *pr) | |||
| 152 | return 0; | 152 | return 0; |
| 153 | } | 153 | } |
| 154 | 154 | ||
| 155 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr) | 155 | #define ACPI_PROCESSOR_NOTIFY_PERFORMANCE 0x80 |
| 156 | /* | ||
| 157 | * acpi_processor_ppc_ost: Notify firmware the _PPC evaluation status | ||
| 158 | * @handle: ACPI processor handle | ||
| 159 | * @status: the status code of _PPC evaluation | ||
| 160 | * 0: success. OSPM is now using the performance state specificed. | ||
| 161 | * 1: failure. OSPM has not changed the number of P-states in use | ||
| 162 | */ | ||
| 163 | static void acpi_processor_ppc_ost(acpi_handle handle, int status) | ||
| 164 | { | ||
| 165 | union acpi_object params[2] = { | ||
| 166 | {.type = ACPI_TYPE_INTEGER,}, | ||
| 167 | {.type = ACPI_TYPE_INTEGER,}, | ||
| 168 | }; | ||
| 169 | struct acpi_object_list arg_list = {2, params}; | ||
| 170 | acpi_handle temp; | ||
| 171 | |||
| 172 | params[0].integer.value = ACPI_PROCESSOR_NOTIFY_PERFORMANCE; | ||
| 173 | params[1].integer.value = status; | ||
| 174 | |||
| 175 | /* when there is no _OST , skip it */ | ||
| 176 | if (ACPI_FAILURE(acpi_get_handle(handle, "_OST", &temp))) | ||
| 177 | return; | ||
| 178 | |||
| 179 | acpi_evaluate_object(handle, "_OST", &arg_list, NULL); | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | |||
| 183 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag) | ||
| 156 | { | 184 | { |
| 157 | int ret; | 185 | int ret; |
| 158 | 186 | ||
| 159 | if (ignore_ppc) | 187 | if (ignore_ppc) { |
| 188 | /* | ||
| 189 | * Only when it is notification event, the _OST object | ||
| 190 | * will be evaluated. Otherwise it is skipped. | ||
| 191 | */ | ||
| 192 | if (event_flag) | ||
| 193 | acpi_processor_ppc_ost(pr->handle, 1); | ||
| 160 | return 0; | 194 | return 0; |
| 195 | } | ||
| 161 | 196 | ||
| 162 | ret = acpi_processor_get_platform_limit(pr); | 197 | ret = acpi_processor_get_platform_limit(pr); |
| 163 | 198 | /* | |
| 199 | * Only when it is notification event, the _OST object | ||
| 200 | * will be evaluated. Otherwise it is skipped. | ||
| 201 | */ | ||
| 202 | if (event_flag) { | ||
| 203 | if (ret < 0) | ||
| 204 | acpi_processor_ppc_ost(pr->handle, 1); | ||
| 205 | else | ||
| 206 | acpi_processor_ppc_ost(pr->handle, 0); | ||
| 207 | } | ||
| 164 | if (ret < 0) | 208 | if (ret < 0) |
| 165 | return (ret); | 209 | return (ret); |
| 166 | else | 210 | else |
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 65f67815902a..9073ada88835 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
| @@ -1052,6 +1052,13 @@ static int acpi_thermal_trip_seq_show(struct seq_file *seq, void *offset) | |||
| 1052 | acpi_device_bid(device)); | 1052 | acpi_device_bid(device)); |
| 1053 | } | 1053 | } |
| 1054 | seq_puts(seq, "\n"); | 1054 | seq_puts(seq, "\n"); |
| 1055 | } else { | ||
| 1056 | seq_printf(seq, "passive (forced):"); | ||
| 1057 | if (tz->thermal_zone->forced_passive) | ||
| 1058 | seq_printf(seq, " %i C\n", | ||
| 1059 | tz->thermal_zone->forced_passive / 1000); | ||
| 1060 | else | ||
| 1061 | seq_printf(seq, "<not set>\n"); | ||
| 1055 | } | 1062 | } |
| 1056 | 1063 | ||
| 1057 | for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { | 1064 | for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) { |
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index d2e698096ace..679cd08b80b4 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c | |||
| @@ -64,6 +64,7 @@ | |||
| 64 | #include <linux/dmi.h> | 64 | #include <linux/dmi.h> |
| 65 | #include <linux/string.h> | 65 | #include <linux/string.h> |
| 66 | #include <linux/ctype.h> | 66 | #include <linux/ctype.h> |
| 67 | #include <linux/pnp.h> | ||
| 67 | 68 | ||
| 68 | #ifdef CONFIG_PPC_OF | 69 | #ifdef CONFIG_PPC_OF |
| 69 | #include <linux/of_device.h> | 70 | #include <linux/of_device.h> |
| @@ -1919,7 +1920,7 @@ struct SPMITable { | |||
| 1919 | s8 spmi_id[1]; /* A '\0' terminated array starts here. */ | 1920 | s8 spmi_id[1]; /* A '\0' terminated array starts here. */ |
| 1920 | }; | 1921 | }; |
| 1921 | 1922 | ||
| 1922 | static __devinit int try_init_acpi(struct SPMITable *spmi) | 1923 | static __devinit int try_init_spmi(struct SPMITable *spmi) |
| 1923 | { | 1924 | { |
| 1924 | struct smi_info *info; | 1925 | struct smi_info *info; |
| 1925 | u8 addr_space; | 1926 | u8 addr_space; |
| @@ -1940,7 +1941,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) | |||
| 1940 | return -ENOMEM; | 1941 | return -ENOMEM; |
| 1941 | } | 1942 | } |
| 1942 | 1943 | ||
| 1943 | info->addr_source = "ACPI"; | 1944 | info->addr_source = "SPMI"; |
| 1944 | 1945 | ||
| 1945 | /* Figure out the interface type. */ | 1946 | /* Figure out the interface type. */ |
| 1946 | switch (spmi->InterfaceType) { | 1947 | switch (spmi->InterfaceType) { |
| @@ -2002,7 +2003,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi) | |||
| 2002 | return 0; | 2003 | return 0; |
| 2003 | } | 2004 | } |
| 2004 | 2005 | ||
| 2005 | static __devinit void acpi_find_bmc(void) | 2006 | static __devinit void spmi_find_bmc(void) |
| 2006 | { | 2007 | { |
| 2007 | acpi_status status; | 2008 | acpi_status status; |
| 2008 | struct SPMITable *spmi; | 2009 | struct SPMITable *spmi; |
| @@ -2020,9 +2021,106 @@ static __devinit void acpi_find_bmc(void) | |||
| 2020 | if (status != AE_OK) | 2021 | if (status != AE_OK) |
| 2021 | return; | 2022 | return; |
| 2022 | 2023 | ||
| 2023 | try_init_acpi(spmi); | 2024 | try_init_spmi(spmi); |
| 2024 | } | 2025 | } |
| 2025 | } | 2026 | } |
| 2027 | |||
| 2028 | static int __devinit ipmi_pnp_probe(struct pnp_dev *dev, | ||
| 2029 | const struct pnp_device_id *dev_id) | ||
| 2030 | { | ||
| 2031 | struct acpi_device *acpi_dev; | ||
| 2032 | struct smi_info *info; | ||
| 2033 | acpi_handle handle; | ||
| 2034 | acpi_status status; | ||
| 2035 | unsigned long long tmp; | ||
| 2036 | |||
| 2037 | acpi_dev = pnp_acpi_device(dev); | ||
| 2038 | if (!acpi_dev) | ||
| 2039 | return -ENODEV; | ||
| 2040 | |||
| 2041 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
| 2042 | if (!info) | ||
| 2043 | return -ENOMEM; | ||
| 2044 | |||
| 2045 | info->addr_source = "ACPI"; | ||
| 2046 | |||
| 2047 | handle = acpi_dev->handle; | ||
| 2048 | |||
| 2049 | /* _IFT tells us the interface type: KCS, BT, etc */ | ||
| 2050 | status = acpi_evaluate_integer(handle, "_IFT", NULL, &tmp); | ||
| 2051 | if (ACPI_FAILURE(status)) | ||
| 2052 | goto err_free; | ||
| 2053 | |||
| 2054 | switch (tmp) { | ||
| 2055 | case 1: | ||
| 2056 | info->si_type = SI_KCS; | ||
| 2057 | break; | ||
| 2058 | case 2: | ||
| 2059 | info->si_type = SI_SMIC; | ||
| 2060 | break; | ||
| 2061 | case 3: | ||
| 2062 | info->si_type = SI_BT; | ||
| 2063 | break; | ||
| 2064 | default: | ||
| 2065 | dev_info(&dev->dev, "unknown interface type %lld\n", tmp); | ||
| 2066 | goto err_free; | ||
| 2067 | } | ||
| 2068 | |||
| 2069 | if (pnp_port_valid(dev, 0)) { | ||
| 2070 | info->io_setup = port_setup; | ||
| 2071 | info->io.addr_type = IPMI_IO_ADDR_SPACE; | ||
| 2072 | info->io.addr_data = pnp_port_start(dev, 0); | ||
| 2073 | } else if (pnp_mem_valid(dev, 0)) { | ||
| 2074 | info->io_setup = mem_setup; | ||
| 2075 | info->io.addr_type = IPMI_MEM_ADDR_SPACE; | ||
| 2076 | info->io.addr_data = pnp_mem_start(dev, 0); | ||
| 2077 | } else { | ||
| 2078 | dev_err(&dev->dev, "no I/O or memory address\n"); | ||
| 2079 | goto err_free; | ||
| 2080 | } | ||
| 2081 | |||
| 2082 | info->io.regspacing = DEFAULT_REGSPACING; | ||
| 2083 | info->io.regsize = DEFAULT_REGSPACING; | ||
| 2084 | info->io.regshift = 0; | ||
| 2085 | |||
| 2086 | /* If _GPE exists, use it; otherwise use standard interrupts */ | ||
| 2087 | status = acpi_evaluate_integer(handle, "_GPE", NULL, &tmp); | ||
| 2088 | if (ACPI_SUCCESS(status)) { | ||
| 2089 | info->irq = tmp; | ||
| 2090 | info->irq_setup = acpi_gpe_irq_setup; | ||
| 2091 | } else if (pnp_irq_valid(dev, 0)) { | ||
| 2092 | info->irq = pnp_irq(dev, 0); | ||
| 2093 | info->irq_setup = std_irq_setup; | ||
| 2094 | } | ||
| 2095 | |||
| 2096 | info->dev = &acpi_dev->dev; | ||
| 2097 | pnp_set_drvdata(dev, info); | ||
| 2098 | |||
| 2099 | return try_smi_init(info); | ||
| 2100 | |||
| 2101 | err_free: | ||
| 2102 | kfree(info); | ||
| 2103 | return -EINVAL; | ||
| 2104 | } | ||
| 2105 | |||
| 2106 | static void __devexit ipmi_pnp_remove(struct pnp_dev *dev) | ||
| 2107 | { | ||
| 2108 | struct smi_info *info = pnp_get_drvdata(dev); | ||
| 2109 | |||
| 2110 | cleanup_one_si(info); | ||
| 2111 | } | ||
| 2112 | |||
| 2113 | static const struct pnp_device_id pnp_dev_table[] = { | ||
| 2114 | {"IPI0001", 0}, | ||
| 2115 | {"", 0}, | ||
| 2116 | }; | ||
| 2117 | |||
| 2118 | static struct pnp_driver ipmi_pnp_driver = { | ||
| 2119 | .name = DEVICE_NAME, | ||
| 2120 | .probe = ipmi_pnp_probe, | ||
| 2121 | .remove = __devexit_p(ipmi_pnp_remove), | ||
| 2122 | .id_table = pnp_dev_table, | ||
| 2123 | }; | ||
| 2026 | #endif | 2124 | #endif |
| 2027 | 2125 | ||
| 2028 | #ifdef CONFIG_DMI | 2126 | #ifdef CONFIG_DMI |
| @@ -2202,7 +2300,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
| 2202 | int rv; | 2300 | int rv; |
| 2203 | int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; | 2301 | int class_type = pdev->class & PCI_ERMC_CLASSCODE_TYPE_MASK; |
| 2204 | struct smi_info *info; | 2302 | struct smi_info *info; |
| 2205 | int first_reg_offset = 0; | ||
| 2206 | 2303 | ||
| 2207 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 2304 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
| 2208 | if (!info) | 2305 | if (!info) |
| @@ -2241,9 +2338,6 @@ static int __devinit ipmi_pci_probe(struct pci_dev *pdev, | |||
| 2241 | info->addr_source_cleanup = ipmi_pci_cleanup; | 2338 | info->addr_source_cleanup = ipmi_pci_cleanup; |
| 2242 | info->addr_source_data = pdev; | 2339 | info->addr_source_data = pdev; |
| 2243 | 2340 | ||
| 2244 | if (pdev->subsystem_vendor == PCI_HP_VENDOR_ID) | ||
| 2245 | first_reg_offset = 1; | ||
| 2246 | |||
| 2247 | if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { | 2341 | if (pci_resource_flags(pdev, 0) & IORESOURCE_IO) { |
| 2248 | info->io_setup = port_setup; | 2342 | info->io_setup = port_setup; |
| 2249 | info->io.addr_type = IPMI_IO_ADDR_SPACE; | 2343 | info->io.addr_type = IPMI_IO_ADDR_SPACE; |
| @@ -3108,7 +3202,10 @@ static __devinit int init_ipmi_si(void) | |||
| 3108 | #endif | 3202 | #endif |
| 3109 | 3203 | ||
| 3110 | #ifdef CONFIG_ACPI | 3204 | #ifdef CONFIG_ACPI |
| 3111 | acpi_find_bmc(); | 3205 | spmi_find_bmc(); |
| 3206 | #endif | ||
| 3207 | #ifdef CONFIG_PNP | ||
| 3208 | pnp_register_driver(&ipmi_pnp_driver); | ||
| 3112 | #endif | 3209 | #endif |
| 3113 | 3210 | ||
| 3114 | #ifdef CONFIG_PCI | 3211 | #ifdef CONFIG_PCI |
| @@ -3233,6 +3330,9 @@ static __exit void cleanup_ipmi_si(void) | |||
| 3233 | #ifdef CONFIG_PCI | 3330 | #ifdef CONFIG_PCI |
| 3234 | pci_unregister_driver(&ipmi_pci_driver); | 3331 | pci_unregister_driver(&ipmi_pci_driver); |
| 3235 | #endif | 3332 | #endif |
| 3333 | #ifdef CONFIG_PNP | ||
| 3334 | pnp_unregister_driver(&ipmi_pnp_driver); | ||
| 3335 | #endif | ||
| 3236 | 3336 | ||
| 3237 | #ifdef CONFIG_PPC_OF | 3337 | #ifdef CONFIG_PPC_OF |
| 3238 | of_unregister_platform_driver(&ipmi_of_platform_driver); | 3338 | of_unregister_platform_driver(&ipmi_of_platform_driver); |
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 59f4ba1b7034..1a7a9fc50ea1 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig | |||
| @@ -248,19 +248,6 @@ config SGI_GRU_DEBUG | |||
| 248 | This option enables addition debugging code for the SGI GRU driver. If | 248 | This option enables addition debugging code for the SGI GRU driver. If |
| 249 | you are unsure, say N. | 249 | you are unsure, say N. |
| 250 | 250 | ||
| 251 | config DELL_LAPTOP | ||
| 252 | tristate "Dell Laptop Extras (EXPERIMENTAL)" | ||
| 253 | depends on X86 | ||
| 254 | depends on DCDBAS | ||
| 255 | depends on EXPERIMENTAL | ||
| 256 | depends on BACKLIGHT_CLASS_DEVICE | ||
| 257 | depends on RFKILL | ||
| 258 | depends on POWER_SUPPLY | ||
| 259 | default n | ||
| 260 | ---help--- | ||
| 261 | This driver adds support for rfkill and backlight control to Dell | ||
| 262 | laptops. | ||
| 263 | |||
| 264 | config ISL29003 | 251 | config ISL29003 |
| 265 | tristate "Intersil ISL29003 ambient light sensor" | 252 | tristate "Intersil ISL29003 ambient light sensor" |
| 266 | depends on I2C && SYSFS | 253 | depends on I2C && SYSFS |
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 55ca39dea42e..fc5bf9d2a3f3 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
| @@ -334,6 +334,8 @@ config EEEPC_LAPTOP | |||
| 334 | depends on HOTPLUG_PCI | 334 | depends on HOTPLUG_PCI |
| 335 | select BACKLIGHT_CLASS_DEVICE | 335 | select BACKLIGHT_CLASS_DEVICE |
| 336 | select HWMON | 336 | select HWMON |
| 337 | select LEDS_CLASS | ||
| 338 | select NEW_LEDS | ||
| 337 | ---help--- | 339 | ---help--- |
| 338 | This driver supports the Fn-Fx keys on Eee PC laptops. | 340 | This driver supports the Fn-Fx keys on Eee PC laptops. |
| 339 | 341 | ||
| @@ -365,6 +367,18 @@ config ACPI_WMI | |||
| 365 | It is safe to enable this driver even if your DSDT doesn't define | 367 | It is safe to enable this driver even if your DSDT doesn't define |
| 366 | any ACPI-WMI devices. | 368 | any ACPI-WMI devices. |
| 367 | 369 | ||
| 370 | config MSI_WMI | ||
| 371 | tristate "MSI WMI extras" | ||
| 372 | depends on ACPI_WMI | ||
| 373 | depends on INPUT | ||
| 374 | depends on BACKLIGHT_CLASS_DEVICE | ||
| 375 | select INPUT_SPARSEKMAP | ||
| 376 | help | ||
| 377 | Say Y here if you want to support WMI-based hotkeys on MSI laptops. | ||
| 378 | |||
| 379 | To compile this driver as a module, choose M here: the module will | ||
| 380 | be called msi-wmi. | ||
| 381 | |||
| 368 | config ACPI_ASUS | 382 | config ACPI_ASUS |
| 369 | tristate "ASUS/Medion Laptop Extras (DEPRECATED)" | 383 | tristate "ASUS/Medion Laptop Extras (DEPRECATED)" |
| 370 | depends on ACPI | 384 | depends on ACPI |
| @@ -435,4 +449,19 @@ config ACPI_TOSHIBA | |||
| 435 | 449 | ||
| 436 | If you have a legacy free Toshiba laptop (such as the Libretto L1 | 450 | If you have a legacy free Toshiba laptop (such as the Libretto L1 |
| 437 | series), say Y. | 451 | series), say Y. |
| 452 | |||
| 453 | config TOSHIBA_BT_RFKILL | ||
| 454 | tristate "Toshiba Bluetooth RFKill switch support" | ||
| 455 | depends on ACPI | ||
| 456 | ---help--- | ||
| 457 | This driver adds support for Bluetooth events for the RFKill | ||
| 458 | switch on modern Toshiba laptops with full ACPI support and | ||
| 459 | an RFKill switch. | ||
| 460 | |||
| 461 | This driver handles RFKill events for the TOS6205 Bluetooth, | ||
| 462 | and re-enables it when the switch is set back to the 'on' | ||
| 463 | position. | ||
| 464 | |||
| 465 | If you have a modern Toshiba laptop with a Bluetooth and an | ||
| 466 | RFKill switch (such as the Portege R500), say Y. | ||
| 438 | endif # X86_PLATFORM_DEVICES | 467 | endif # X86_PLATFORM_DEVICES |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index d1c16210a512..b7474b6a8bf1 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
| @@ -18,6 +18,8 @@ obj-$(CONFIG_FUJITSU_LAPTOP) += fujitsu-laptop.o | |||
| 18 | obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o | 18 | obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o |
| 19 | obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o | 19 | obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o |
| 20 | obj-$(CONFIG_ACPI_WMI) += wmi.o | 20 | obj-$(CONFIG_ACPI_WMI) += wmi.o |
| 21 | obj-$(CONFIG_MSI_WMI) += msi-wmi.o | ||
| 21 | obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o | 22 | obj-$(CONFIG_ACPI_ASUS) += asus_acpi.o |
| 22 | obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o | 23 | obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o |
| 23 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o | 24 | obj-$(CONFIG_ACPI_TOSHIBA) += toshiba_acpi.o |
| 25 | obj-$(CONFIG_TOSHIBA_BT_RFKILL) += toshiba_bluetooth.o | ||
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index be27aa47e810..79b15b9d9cf0 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c | |||
| @@ -52,7 +52,7 @@ | |||
| 52 | */ | 52 | */ |
| 53 | #undef START_IN_KERNEL_MODE | 53 | #undef START_IN_KERNEL_MODE |
| 54 | 54 | ||
| 55 | #define DRV_VER "0.5.18" | 55 | #define DRV_VER "0.5.20" |
| 56 | 56 | ||
| 57 | /* | 57 | /* |
| 58 | * According to the Atom N270 datasheet, | 58 | * According to the Atom N270 datasheet, |
| @@ -112,12 +112,14 @@ module_param_string(force_product, force_product, 16, 0); | |||
| 112 | MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); | 112 | MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); |
| 113 | 113 | ||
| 114 | /* | 114 | /* |
| 115 | * cmd_off: to switch the fan completely off / to check if the fan is off | 115 | * cmd_off: to switch the fan completely off |
| 116 | * chk_off: to check if the fan is off | ||
| 116 | * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then | 117 | * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then |
| 117 | * the fan speed depending on the temperature | 118 | * the fan speed depending on the temperature |
| 118 | */ | 119 | */ |
| 119 | struct fancmd { | 120 | struct fancmd { |
| 120 | u8 cmd_off; | 121 | u8 cmd_off; |
| 122 | u8 chk_off; | ||
| 121 | u8 cmd_auto; | 123 | u8 cmd_auto; |
| 122 | }; | 124 | }; |
| 123 | 125 | ||
| @@ -134,32 +136,41 @@ struct bios_settings_t { | |||
| 134 | /* Register addresses and values for different BIOS versions */ | 136 | /* Register addresses and values for different BIOS versions */ |
| 135 | static const struct bios_settings_t bios_tbl[] = { | 137 | static const struct bios_settings_t bios_tbl[] = { |
| 136 | /* AOA110 */ | 138 | /* AOA110 */ |
| 137 | {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, | 139 | {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, |
| 138 | {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, | 140 | {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x1f, 0x00} }, |
| 139 | {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, | 141 | {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
| 140 | {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, | 142 | {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
| 141 | {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, | 143 | {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
| 142 | {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00} }, | 144 | {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0xaf, 0x00} }, |
| 143 | {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, | 145 | {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
| 144 | {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, | 146 | {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
| 145 | {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, | 147 | {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
| 146 | /* AOA150 */ | 148 | /* AOA150 */ |
| 147 | {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} }, | 149 | {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 148 | {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00} }, | 150 | {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 149 | {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, | 151 | {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 150 | {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, | 152 | {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 151 | {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00} }, | 153 | {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 152 | {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, | 154 | {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 153 | {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, | 155 | {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 154 | {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, | 156 | {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 157 | /* Acer 1410 */ | ||
| 158 | {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x9e, 0x00} }, | ||
| 155 | /* special BIOS / other */ | 159 | /* special BIOS / other */ |
| 156 | {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, | 160 | {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x21, 0x00} }, |
| 157 | {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, | 161 | {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x20, 0x00} }, |
| 158 | {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, | 162 | {"Gateway ", "LT31 ", "v1.3103 ", 0x55, 0x58, |
| 159 | {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, | 163 | {0x10, 0x0f, 0x00} }, |
| 160 | {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00} }, | 164 | {"Gateway ", "LT31 ", "v1.3201 ", 0x55, 0x58, |
| 165 | {0x10, 0x0f, 0x00} }, | ||
| 166 | {"Gateway ", "LT31 ", "v1.3302 ", 0x55, 0x58, | ||
| 167 | {0x10, 0x0f, 0x00} }, | ||
| 168 | {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x21, 0x00} }, | ||
| 169 | {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, | ||
| 170 | {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x21, 0x00} }, | ||
| 171 | {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x20, 0x00} }, | ||
| 161 | /* pewpew-terminator */ | 172 | /* pewpew-terminator */ |
| 162 | {"", "", "", 0, 0, {0, 0} } | 173 | {"", "", "", 0, 0, {0, 0, 0} } |
| 163 | }; | 174 | }; |
| 164 | 175 | ||
| 165 | static const struct bios_settings_t *bios_cfg __read_mostly; | 176 | static const struct bios_settings_t *bios_cfg __read_mostly; |
| @@ -183,7 +194,7 @@ static int acerhdf_get_fanstate(int *state) | |||
| 183 | if (ec_read(bios_cfg->fanreg, &fan)) | 194 | if (ec_read(bios_cfg->fanreg, &fan)) |
| 184 | return -EINVAL; | 195 | return -EINVAL; |
| 185 | 196 | ||
| 186 | if (fan != bios_cfg->cmd.cmd_off) | 197 | if (fan != bios_cfg->cmd.chk_off) |
| 187 | *state = ACERHDF_FAN_AUTO; | 198 | *state = ACERHDF_FAN_AUTO; |
| 188 | else | 199 | else |
| 189 | *state = ACERHDF_FAN_OFF; | 200 | *state = ACERHDF_FAN_OFF; |
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c index b39d2bb3e75b..61a1c7503658 100644 --- a/drivers/platform/x86/asus-laptop.c +++ b/drivers/platform/x86/asus-laptop.c | |||
| @@ -221,6 +221,7 @@ static struct asus_hotk *hotk; | |||
| 221 | */ | 221 | */ |
| 222 | static const struct acpi_device_id asus_device_ids[] = { | 222 | static const struct acpi_device_id asus_device_ids[] = { |
| 223 | {"ATK0100", 0}, | 223 | {"ATK0100", 0}, |
| 224 | {"ATK0101", 0}, | ||
| 224 | {"", 0}, | 225 | {"", 0}, |
| 225 | }; | 226 | }; |
| 226 | MODULE_DEVICE_TABLE(acpi, asus_device_ids); | 227 | MODULE_DEVICE_TABLE(acpi, asus_device_ids); |
| @@ -232,6 +233,7 @@ static void asus_hotk_notify(struct acpi_device *device, u32 event); | |||
| 232 | static struct acpi_driver asus_hotk_driver = { | 233 | static struct acpi_driver asus_hotk_driver = { |
| 233 | .name = ASUS_HOTK_NAME, | 234 | .name = ASUS_HOTK_NAME, |
| 234 | .class = ASUS_HOTK_CLASS, | 235 | .class = ASUS_HOTK_CLASS, |
| 236 | .owner = THIS_MODULE, | ||
| 235 | .ids = asus_device_ids, | 237 | .ids = asus_device_ids, |
| 236 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | 238 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, |
| 237 | .ops = { | 239 | .ops = { |
| @@ -293,6 +295,11 @@ struct key_entry { | |||
| 293 | enum { KE_KEY, KE_END }; | 295 | enum { KE_KEY, KE_END }; |
| 294 | 296 | ||
| 295 | static struct key_entry asus_keymap[] = { | 297 | static struct key_entry asus_keymap[] = { |
| 298 | {KE_KEY, 0x02, KEY_SCREENLOCK}, | ||
| 299 | {KE_KEY, 0x05, KEY_WLAN}, | ||
| 300 | {KE_KEY, 0x08, KEY_F13}, | ||
| 301 | {KE_KEY, 0x17, KEY_ZOOM}, | ||
| 302 | {KE_KEY, 0x1f, KEY_BATTERY}, | ||
| 296 | {KE_KEY, 0x30, KEY_VOLUMEUP}, | 303 | {KE_KEY, 0x30, KEY_VOLUMEUP}, |
| 297 | {KE_KEY, 0x31, KEY_VOLUMEDOWN}, | 304 | {KE_KEY, 0x31, KEY_VOLUMEDOWN}, |
| 298 | {KE_KEY, 0x32, KEY_MUTE}, | 305 | {KE_KEY, 0x32, KEY_MUTE}, |
| @@ -312,8 +319,11 @@ static struct key_entry asus_keymap[] = { | |||
| 312 | {KE_KEY, 0x5F, KEY_WLAN}, | 319 | {KE_KEY, 0x5F, KEY_WLAN}, |
| 313 | {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, | 320 | {KE_KEY, 0x60, KEY_SWITCHVIDEOMODE}, |
| 314 | {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, | 321 | {KE_KEY, 0x61, KEY_SWITCHVIDEOMODE}, |
| 315 | {KE_KEY, 0x6B, BTN_TOUCH}, /* Lock Mouse */ | 322 | {KE_KEY, 0x62, KEY_SWITCHVIDEOMODE}, |
| 323 | {KE_KEY, 0x63, KEY_SWITCHVIDEOMODE}, | ||
| 324 | {KE_KEY, 0x6B, KEY_F13}, /* Lock Touchpad */ | ||
| 316 | {KE_KEY, 0x82, KEY_CAMERA}, | 325 | {KE_KEY, 0x82, KEY_CAMERA}, |
| 326 | {KE_KEY, 0x88, KEY_WLAN }, | ||
| 317 | {KE_KEY, 0x8A, KEY_PROG1}, | 327 | {KE_KEY, 0x8A, KEY_PROG1}, |
| 318 | {KE_KEY, 0x95, KEY_MEDIA}, | 328 | {KE_KEY, 0x95, KEY_MEDIA}, |
| 319 | {KE_KEY, 0x99, KEY_PHONE}, | 329 | {KE_KEY, 0x99, KEY_PHONE}, |
| @@ -1240,9 +1250,6 @@ static int asus_hotk_add(struct acpi_device *device) | |||
| 1240 | { | 1250 | { |
| 1241 | int result; | 1251 | int result; |
| 1242 | 1252 | ||
| 1243 | if (!device) | ||
| 1244 | return -EINVAL; | ||
| 1245 | |||
| 1246 | pr_notice("Asus Laptop Support version %s\n", | 1253 | pr_notice("Asus Laptop Support version %s\n", |
| 1247 | ASUS_LAPTOP_VERSION); | 1254 | ASUS_LAPTOP_VERSION); |
| 1248 | 1255 | ||
| @@ -1283,8 +1290,8 @@ static int asus_hotk_add(struct acpi_device *device) | |||
| 1283 | hotk->ledd_status = 0xFFF; | 1290 | hotk->ledd_status = 0xFFF; |
| 1284 | 1291 | ||
| 1285 | /* Set initial values of light sensor and level */ | 1292 | /* Set initial values of light sensor and level */ |
| 1286 | hotk->light_switch = 1; /* Default to light sensor disabled */ | 1293 | hotk->light_switch = 0; /* Default to light sensor disabled */ |
| 1287 | hotk->light_level = 0; /* level 5 for sensor sensitivity */ | 1294 | hotk->light_level = 5; /* level 5 for sensor sensitivity */ |
| 1288 | 1295 | ||
| 1289 | if (ls_switch_handle) | 1296 | if (ls_switch_handle) |
| 1290 | set_light_sens_switch(hotk->light_switch); | 1297 | set_light_sens_switch(hotk->light_switch); |
| @@ -1306,9 +1313,6 @@ end: | |||
| 1306 | 1313 | ||
| 1307 | static int asus_hotk_remove(struct acpi_device *device, int type) | 1314 | static int asus_hotk_remove(struct acpi_device *device, int type) |
| 1308 | { | 1315 | { |
| 1309 | if (!device || !acpi_driver_data(device)) | ||
| 1310 | return -EINVAL; | ||
| 1311 | |||
| 1312 | kfree(hotk->name); | 1316 | kfree(hotk->name); |
| 1313 | kfree(hotk); | 1317 | kfree(hotk); |
| 1314 | 1318 | ||
| @@ -1444,9 +1448,6 @@ static int __init asus_laptop_init(void) | |||
| 1444 | { | 1448 | { |
| 1445 | int result; | 1449 | int result; |
| 1446 | 1450 | ||
| 1447 | if (acpi_disabled) | ||
| 1448 | return -ENODEV; | ||
| 1449 | |||
| 1450 | result = acpi_bus_register_driver(&asus_hotk_driver); | 1451 | result = acpi_bus_register_driver(&asus_hotk_driver); |
| 1451 | if (result < 0) | 1452 | if (result < 0) |
| 1452 | return result; | 1453 | return result; |
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c index ddf5240ade8c..0c9c53111a22 100644 --- a/drivers/platform/x86/asus_acpi.c +++ b/drivers/platform/x86/asus_acpi.c | |||
| @@ -466,6 +466,7 @@ MODULE_DEVICE_TABLE(acpi, asus_device_ids); | |||
| 466 | static struct acpi_driver asus_hotk_driver = { | 466 | static struct acpi_driver asus_hotk_driver = { |
| 467 | .name = "asus_acpi", | 467 | .name = "asus_acpi", |
| 468 | .class = ACPI_HOTK_CLASS, | 468 | .class = ACPI_HOTK_CLASS, |
| 469 | .owner = THIS_MODULE, | ||
| 469 | .ids = asus_device_ids, | 470 | .ids = asus_device_ids, |
| 470 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | 471 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, |
| 471 | .ops = { | 472 | .ops = { |
| @@ -1334,9 +1335,6 @@ static int asus_hotk_add(struct acpi_device *device) | |||
| 1334 | acpi_status status = AE_OK; | 1335 | acpi_status status = AE_OK; |
| 1335 | int result; | 1336 | int result; |
| 1336 | 1337 | ||
| 1337 | if (!device) | ||
| 1338 | return -EINVAL; | ||
| 1339 | |||
| 1340 | printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", | 1338 | printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n", |
| 1341 | ASUS_ACPI_VERSION); | 1339 | ASUS_ACPI_VERSION); |
| 1342 | 1340 | ||
| @@ -1392,9 +1390,6 @@ end: | |||
| 1392 | 1390 | ||
| 1393 | static int asus_hotk_remove(struct acpi_device *device, int type) | 1391 | static int asus_hotk_remove(struct acpi_device *device, int type) |
| 1394 | { | 1392 | { |
| 1395 | if (!device || !acpi_driver_data(device)) | ||
| 1396 | return -EINVAL; | ||
| 1397 | |||
| 1398 | asus_hotk_remove_fs(device); | 1393 | asus_hotk_remove_fs(device); |
| 1399 | 1394 | ||
| 1400 | kfree(hotk); | 1395 | kfree(hotk); |
| @@ -1422,21 +1417,17 @@ static int __init asus_acpi_init(void) | |||
| 1422 | { | 1417 | { |
| 1423 | int result; | 1418 | int result; |
| 1424 | 1419 | ||
| 1425 | if (acpi_disabled) | 1420 | result = acpi_bus_register_driver(&asus_hotk_driver); |
| 1426 | return -ENODEV; | 1421 | if (result < 0) |
| 1422 | return result; | ||
| 1427 | 1423 | ||
| 1428 | asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); | 1424 | asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir); |
| 1429 | if (!asus_proc_dir) { | 1425 | if (!asus_proc_dir) { |
| 1430 | printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); | 1426 | printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n"); |
| 1427 | acpi_bus_unregister_driver(&asus_hotk_driver); | ||
| 1431 | return -ENODEV; | 1428 | return -ENODEV; |
| 1432 | } | 1429 | } |
| 1433 | 1430 | ||
| 1434 | result = acpi_bus_register_driver(&asus_hotk_driver); | ||
| 1435 | if (result < 0) { | ||
| 1436 | remove_proc_entry(PROC_ASUS, acpi_root_dir); | ||
| 1437 | return result; | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | /* | 1431 | /* |
| 1441 | * This is a bit of a kludge. We only want this module loaded | 1432 | * This is a bit of a kludge. We only want this module loaded |
| 1442 | * for ASUS systems, but there's currently no way to probe the | 1433 | * for ASUS systems, but there's currently no way to probe the |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 74909c4aaeea..3780994dc8f2 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
| @@ -58,6 +58,14 @@ static int da_command_code; | |||
| 58 | static int da_num_tokens; | 58 | static int da_num_tokens; |
| 59 | static struct calling_interface_token *da_tokens; | 59 | static struct calling_interface_token *da_tokens; |
| 60 | 60 | ||
| 61 | static struct platform_driver platform_driver = { | ||
| 62 | .driver = { | ||
| 63 | .name = "dell-laptop", | ||
| 64 | .owner = THIS_MODULE, | ||
| 65 | } | ||
| 66 | }; | ||
| 67 | |||
| 68 | static struct platform_device *platform_device; | ||
| 61 | static struct backlight_device *dell_backlight_device; | 69 | static struct backlight_device *dell_backlight_device; |
| 62 | static struct rfkill *wifi_rfkill; | 70 | static struct rfkill *wifi_rfkill; |
| 63 | static struct rfkill *bluetooth_rfkill; | 71 | static struct rfkill *bluetooth_rfkill; |
| @@ -74,7 +82,7 @@ static const struct dmi_system_id __initdata dell_device_table[] = { | |||
| 74 | { } | 82 | { } |
| 75 | }; | 83 | }; |
| 76 | 84 | ||
| 77 | static void parse_da_table(const struct dmi_header *dm) | 85 | static void __init parse_da_table(const struct dmi_header *dm) |
| 78 | { | 86 | { |
| 79 | /* Final token is a terminator, so we don't want to copy it */ | 87 | /* Final token is a terminator, so we don't want to copy it */ |
| 80 | int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; | 88 | 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) | |||
| 103 | da_num_tokens += tokens; | 111 | da_num_tokens += tokens; |
| 104 | } | 112 | } |
| 105 | 113 | ||
| 106 | static void find_tokens(const struct dmi_header *dm, void *dummy) | 114 | static void __init find_tokens(const struct dmi_header *dm, void *dummy) |
| 107 | { | 115 | { |
| 108 | switch (dm->type) { | 116 | switch (dm->type) { |
| 109 | case 0xd4: /* Indexed IO */ | 117 | case 0xd4: /* Indexed IO */ |
| @@ -197,8 +205,8 @@ static void dell_rfkill_query(struct rfkill *rfkill, void *data) | |||
| 197 | dell_send_request(&buffer, 17, 11); | 205 | dell_send_request(&buffer, 17, 11); |
| 198 | status = buffer.output[1]; | 206 | status = buffer.output[1]; |
| 199 | 207 | ||
| 200 | if (status & BIT(bit)) | 208 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); |
| 201 | rfkill_set_hw_state(rfkill, !!(status & BIT(16))); | 209 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); |
| 202 | } | 210 | } |
| 203 | 211 | ||
| 204 | static const struct rfkill_ops dell_rfkill_ops = { | 212 | static const struct rfkill_ops dell_rfkill_ops = { |
| @@ -206,7 +214,7 @@ static const struct rfkill_ops dell_rfkill_ops = { | |||
| 206 | .query = dell_rfkill_query, | 214 | .query = dell_rfkill_query, |
| 207 | }; | 215 | }; |
| 208 | 216 | ||
| 209 | static int dell_setup_rfkill(void) | 217 | static int __init dell_setup_rfkill(void) |
| 210 | { | 218 | { |
| 211 | struct calling_interface_buffer buffer; | 219 | struct calling_interface_buffer buffer; |
| 212 | int status; | 220 | int status; |
| @@ -217,7 +225,8 @@ static int dell_setup_rfkill(void) | |||
| 217 | status = buffer.output[1]; | 225 | status = buffer.output[1]; |
| 218 | 226 | ||
| 219 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | 227 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { |
| 220 | wifi_rfkill = rfkill_alloc("dell-wifi", NULL, RFKILL_TYPE_WLAN, | 228 | wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, |
| 229 | RFKILL_TYPE_WLAN, | ||
| 221 | &dell_rfkill_ops, (void *) 1); | 230 | &dell_rfkill_ops, (void *) 1); |
| 222 | if (!wifi_rfkill) { | 231 | if (!wifi_rfkill) { |
| 223 | ret = -ENOMEM; | 232 | ret = -ENOMEM; |
| @@ -229,7 +238,8 @@ static int dell_setup_rfkill(void) | |||
| 229 | } | 238 | } |
| 230 | 239 | ||
| 231 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { | 240 | if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { |
| 232 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", NULL, | 241 | bluetooth_rfkill = rfkill_alloc("dell-bluetooth", |
| 242 | &platform_device->dev, | ||
| 233 | RFKILL_TYPE_BLUETOOTH, | 243 | RFKILL_TYPE_BLUETOOTH, |
| 234 | &dell_rfkill_ops, (void *) 2); | 244 | &dell_rfkill_ops, (void *) 2); |
| 235 | if (!bluetooth_rfkill) { | 245 | if (!bluetooth_rfkill) { |
| @@ -242,7 +252,9 @@ static int dell_setup_rfkill(void) | |||
| 242 | } | 252 | } |
| 243 | 253 | ||
| 244 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { | 254 | if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { |
| 245 | wwan_rfkill = rfkill_alloc("dell-wwan", NULL, RFKILL_TYPE_WWAN, | 255 | wwan_rfkill = rfkill_alloc("dell-wwan", |
| 256 | &platform_device->dev, | ||
| 257 | RFKILL_TYPE_WWAN, | ||
| 246 | &dell_rfkill_ops, (void *) 3); | 258 | &dell_rfkill_ops, (void *) 3); |
| 247 | if (!wwan_rfkill) { | 259 | if (!wwan_rfkill) { |
| 248 | ret = -ENOMEM; | 260 | ret = -ENOMEM; |
| @@ -268,6 +280,22 @@ err_wifi: | |||
| 268 | return ret; | 280 | return ret; |
| 269 | } | 281 | } |
| 270 | 282 | ||
| 283 | static void dell_cleanup_rfkill(void) | ||
| 284 | { | ||
| 285 | if (wifi_rfkill) { | ||
| 286 | rfkill_unregister(wifi_rfkill); | ||
| 287 | rfkill_destroy(wifi_rfkill); | ||
| 288 | } | ||
| 289 | if (bluetooth_rfkill) { | ||
| 290 | rfkill_unregister(bluetooth_rfkill); | ||
| 291 | rfkill_destroy(bluetooth_rfkill); | ||
| 292 | } | ||
| 293 | if (wwan_rfkill) { | ||
| 294 | rfkill_unregister(wwan_rfkill); | ||
| 295 | rfkill_destroy(wwan_rfkill); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 271 | static int dell_send_intensity(struct backlight_device *bd) | 299 | static int dell_send_intensity(struct backlight_device *bd) |
| 272 | { | 300 | { |
| 273 | struct calling_interface_buffer buffer; | 301 | struct calling_interface_buffer buffer; |
| @@ -326,11 +354,23 @@ static int __init dell_init(void) | |||
| 326 | return -ENODEV; | 354 | return -ENODEV; |
| 327 | } | 355 | } |
| 328 | 356 | ||
| 357 | ret = platform_driver_register(&platform_driver); | ||
| 358 | if (ret) | ||
| 359 | goto fail_platform_driver; | ||
| 360 | platform_device = platform_device_alloc("dell-laptop", -1); | ||
| 361 | if (!platform_device) { | ||
| 362 | ret = -ENOMEM; | ||
| 363 | goto fail_platform_device1; | ||
| 364 | } | ||
| 365 | ret = platform_device_add(platform_device); | ||
| 366 | if (ret) | ||
| 367 | goto fail_platform_device2; | ||
| 368 | |||
| 329 | ret = dell_setup_rfkill(); | 369 | ret = dell_setup_rfkill(); |
| 330 | 370 | ||
| 331 | if (ret) { | 371 | if (ret) { |
| 332 | printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); | 372 | printk(KERN_WARNING "dell-laptop: Unable to setup rfkill\n"); |
| 333 | goto out; | 373 | goto fail_rfkill; |
| 334 | } | 374 | } |
| 335 | 375 | ||
| 336 | #ifdef CONFIG_ACPI | 376 | #ifdef CONFIG_ACPI |
| @@ -352,13 +392,13 @@ static int __init dell_init(void) | |||
| 352 | if (max_intensity) { | 392 | if (max_intensity) { |
| 353 | dell_backlight_device = backlight_device_register( | 393 | dell_backlight_device = backlight_device_register( |
| 354 | "dell_backlight", | 394 | "dell_backlight", |
| 355 | NULL, NULL, | 395 | &platform_device->dev, NULL, |
| 356 | &dell_ops); | 396 | &dell_ops); |
| 357 | 397 | ||
| 358 | if (IS_ERR(dell_backlight_device)) { | 398 | if (IS_ERR(dell_backlight_device)) { |
| 359 | ret = PTR_ERR(dell_backlight_device); | 399 | ret = PTR_ERR(dell_backlight_device); |
| 360 | dell_backlight_device = NULL; | 400 | dell_backlight_device = NULL; |
| 361 | goto out; | 401 | goto fail_backlight; |
| 362 | } | 402 | } |
| 363 | 403 | ||
| 364 | dell_backlight_device->props.max_brightness = max_intensity; | 404 | dell_backlight_device->props.max_brightness = max_intensity; |
| @@ -368,13 +408,16 @@ static int __init dell_init(void) | |||
| 368 | } | 408 | } |
| 369 | 409 | ||
| 370 | return 0; | 410 | return 0; |
| 371 | out: | 411 | |
| 372 | if (wifi_rfkill) | 412 | fail_backlight: |
| 373 | rfkill_unregister(wifi_rfkill); | 413 | dell_cleanup_rfkill(); |
| 374 | if (bluetooth_rfkill) | 414 | fail_rfkill: |
| 375 | rfkill_unregister(bluetooth_rfkill); | 415 | platform_device_del(platform_device); |
| 376 | if (wwan_rfkill) | 416 | fail_platform_device2: |
| 377 | rfkill_unregister(wwan_rfkill); | 417 | platform_device_put(platform_device); |
| 418 | fail_platform_device1: | ||
| 419 | platform_driver_unregister(&platform_driver); | ||
| 420 | fail_platform_driver: | ||
| 378 | kfree(da_tokens); | 421 | kfree(da_tokens); |
| 379 | return ret; | 422 | return ret; |
| 380 | } | 423 | } |
| @@ -382,12 +425,7 @@ out: | |||
| 382 | static void __exit dell_exit(void) | 425 | static void __exit dell_exit(void) |
| 383 | { | 426 | { |
| 384 | backlight_device_unregister(dell_backlight_device); | 427 | backlight_device_unregister(dell_backlight_device); |
| 385 | if (wifi_rfkill) | 428 | dell_cleanup_rfkill(); |
| 386 | rfkill_unregister(wifi_rfkill); | ||
| 387 | if (bluetooth_rfkill) | ||
| 388 | rfkill_unregister(bluetooth_rfkill); | ||
| 389 | if (wwan_rfkill) | ||
| 390 | rfkill_unregister(wwan_rfkill); | ||
| 391 | } | 429 | } |
| 392 | 430 | ||
| 393 | module_init(dell_init); | 431 | module_init(dell_init); |
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 0f900cc9fa7a..67f3fe71c509 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include <acpi/acpi_drivers.h> | 31 | #include <acpi/acpi_drivers.h> |
| 32 | #include <linux/acpi.h> | 32 | #include <linux/acpi.h> |
| 33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| 34 | #include <linux/dmi.h> | ||
| 34 | 35 | ||
| 35 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); | 36 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); |
| 36 | MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); | 37 | MODULE_DESCRIPTION("Dell laptop WMI hotkeys driver"); |
| @@ -38,6 +39,8 @@ MODULE_LICENSE("GPL"); | |||
| 38 | 39 | ||
| 39 | #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" | 40 | #define DELL_EVENT_GUID "9DBB5994-A997-11DA-B012-B622A1EF5492" |
| 40 | 41 | ||
| 42 | static int acpi_video; | ||
| 43 | |||
| 41 | MODULE_ALIAS("wmi:"DELL_EVENT_GUID); | 44 | MODULE_ALIAS("wmi:"DELL_EVENT_GUID); |
| 42 | 45 | ||
| 43 | struct key_entry { | 46 | struct key_entry { |
| @@ -54,7 +57,7 @@ enum { KE_KEY, KE_SW, KE_IGNORE, KE_END }; | |||
| 54 | * via the keyboard controller so should not be sent again. | 57 | * via the keyboard controller so should not be sent again. |
| 55 | */ | 58 | */ |
| 56 | 59 | ||
| 57 | static struct key_entry dell_wmi_keymap[] = { | 60 | static struct key_entry dell_legacy_wmi_keymap[] = { |
| 58 | {KE_KEY, 0xe045, KEY_PROG1}, | 61 | {KE_KEY, 0xe045, KEY_PROG1}, |
| 59 | {KE_KEY, 0xe009, KEY_EJECTCD}, | 62 | {KE_KEY, 0xe009, KEY_EJECTCD}, |
| 60 | 63 | ||
| @@ -72,7 +75,7 @@ static struct key_entry dell_wmi_keymap[] = { | |||
| 72 | 75 | ||
| 73 | /* The next device is at offset 6, the active devices are at | 76 | /* The next device is at offset 6, the active devices are at |
| 74 | offset 8 and the attached devices at offset 10 */ | 77 | offset 8 and the attached devices at offset 10 */ |
| 75 | {KE_KEY, 0xe00b, KEY_DISPLAYTOGGLE}, | 78 | {KE_KEY, 0xe00b, KEY_SWITCHVIDEOMODE}, |
| 76 | 79 | ||
| 77 | {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, | 80 | {KE_IGNORE, 0xe00c, KEY_KBDILLUMTOGGLE}, |
| 78 | 81 | ||
| @@ -96,6 +99,47 @@ static struct key_entry dell_wmi_keymap[] = { | |||
| 96 | {KE_END, 0} | 99 | {KE_END, 0} |
| 97 | }; | 100 | }; |
| 98 | 101 | ||
| 102 | static bool dell_new_hk_type; | ||
| 103 | |||
| 104 | struct dell_new_keymap_entry { | ||
| 105 | u16 scancode; | ||
| 106 | u16 keycode; | ||
| 107 | }; | ||
| 108 | |||
| 109 | struct dell_hotkey_table { | ||
| 110 | struct dmi_header header; | ||
| 111 | struct dell_new_keymap_entry keymap[]; | ||
| 112 | |||
| 113 | }; | ||
| 114 | |||
| 115 | static struct key_entry *dell_new_wmi_keymap; | ||
| 116 | |||
| 117 | static u16 bios_to_linux_keycode[256] = { | ||
| 118 | |||
| 119 | KEY_MEDIA, KEY_NEXTSONG, KEY_PLAYPAUSE, KEY_PREVIOUSSONG, | ||
| 120 | KEY_STOPCD, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 121 | KEY_WWW, KEY_UNKNOWN, KEY_VOLUMEDOWN, KEY_MUTE, | ||
| 122 | KEY_VOLUMEUP, KEY_UNKNOWN, KEY_BATTERY, KEY_EJECTCD, | ||
| 123 | KEY_UNKNOWN, KEY_SLEEP, KEY_PROG1, KEY_BRIGHTNESSDOWN, | ||
| 124 | KEY_BRIGHTNESSUP, KEY_UNKNOWN, KEY_KBDILLUMTOGGLE, | ||
| 125 | KEY_UNKNOWN, KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, | ||
| 126 | KEY_SWITCHVIDEOMODE, KEY_UNKNOWN, KEY_UNKNOWN, KEY_PROG2, | ||
| 127 | KEY_UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 128 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 129 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 130 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 131 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 132 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 133 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 134 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 135 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 136 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
| 137 | KEY_PROG3 | ||
| 138 | }; | ||
| 139 | |||
| 140 | |||
| 141 | static struct key_entry *dell_wmi_keymap = dell_legacy_wmi_keymap; | ||
| 142 | |||
| 99 | static struct input_dev *dell_wmi_input_dev; | 143 | static struct input_dev *dell_wmi_input_dev; |
| 100 | 144 | ||
| 101 | static struct key_entry *dell_wmi_get_entry_by_scancode(int code) | 145 | 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) | |||
| 164 | obj = (union acpi_object *)response.pointer; | 208 | obj = (union acpi_object *)response.pointer; |
| 165 | 209 | ||
| 166 | if (obj && obj->type == ACPI_TYPE_BUFFER) { | 210 | if (obj && obj->type == ACPI_TYPE_BUFFER) { |
| 167 | int *buffer = (int *)obj->buffer.pointer; | 211 | int reported_key; |
| 168 | /* | 212 | u16 *buffer_entry = (u16 *)obj->buffer.pointer; |
| 169 | * The upper bytes of the event may contain | 213 | if (dell_new_hk_type && (buffer_entry[1] != 0x10)) { |
| 170 | * additional information, so mask them off for the | 214 | printk(KERN_INFO "dell-wmi: Received unknown WMI event" |
| 171 | * scancode lookup | 215 | " (0x%x)\n", buffer_entry[1]); |
| 172 | */ | 216 | return; |
| 173 | key = dell_wmi_get_entry_by_scancode(buffer[1] & 0xFFFF); | 217 | } |
| 174 | if (key) { | 218 | |
| 219 | if (dell_new_hk_type) | ||
| 220 | reported_key = (int)buffer_entry[2]; | ||
| 221 | else | ||
| 222 | reported_key = (int)buffer_entry[1] & 0xffff; | ||
| 223 | |||
| 224 | key = dell_wmi_get_entry_by_scancode(reported_key); | ||
| 225 | |||
| 226 | if (!key) { | ||
| 227 | printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n", | ||
| 228 | reported_key); | ||
| 229 | } else if ((key->keycode == KEY_BRIGHTNESSUP || | ||
| 230 | key->keycode == KEY_BRIGHTNESSDOWN) && acpi_video) { | ||
| 231 | /* Don't report brightness notifications that will also | ||
| 232 | * come via ACPI */ | ||
| 233 | return; | ||
| 234 | } else { | ||
| 175 | input_report_key(dell_wmi_input_dev, key->keycode, 1); | 235 | input_report_key(dell_wmi_input_dev, key->keycode, 1); |
| 176 | input_sync(dell_wmi_input_dev); | 236 | input_sync(dell_wmi_input_dev); |
| 177 | input_report_key(dell_wmi_input_dev, key->keycode, 0); | 237 | input_report_key(dell_wmi_input_dev, key->keycode, 0); |
| 178 | input_sync(dell_wmi_input_dev); | 238 | input_sync(dell_wmi_input_dev); |
| 179 | } else if (buffer[1] & 0xFFFF) | 239 | } |
| 180 | printk(KERN_INFO "dell-wmi: Unknown key %x pressed\n", | ||
| 181 | buffer[1] & 0xFFFF); | ||
| 182 | } | 240 | } |
| 183 | } | 241 | } |
| 184 | 242 | ||
| 243 | |||
| 244 | static void setup_new_hk_map(const struct dmi_header *dm) | ||
| 245 | { | ||
| 246 | |||
| 247 | int i; | ||
| 248 | int hotkey_num = (dm->length-4)/sizeof(struct dell_new_keymap_entry); | ||
| 249 | struct dell_hotkey_table *table = | ||
| 250 | container_of(dm, struct dell_hotkey_table, header); | ||
| 251 | |||
| 252 | dell_new_wmi_keymap = kzalloc((hotkey_num+1) * | ||
| 253 | sizeof(struct key_entry), GFP_KERNEL); | ||
| 254 | |||
| 255 | for (i = 0; i < hotkey_num; i++) { | ||
| 256 | dell_new_wmi_keymap[i].type = KE_KEY; | ||
| 257 | dell_new_wmi_keymap[i].code = table->keymap[i].scancode; | ||
| 258 | dell_new_wmi_keymap[i].keycode = | ||
| 259 | (table->keymap[i].keycode > 255) ? 0 : | ||
| 260 | bios_to_linux_keycode[table->keymap[i].keycode]; | ||
| 261 | } | ||
| 262 | |||
| 263 | dell_new_wmi_keymap[i].type = KE_END; | ||
| 264 | dell_new_wmi_keymap[i].code = 0; | ||
| 265 | dell_new_wmi_keymap[i].keycode = 0; | ||
| 266 | |||
| 267 | dell_wmi_keymap = dell_new_wmi_keymap; | ||
| 268 | |||
| 269 | } | ||
| 270 | |||
| 271 | |||
| 272 | static void find_hk_type(const struct dmi_header *dm, void *dummy) | ||
| 273 | { | ||
| 274 | |||
| 275 | if ((dm->type == 0xb2) && (dm->length > 6)) { | ||
| 276 | dell_new_hk_type = true; | ||
| 277 | setup_new_hk_map(dm); | ||
| 278 | } | ||
| 279 | |||
| 280 | } | ||
| 281 | |||
| 282 | |||
| 185 | static int __init dell_wmi_input_setup(void) | 283 | static int __init dell_wmi_input_setup(void) |
| 186 | { | 284 | { |
| 187 | struct key_entry *key; | 285 | struct key_entry *key; |
| @@ -226,6 +324,9 @@ static int __init dell_wmi_init(void) | |||
| 226 | int err; | 324 | int err; |
| 227 | 325 | ||
| 228 | if (wmi_has_guid(DELL_EVENT_GUID)) { | 326 | if (wmi_has_guid(DELL_EVENT_GUID)) { |
| 327 | |||
| 328 | dmi_walk(find_hk_type, NULL); | ||
| 329 | |||
| 229 | err = dell_wmi_input_setup(); | 330 | err = dell_wmi_input_setup(); |
| 230 | 331 | ||
| 231 | if (err) | 332 | if (err) |
| @@ -240,6 +341,8 @@ static int __init dell_wmi_init(void) | |||
| 240 | return err; | 341 | return err; |
| 241 | } | 342 | } |
| 242 | 343 | ||
| 344 | acpi_video = acpi_video_backlight_support(); | ||
| 345 | |||
| 243 | } else | 346 | } else |
| 244 | printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); | 347 | printk(KERN_WARNING "dell-wmi: No known WMI GUID found\n"); |
| 245 | 348 | ||
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c index e647a856b9bf..5838c69b2fb3 100644 --- a/drivers/platform/x86/eeepc-laptop.c +++ b/drivers/platform/x86/eeepc-laptop.c | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * eepc-laptop.c - Asus Eee PC extras | 2 | * eeepc-laptop.c - Asus Eee PC extras |
| 3 | * | 3 | * |
| 4 | * Based on asus_acpi.c as patched for the Eee PC by Asus: | 4 | * Based on asus_acpi.c as patched for the Eee PC by Asus: |
| 5 | * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar | 5 | * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar |
| @@ -34,20 +34,23 @@ | |||
| 34 | #include <linux/rfkill.h> | 34 | #include <linux/rfkill.h> |
| 35 | #include <linux/pci.h> | 35 | #include <linux/pci.h> |
| 36 | #include <linux/pci_hotplug.h> | 36 | #include <linux/pci_hotplug.h> |
| 37 | #include <linux/leds.h> | ||
| 37 | 38 | ||
| 38 | #define EEEPC_LAPTOP_VERSION "0.1" | 39 | #define EEEPC_LAPTOP_VERSION "0.1" |
| 40 | #define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver" | ||
| 41 | #define EEEPC_LAPTOP_FILE "eeepc" | ||
| 39 | 42 | ||
| 40 | #define EEEPC_HOTK_NAME "Eee PC Hotkey Driver" | 43 | #define EEEPC_ACPI_CLASS "hotkey" |
| 41 | #define EEEPC_HOTK_FILE "eeepc" | 44 | #define EEEPC_ACPI_DEVICE_NAME "Hotkey" |
| 42 | #define EEEPC_HOTK_CLASS "hotkey" | 45 | #define EEEPC_ACPI_HID "ASUS010" |
| 43 | #define EEEPC_HOTK_DEVICE_NAME "Hotkey" | ||
| 44 | #define EEEPC_HOTK_HID "ASUS010" | ||
| 45 | 46 | ||
| 47 | MODULE_AUTHOR("Corentin Chary, Eric Cooper"); | ||
| 48 | MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME); | ||
| 49 | MODULE_LICENSE("GPL"); | ||
| 46 | 50 | ||
| 47 | /* | 51 | /* |
| 48 | * Definitions for Asus EeePC | 52 | * Definitions for Asus EeePC |
| 49 | */ | 53 | */ |
| 50 | #define NOTIFY_WLAN_ON 0x10 | ||
| 51 | #define NOTIFY_BRN_MIN 0x20 | 54 | #define NOTIFY_BRN_MIN 0x20 |
| 52 | #define NOTIFY_BRN_MAX 0x2f | 55 | #define NOTIFY_BRN_MAX 0x2f |
| 53 | 56 | ||
| @@ -117,58 +120,6 @@ static const char *cm_setv[] = { | |||
| 117 | NULL, NULL, "PBPS", "TPDS" | 120 | NULL, NULL, "PBPS", "TPDS" |
| 118 | }; | 121 | }; |
| 119 | 122 | ||
| 120 | #define EEEPC_EC "\\_SB.PCI0.SBRG.EC0." | ||
| 121 | |||
| 122 | #define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */ | ||
| 123 | #define EEEPC_EC_SC02 0x63 | ||
| 124 | #define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */ | ||
| 125 | #define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */ | ||
| 126 | #define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */ | ||
| 127 | #define EEEPC_EC_SFB3 0xD3 | ||
| 128 | |||
| 129 | /* | ||
| 130 | * This is the main structure, we can use it to store useful information | ||
| 131 | * about the hotk device | ||
| 132 | */ | ||
| 133 | struct eeepc_hotk { | ||
| 134 | struct acpi_device *device; /* the device we are in */ | ||
| 135 | acpi_handle handle; /* the handle of the hotk device */ | ||
| 136 | u32 cm_supported; /* the control methods supported | ||
| 137 | by this BIOS */ | ||
| 138 | uint init_flag; /* Init flags */ | ||
| 139 | u16 event_count[128]; /* count for each event */ | ||
| 140 | struct input_dev *inputdev; | ||
| 141 | u16 *keycode_map; | ||
| 142 | struct rfkill *wlan_rfkill; | ||
| 143 | struct rfkill *bluetooth_rfkill; | ||
| 144 | struct rfkill *wwan3g_rfkill; | ||
| 145 | struct rfkill *wimax_rfkill; | ||
| 146 | struct hotplug_slot *hotplug_slot; | ||
| 147 | struct mutex hotplug_lock; | ||
| 148 | }; | ||
| 149 | |||
| 150 | /* The actual device the driver binds to */ | ||
| 151 | static struct eeepc_hotk *ehotk; | ||
| 152 | |||
| 153 | /* Platform device/driver */ | ||
| 154 | static int eeepc_hotk_thaw(struct device *device); | ||
| 155 | static int eeepc_hotk_restore(struct device *device); | ||
| 156 | |||
| 157 | static const struct dev_pm_ops eeepc_pm_ops = { | ||
| 158 | .thaw = eeepc_hotk_thaw, | ||
| 159 | .restore = eeepc_hotk_restore, | ||
| 160 | }; | ||
| 161 | |||
| 162 | static struct platform_driver platform_driver = { | ||
| 163 | .driver = { | ||
| 164 | .name = EEEPC_HOTK_FILE, | ||
| 165 | .owner = THIS_MODULE, | ||
| 166 | .pm = &eeepc_pm_ops, | ||
| 167 | } | ||
| 168 | }; | ||
| 169 | |||
| 170 | static struct platform_device *platform_device; | ||
| 171 | |||
| 172 | struct key_entry { | 123 | struct key_entry { |
| 173 | char type; | 124 | char type; |
| 174 | u8 code; | 125 | u8 code; |
| @@ -177,7 +128,7 @@ struct key_entry { | |||
| 177 | 128 | ||
| 178 | enum { KE_KEY, KE_END }; | 129 | enum { KE_KEY, KE_END }; |
| 179 | 130 | ||
| 180 | static struct key_entry eeepc_keymap[] = { | 131 | static const struct key_entry eeepc_keymap[] = { |
| 181 | /* Sleep already handled via generic ACPI code */ | 132 | /* Sleep already handled via generic ACPI code */ |
| 182 | {KE_KEY, 0x10, KEY_WLAN }, | 133 | {KE_KEY, 0x10, KEY_WLAN }, |
| 183 | {KE_KEY, 0x11, KEY_WLAN }, | 134 | {KE_KEY, 0x11, KEY_WLAN }, |
| @@ -185,77 +136,56 @@ static struct key_entry eeepc_keymap[] = { | |||
| 185 | {KE_KEY, 0x13, KEY_MUTE }, | 136 | {KE_KEY, 0x13, KEY_MUTE }, |
| 186 | {KE_KEY, 0x14, KEY_VOLUMEDOWN }, | 137 | {KE_KEY, 0x14, KEY_VOLUMEDOWN }, |
| 187 | {KE_KEY, 0x15, KEY_VOLUMEUP }, | 138 | {KE_KEY, 0x15, KEY_VOLUMEUP }, |
| 139 | {KE_KEY, 0x16, KEY_DISPLAY_OFF }, | ||
| 188 | {KE_KEY, 0x1a, KEY_COFFEE }, | 140 | {KE_KEY, 0x1a, KEY_COFFEE }, |
| 189 | {KE_KEY, 0x1b, KEY_ZOOM }, | 141 | {KE_KEY, 0x1b, KEY_ZOOM }, |
| 190 | {KE_KEY, 0x1c, KEY_PROG2 }, | 142 | {KE_KEY, 0x1c, KEY_PROG2 }, |
| 191 | {KE_KEY, 0x1d, KEY_PROG3 }, | 143 | {KE_KEY, 0x1d, KEY_PROG3 }, |
| 192 | {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN }, | 144 | {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN }, |
| 193 | {KE_KEY, NOTIFY_BRN_MIN + 2, KEY_BRIGHTNESSUP }, | 145 | {KE_KEY, NOTIFY_BRN_MAX, KEY_BRIGHTNESSUP }, |
| 194 | {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, | 146 | {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE }, |
| 195 | {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, | 147 | {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE }, |
| 196 | {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, | 148 | {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE }, |
| 149 | {KE_KEY, 0x37, KEY_F13 }, /* Disable Touchpad */ | ||
| 150 | {KE_KEY, 0x38, KEY_F14 }, | ||
| 197 | {KE_END, 0}, | 151 | {KE_END, 0}, |
| 198 | }; | 152 | }; |
| 199 | 153 | ||
| 154 | |||
| 200 | /* | 155 | /* |
| 201 | * The hotkey driver declaration | 156 | * This is the main structure, we can use it to store useful information |
| 202 | */ | 157 | */ |
| 203 | static int eeepc_hotk_add(struct acpi_device *device); | 158 | struct eeepc_laptop { |
| 204 | static int eeepc_hotk_remove(struct acpi_device *device, int type); | 159 | acpi_handle handle; /* the handle of the acpi device */ |
| 205 | static void eeepc_hotk_notify(struct acpi_device *device, u32 event); | 160 | u32 cm_supported; /* the control methods supported |
| 206 | 161 | by this BIOS */ | |
| 207 | static const struct acpi_device_id eeepc_device_ids[] = { | 162 | u16 event_count[128]; /* count for each event */ |
| 208 | {EEEPC_HOTK_HID, 0}, | ||
| 209 | {"", 0}, | ||
| 210 | }; | ||
| 211 | MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); | ||
| 212 | |||
| 213 | static struct acpi_driver eeepc_hotk_driver = { | ||
| 214 | .name = EEEPC_HOTK_NAME, | ||
| 215 | .class = EEEPC_HOTK_CLASS, | ||
| 216 | .ids = eeepc_device_ids, | ||
| 217 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | ||
| 218 | .ops = { | ||
| 219 | .add = eeepc_hotk_add, | ||
| 220 | .remove = eeepc_hotk_remove, | ||
| 221 | .notify = eeepc_hotk_notify, | ||
| 222 | }, | ||
| 223 | }; | ||
| 224 | 163 | ||
| 225 | /* PCI hotplug ops */ | 164 | struct platform_device *platform_device; |
| 226 | static int eeepc_get_adapter_status(struct hotplug_slot *slot, u8 *value); | 165 | struct device *hwmon_device; |
| 166 | struct backlight_device *backlight_device; | ||
| 227 | 167 | ||
| 228 | static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { | 168 | struct input_dev *inputdev; |
| 229 | .owner = THIS_MODULE, | 169 | struct key_entry *keymap; |
| 230 | .get_adapter_status = eeepc_get_adapter_status, | ||
| 231 | .get_power_status = eeepc_get_adapter_status, | ||
| 232 | }; | ||
| 233 | 170 | ||
| 234 | /* The backlight device /sys/class/backlight */ | 171 | struct rfkill *wlan_rfkill; |
| 235 | static struct backlight_device *eeepc_backlight_device; | 172 | struct rfkill *bluetooth_rfkill; |
| 173 | struct rfkill *wwan3g_rfkill; | ||
| 174 | struct rfkill *wimax_rfkill; | ||
| 236 | 175 | ||
| 237 | /* The hwmon device */ | 176 | struct hotplug_slot *hotplug_slot; |
| 238 | static struct device *eeepc_hwmon_device; | 177 | struct mutex hotplug_lock; |
| 239 | 178 | ||
| 240 | /* | 179 | struct led_classdev tpd_led; |
| 241 | * The backlight class declaration | 180 | int tpd_led_wk; |
| 242 | */ | 181 | struct workqueue_struct *led_workqueue; |
| 243 | static int read_brightness(struct backlight_device *bd); | 182 | struct work_struct tpd_led_work; |
| 244 | static int update_bl_status(struct backlight_device *bd); | ||
| 245 | static struct backlight_ops eeepcbl_ops = { | ||
| 246 | .get_brightness = read_brightness, | ||
| 247 | .update_status = update_bl_status, | ||
| 248 | }; | 183 | }; |
| 249 | 184 | ||
| 250 | MODULE_AUTHOR("Corentin Chary, Eric Cooper"); | ||
| 251 | MODULE_DESCRIPTION(EEEPC_HOTK_NAME); | ||
| 252 | MODULE_LICENSE("GPL"); | ||
| 253 | |||
| 254 | /* | 185 | /* |
| 255 | * ACPI Helpers | 186 | * ACPI Helpers |
| 256 | */ | 187 | */ |
| 257 | static int write_acpi_int(acpi_handle handle, const char *method, int val, | 188 | static int write_acpi_int(acpi_handle handle, const char *method, int val) |
| 258 | struct acpi_buffer *output) | ||
| 259 | { | 189 | { |
| 260 | struct acpi_object_list params; | 190 | struct acpi_object_list params; |
| 261 | union acpi_object in_obj; | 191 | union acpi_object in_obj; |
| @@ -266,7 +196,7 @@ static int write_acpi_int(acpi_handle handle, const char *method, int val, | |||
| 266 | in_obj.type = ACPI_TYPE_INTEGER; | 196 | in_obj.type = ACPI_TYPE_INTEGER; |
| 267 | in_obj.integer.value = val; | 197 | in_obj.integer.value = val; |
| 268 | 198 | ||
| 269 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, output); | 199 | status = acpi_evaluate_object(handle, (char *)method, ¶ms, NULL); |
| 270 | return (status == AE_OK ? 0 : -1); | 200 | return (status == AE_OK ? 0 : -1); |
| 271 | } | 201 | } |
| 272 | 202 | ||
| @@ -285,81 +215,56 @@ static int read_acpi_int(acpi_handle handle, const char *method, int *val) | |||
| 285 | } | 215 | } |
| 286 | } | 216 | } |
| 287 | 217 | ||
| 288 | static int set_acpi(int cm, int value) | 218 | static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value) |
| 289 | { | 219 | { |
| 290 | if (ehotk->cm_supported & (0x1 << cm)) { | 220 | const char *method = cm_setv[cm]; |
| 291 | const char *method = cm_setv[cm]; | ||
| 292 | if (method == NULL) | ||
| 293 | return -ENODEV; | ||
| 294 | if (write_acpi_int(ehotk->handle, method, value, NULL)) | ||
| 295 | pr_warning("Error writing %s\n", method); | ||
| 296 | } | ||
| 297 | return 0; | ||
| 298 | } | ||
| 299 | 221 | ||
| 300 | static int get_acpi(int cm) | 222 | if (method == NULL) |
| 301 | { | 223 | return -ENODEV; |
| 302 | int value = -ENODEV; | 224 | if ((eeepc->cm_supported & (0x1 << cm)) == 0) |
| 303 | if ((ehotk->cm_supported & (0x1 << cm))) { | 225 | return -ENODEV; |
| 304 | const char *method = cm_getv[cm]; | ||
| 305 | if (method == NULL) | ||
| 306 | return -ENODEV; | ||
| 307 | if (read_acpi_int(ehotk->handle, method, &value)) | ||
| 308 | pr_warning("Error reading %s\n", method); | ||
| 309 | } | ||
| 310 | return value; | ||
| 311 | } | ||
| 312 | |||
| 313 | /* | ||
| 314 | * Backlight | ||
| 315 | */ | ||
| 316 | static int read_brightness(struct backlight_device *bd) | ||
| 317 | { | ||
| 318 | return get_acpi(CM_ASL_PANELBRIGHT); | ||
| 319 | } | ||
| 320 | 226 | ||
| 321 | static int set_brightness(struct backlight_device *bd, int value) | 227 | if (write_acpi_int(eeepc->handle, method, value)) |
| 322 | { | 228 | pr_warning("Error writing %s\n", method); |
| 323 | value = max(0, min(15, value)); | 229 | return 0; |
| 324 | return set_acpi(CM_ASL_PANELBRIGHT, value); | ||
| 325 | } | 230 | } |
| 326 | 231 | ||
| 327 | static int update_bl_status(struct backlight_device *bd) | 232 | static int get_acpi(struct eeepc_laptop *eeepc, int cm) |
| 328 | { | 233 | { |
| 329 | return set_brightness(bd, bd->props.brightness); | 234 | const char *method = cm_getv[cm]; |
| 330 | } | 235 | int value; |
| 331 | 236 | ||
| 332 | /* | 237 | if (method == NULL) |
| 333 | * Rfkill helpers | 238 | return -ENODEV; |
| 334 | */ | 239 | if ((eeepc->cm_supported & (0x1 << cm)) == 0) |
| 240 | return -ENODEV; | ||
| 335 | 241 | ||
| 336 | static bool eeepc_wlan_rfkill_blocked(void) | 242 | if (read_acpi_int(eeepc->handle, method, &value)) |
| 337 | { | 243 | pr_warning("Error reading %s\n", method); |
| 338 | if (get_acpi(CM_ASL_WLAN) == 1) | 244 | return value; |
| 339 | return false; | ||
| 340 | return true; | ||
| 341 | } | 245 | } |
| 342 | 246 | ||
| 343 | static int eeepc_rfkill_set(void *data, bool blocked) | 247 | static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm, |
| 248 | acpi_handle *handle) | ||
| 344 | { | 249 | { |
| 345 | unsigned long asl = (unsigned long)data; | 250 | const char *method = cm_setv[cm]; |
| 346 | return set_acpi(asl, !blocked); | 251 | acpi_status status; |
| 347 | } | ||
| 348 | 252 | ||
| 349 | static const struct rfkill_ops eeepc_rfkill_ops = { | 253 | if (method == NULL) |
| 350 | .set_block = eeepc_rfkill_set, | 254 | return -ENODEV; |
| 351 | }; | 255 | if ((eeepc->cm_supported & (0x1 << cm)) == 0) |
| 256 | return -ENODEV; | ||
| 352 | 257 | ||
| 353 | static void __devinit eeepc_enable_camera(void) | 258 | status = acpi_get_handle(eeepc->handle, (char *)method, |
| 354 | { | 259 | handle); |
| 355 | /* | 260 | if (status != AE_OK) { |
| 356 | * If the following call to set_acpi() fails, it's because there's no | 261 | pr_warning("Error finding %s\n", method); |
| 357 | * camera so we can ignore the error. | 262 | return -ENODEV; |
| 358 | */ | 263 | } |
| 359 | if (get_acpi(CM_ASL_CAMERA) == 0) | 264 | return 0; |
| 360 | set_acpi(CM_ASL_CAMERA, 1); | ||
| 361 | } | 265 | } |
| 362 | 266 | ||
| 267 | |||
| 363 | /* | 268 | /* |
| 364 | * Sys helpers | 269 | * Sys helpers |
| 365 | */ | 270 | */ |
| @@ -372,60 +277,63 @@ static int parse_arg(const char *buf, unsigned long count, int *val) | |||
| 372 | return count; | 277 | return count; |
| 373 | } | 278 | } |
| 374 | 279 | ||
| 375 | static ssize_t store_sys_acpi(int cm, const char *buf, size_t count) | 280 | static ssize_t store_sys_acpi(struct device *dev, int cm, |
| 281 | const char *buf, size_t count) | ||
| 376 | { | 282 | { |
| 283 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
| 377 | int rv, value; | 284 | int rv, value; |
| 378 | 285 | ||
| 379 | rv = parse_arg(buf, count, &value); | 286 | rv = parse_arg(buf, count, &value); |
| 380 | if (rv > 0) | 287 | if (rv > 0) |
| 381 | value = set_acpi(cm, value); | 288 | value = set_acpi(eeepc, cm, value); |
| 382 | if (value < 0) | 289 | if (value < 0) |
| 383 | return value; | 290 | return -EIO; |
| 384 | return rv; | 291 | return rv; |
| 385 | } | 292 | } |
| 386 | 293 | ||
| 387 | static ssize_t show_sys_acpi(int cm, char *buf) | 294 | static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf) |
| 388 | { | 295 | { |
| 389 | int value = get_acpi(cm); | 296 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); |
| 297 | int value = get_acpi(eeepc, cm); | ||
| 390 | 298 | ||
| 391 | if (value < 0) | 299 | if (value < 0) |
| 392 | return value; | 300 | return -EIO; |
| 393 | return sprintf(buf, "%d\n", value); | 301 | return sprintf(buf, "%d\n", value); |
| 394 | } | 302 | } |
| 395 | 303 | ||
| 396 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \ | 304 | #define EEEPC_CREATE_DEVICE_ATTR(_name, _mode, _cm) \ |
| 397 | static ssize_t show_##_name(struct device *dev, \ | 305 | static ssize_t show_##_name(struct device *dev, \ |
| 398 | struct device_attribute *attr, \ | 306 | struct device_attribute *attr, \ |
| 399 | char *buf) \ | 307 | char *buf) \ |
| 400 | { \ | 308 | { \ |
| 401 | return show_sys_acpi(_cm, buf); \ | 309 | return show_sys_acpi(dev, _cm, buf); \ |
| 402 | } \ | 310 | } \ |
| 403 | static ssize_t store_##_name(struct device *dev, \ | 311 | static ssize_t store_##_name(struct device *dev, \ |
| 404 | struct device_attribute *attr, \ | 312 | struct device_attribute *attr, \ |
| 405 | const char *buf, size_t count) \ | 313 | const char *buf, size_t count) \ |
| 406 | { \ | 314 | { \ |
| 407 | return store_sys_acpi(_cm, buf, count); \ | 315 | return store_sys_acpi(dev, _cm, buf, count); \ |
| 408 | } \ | 316 | } \ |
| 409 | static struct device_attribute dev_attr_##_name = { \ | 317 | static struct device_attribute dev_attr_##_name = { \ |
| 410 | .attr = { \ | 318 | .attr = { \ |
| 411 | .name = __stringify(_name), \ | 319 | .name = __stringify(_name), \ |
| 412 | .mode = 0644 }, \ | 320 | .mode = _mode }, \ |
| 413 | .show = show_##_name, \ | 321 | .show = show_##_name, \ |
| 414 | .store = store_##_name, \ | 322 | .store = store_##_name, \ |
| 415 | } | 323 | } |
| 416 | 324 | ||
| 417 | EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA); | 325 | EEEPC_CREATE_DEVICE_ATTR(camera, 0644, CM_ASL_CAMERA); |
| 418 | EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER); | 326 | EEEPC_CREATE_DEVICE_ATTR(cardr, 0644, CM_ASL_CARDREADER); |
| 419 | EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH); | 327 | EEEPC_CREATE_DEVICE_ATTR(disp, 0200, CM_ASL_DISPLAYSWITCH); |
| 420 | 328 | ||
| 421 | struct eeepc_cpufv { | 329 | struct eeepc_cpufv { |
| 422 | int num; | 330 | int num; |
| 423 | int cur; | 331 | int cur; |
| 424 | }; | 332 | }; |
| 425 | 333 | ||
| 426 | static int get_cpufv(struct eeepc_cpufv *c) | 334 | static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c) |
| 427 | { | 335 | { |
| 428 | c->cur = get_acpi(CM_ASL_CPUFV); | 336 | c->cur = get_acpi(eeepc, CM_ASL_CPUFV); |
| 429 | c->num = (c->cur >> 8) & 0xff; | 337 | c->num = (c->cur >> 8) & 0xff; |
| 430 | c->cur &= 0xff; | 338 | c->cur &= 0xff; |
| 431 | if (c->cur < 0 || c->num <= 0 || c->num > 12) | 339 | if (c->cur < 0 || c->num <= 0 || c->num > 12) |
| @@ -437,11 +345,12 @@ static ssize_t show_available_cpufv(struct device *dev, | |||
| 437 | struct device_attribute *attr, | 345 | struct device_attribute *attr, |
| 438 | char *buf) | 346 | char *buf) |
| 439 | { | 347 | { |
| 348 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
| 440 | struct eeepc_cpufv c; | 349 | struct eeepc_cpufv c; |
| 441 | int i; | 350 | int i; |
| 442 | ssize_t len = 0; | 351 | ssize_t len = 0; |
| 443 | 352 | ||
| 444 | if (get_cpufv(&c)) | 353 | if (get_cpufv(eeepc, &c)) |
| 445 | return -ENODEV; | 354 | return -ENODEV; |
| 446 | for (i = 0; i < c.num; i++) | 355 | for (i = 0; i < c.num; i++) |
| 447 | len += sprintf(buf + len, "%d ", i); | 356 | len += sprintf(buf + len, "%d ", i); |
| @@ -453,9 +362,10 @@ static ssize_t show_cpufv(struct device *dev, | |||
| 453 | struct device_attribute *attr, | 362 | struct device_attribute *attr, |
| 454 | char *buf) | 363 | char *buf) |
| 455 | { | 364 | { |
| 365 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
| 456 | struct eeepc_cpufv c; | 366 | struct eeepc_cpufv c; |
| 457 | 367 | ||
| 458 | if (get_cpufv(&c)) | 368 | if (get_cpufv(eeepc, &c)) |
| 459 | return -ENODEV; | 369 | return -ENODEV; |
| 460 | return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); | 370 | return sprintf(buf, "%#x\n", (c.num << 8) | c.cur); |
| 461 | } | 371 | } |
| @@ -464,17 +374,18 @@ static ssize_t store_cpufv(struct device *dev, | |||
| 464 | struct device_attribute *attr, | 374 | struct device_attribute *attr, |
| 465 | const char *buf, size_t count) | 375 | const char *buf, size_t count) |
| 466 | { | 376 | { |
| 377 | struct eeepc_laptop *eeepc = dev_get_drvdata(dev); | ||
| 467 | struct eeepc_cpufv c; | 378 | struct eeepc_cpufv c; |
| 468 | int rv, value; | 379 | int rv, value; |
| 469 | 380 | ||
| 470 | if (get_cpufv(&c)) | 381 | if (get_cpufv(eeepc, &c)) |
| 471 | return -ENODEV; | 382 | return -ENODEV; |
| 472 | rv = parse_arg(buf, count, &value); | 383 | rv = parse_arg(buf, count, &value); |
| 473 | if (rv < 0) | 384 | if (rv < 0) |
| 474 | return rv; | 385 | return rv; |
| 475 | if (!rv || value < 0 || value >= c.num) | 386 | if (!rv || value < 0 || value >= c.num) |
| 476 | return -EINVAL; | 387 | return -EINVAL; |
| 477 | set_acpi(CM_ASL_CPUFV, value); | 388 | set_acpi(eeepc, CM_ASL_CPUFV, value); |
| 478 | return rv; | 389 | return rv; |
| 479 | } | 390 | } |
| 480 | 391 | ||
| @@ -506,156 +417,125 @@ static struct attribute_group platform_attribute_group = { | |||
| 506 | .attrs = platform_attributes | 417 | .attrs = platform_attributes |
| 507 | }; | 418 | }; |
| 508 | 419 | ||
| 509 | /* | 420 | static int eeepc_platform_init(struct eeepc_laptop *eeepc) |
| 510 | * Hotkey functions | ||
| 511 | */ | ||
| 512 | static struct key_entry *eepc_get_entry_by_scancode(int code) | ||
| 513 | { | 421 | { |
| 514 | struct key_entry *key; | 422 | int result; |
| 515 | |||
| 516 | for (key = eeepc_keymap; key->type != KE_END; key++) | ||
| 517 | if (code == key->code) | ||
| 518 | return key; | ||
| 519 | 423 | ||
| 520 | return NULL; | 424 | eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1); |
| 521 | } | 425 | if (!eeepc->platform_device) |
| 426 | return -ENOMEM; | ||
| 427 | platform_set_drvdata(eeepc->platform_device, eeepc); | ||
| 522 | 428 | ||
| 523 | static struct key_entry *eepc_get_entry_by_keycode(int code) | 429 | result = platform_device_add(eeepc->platform_device); |
| 524 | { | 430 | if (result) |
| 525 | struct key_entry *key; | 431 | goto fail_platform_device; |
| 526 | 432 | ||
| 527 | for (key = eeepc_keymap; key->type != KE_END; key++) | 433 | result = sysfs_create_group(&eeepc->platform_device->dev.kobj, |
| 528 | if (code == key->keycode && key->type == KE_KEY) | 434 | &platform_attribute_group); |
| 529 | return key; | 435 | if (result) |
| 436 | goto fail_sysfs; | ||
| 437 | return 0; | ||
| 530 | 438 | ||
| 531 | return NULL; | 439 | fail_sysfs: |
| 440 | platform_device_del(eeepc->platform_device); | ||
| 441 | fail_platform_device: | ||
| 442 | platform_device_put(eeepc->platform_device); | ||
| 443 | return result; | ||
| 532 | } | 444 | } |
| 533 | 445 | ||
| 534 | static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) | 446 | static void eeepc_platform_exit(struct eeepc_laptop *eeepc) |
| 535 | { | 447 | { |
| 536 | struct key_entry *key = eepc_get_entry_by_scancode(scancode); | 448 | sysfs_remove_group(&eeepc->platform_device->dev.kobj, |
| 449 | &platform_attribute_group); | ||
| 450 | platform_device_unregister(eeepc->platform_device); | ||
| 451 | } | ||
| 537 | 452 | ||
| 538 | if (key && key->type == KE_KEY) { | 453 | /* |
| 539 | *keycode = key->keycode; | 454 | * LEDs |
| 540 | return 0; | 455 | */ |
| 541 | } | 456 | /* |
| 457 | * These functions actually update the LED's, and are called from a | ||
| 458 | * workqueue. By doing this as separate work rather than when the LED | ||
| 459 | * subsystem asks, we avoid messing with the Asus ACPI stuff during a | ||
| 460 | * potentially bad time, such as a timer interrupt. | ||
| 461 | */ | ||
| 462 | static void tpd_led_update(struct work_struct *work) | ||
| 463 | { | ||
| 464 | struct eeepc_laptop *eeepc; | ||
| 542 | 465 | ||
| 543 | return -EINVAL; | 466 | eeepc = container_of(work, struct eeepc_laptop, tpd_led_work); |
| 467 | |||
| 468 | set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk); | ||
| 544 | } | 469 | } |
| 545 | 470 | ||
| 546 | static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) | 471 | static void tpd_led_set(struct led_classdev *led_cdev, |
| 472 | enum led_brightness value) | ||
| 547 | { | 473 | { |
| 548 | struct key_entry *key; | 474 | struct eeepc_laptop *eeepc; |
| 549 | int old_keycode; | ||
| 550 | 475 | ||
| 551 | if (keycode < 0 || keycode > KEY_MAX) | 476 | eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led); |
| 552 | return -EINVAL; | ||
| 553 | 477 | ||
| 554 | key = eepc_get_entry_by_scancode(scancode); | 478 | eeepc->tpd_led_wk = (value > 0) ? 1 : 0; |
| 555 | if (key && key->type == KE_KEY) { | 479 | queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work); |
| 556 | old_keycode = key->keycode; | ||
| 557 | key->keycode = keycode; | ||
| 558 | set_bit(keycode, dev->keybit); | ||
| 559 | if (!eepc_get_entry_by_keycode(old_keycode)) | ||
| 560 | clear_bit(old_keycode, dev->keybit); | ||
| 561 | return 0; | ||
| 562 | } | ||
| 563 | |||
| 564 | return -EINVAL; | ||
| 565 | } | 480 | } |
| 566 | 481 | ||
| 567 | static void cmsg_quirk(int cm, const char *name) | 482 | static int eeepc_led_init(struct eeepc_laptop *eeepc) |
| 568 | { | 483 | { |
| 569 | int dummy; | 484 | int rv; |
| 570 | 485 | ||
| 571 | /* Some BIOSes do not report cm although it is avaliable. | 486 | if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV) |
| 572 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | 487 | return 0; |
| 573 | if (!(ehotk->cm_supported & (1 << cm)) | ||
| 574 | && !read_acpi_int(ehotk->handle, cm_getv[cm], &dummy)) { | ||
| 575 | pr_info("%s (%x) not reported by BIOS," | ||
| 576 | " enabling anyway\n", name, 1 << cm); | ||
| 577 | ehotk->cm_supported |= 1 << cm; | ||
| 578 | } | ||
| 579 | } | ||
| 580 | 488 | ||
| 581 | static void cmsg_quirks(void) | 489 | eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue"); |
| 582 | { | 490 | if (!eeepc->led_workqueue) |
| 583 | cmsg_quirk(CM_ASL_LID, "LID"); | 491 | return -ENOMEM; |
| 584 | cmsg_quirk(CM_ASL_TYPE, "TYPE"); | 492 | INIT_WORK(&eeepc->tpd_led_work, tpd_led_update); |
| 585 | cmsg_quirk(CM_ASL_PANELPOWER, "PANELPOWER"); | ||
| 586 | cmsg_quirk(CM_ASL_TPD, "TPD"); | ||
| 587 | } | ||
| 588 | 493 | ||
| 589 | static int eeepc_hotk_check(void) | 494 | eeepc->tpd_led.name = "eeepc::touchpad"; |
| 590 | { | 495 | eeepc->tpd_led.brightness_set = tpd_led_set; |
| 591 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 496 | eeepc->tpd_led.max_brightness = 1; |
| 592 | int result; | ||
| 593 | 497 | ||
| 594 | result = acpi_bus_get_status(ehotk->device); | 498 | rv = led_classdev_register(&eeepc->platform_device->dev, |
| 595 | if (result) | 499 | &eeepc->tpd_led); |
| 596 | return result; | 500 | if (rv) { |
| 597 | if (ehotk->device->status.present) { | 501 | destroy_workqueue(eeepc->led_workqueue); |
| 598 | if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag, | 502 | return rv; |
| 599 | &buffer)) { | ||
| 600 | pr_err("Hotkey initialization failed\n"); | ||
| 601 | return -ENODEV; | ||
| 602 | } else { | ||
| 603 | pr_notice("Hotkey init flags 0x%x\n", ehotk->init_flag); | ||
| 604 | } | ||
| 605 | /* get control methods supported */ | ||
| 606 | if (read_acpi_int(ehotk->handle, "CMSG" | ||
| 607 | , &ehotk->cm_supported)) { | ||
| 608 | pr_err("Get control methods supported failed\n"); | ||
| 609 | return -ENODEV; | ||
| 610 | } else { | ||
| 611 | cmsg_quirks(); | ||
| 612 | pr_info("Get control methods supported: 0x%x\n", | ||
| 613 | ehotk->cm_supported); | ||
| 614 | } | ||
| 615 | } else { | ||
| 616 | pr_err("Hotkey device not present, aborting\n"); | ||
| 617 | return -EINVAL; | ||
| 618 | } | 503 | } |
| 504 | |||
| 619 | return 0; | 505 | return 0; |
| 620 | } | 506 | } |
| 621 | 507 | ||
| 622 | static int notify_brn(void) | 508 | static void eeepc_led_exit(struct eeepc_laptop *eeepc) |
| 623 | { | 509 | { |
| 624 | /* returns the *previous* brightness, or -1 */ | 510 | if (eeepc->tpd_led.dev) |
| 625 | struct backlight_device *bd = eeepc_backlight_device; | 511 | led_classdev_unregister(&eeepc->tpd_led); |
| 626 | if (bd) { | 512 | if (eeepc->led_workqueue) |
| 627 | int old = bd->props.brightness; | 513 | destroy_workqueue(eeepc->led_workqueue); |
| 628 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); | ||
| 629 | return old; | ||
| 630 | } | ||
| 631 | return -1; | ||
| 632 | } | 514 | } |
| 633 | 515 | ||
| 634 | static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, | ||
| 635 | u8 *value) | ||
| 636 | { | ||
| 637 | int val = get_acpi(CM_ASL_WLAN); | ||
| 638 | 516 | ||
| 639 | if (val == 1 || val == 0) | 517 | /* |
| 640 | *value = val; | 518 | * PCI hotplug (for wlan rfkill) |
| 641 | else | 519 | */ |
| 642 | return -EINVAL; | 520 | static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc) |
| 643 | 521 | { | |
| 644 | return 0; | 522 | if (get_acpi(eeepc, CM_ASL_WLAN) == 1) |
| 523 | return false; | ||
| 524 | return true; | ||
| 645 | } | 525 | } |
| 646 | 526 | ||
| 647 | static void eeepc_rfkill_hotplug(void) | 527 | static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc) |
| 648 | { | 528 | { |
| 649 | struct pci_dev *dev; | 529 | struct pci_dev *dev; |
| 650 | struct pci_bus *bus; | 530 | struct pci_bus *bus; |
| 651 | bool blocked = eeepc_wlan_rfkill_blocked(); | 531 | bool blocked = eeepc_wlan_rfkill_blocked(eeepc); |
| 652 | 532 | ||
| 653 | if (ehotk->wlan_rfkill) | 533 | if (eeepc->wlan_rfkill) |
| 654 | rfkill_set_sw_state(ehotk->wlan_rfkill, blocked); | 534 | rfkill_set_sw_state(eeepc->wlan_rfkill, blocked); |
| 655 | 535 | ||
| 656 | mutex_lock(&ehotk->hotplug_lock); | 536 | mutex_lock(&eeepc->hotplug_lock); |
| 657 | 537 | ||
| 658 | if (ehotk->hotplug_slot) { | 538 | if (eeepc->hotplug_slot) { |
| 659 | bus = pci_find_bus(0, 1); | 539 | bus = pci_find_bus(0, 1); |
| 660 | if (!bus) { | 540 | if (!bus) { |
| 661 | pr_warning("Unable to find PCI bus 1?\n"); | 541 | pr_warning("Unable to find PCI bus 1?\n"); |
| @@ -685,69 +565,23 @@ static void eeepc_rfkill_hotplug(void) | |||
| 685 | } | 565 | } |
| 686 | 566 | ||
| 687 | out_unlock: | 567 | out_unlock: |
| 688 | mutex_unlock(&ehotk->hotplug_lock); | 568 | mutex_unlock(&eeepc->hotplug_lock); |
| 689 | } | 569 | } |
| 690 | 570 | ||
| 691 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) | 571 | static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data) |
| 692 | { | 572 | { |
| 573 | struct eeepc_laptop *eeepc = data; | ||
| 574 | |||
| 693 | if (event != ACPI_NOTIFY_BUS_CHECK) | 575 | if (event != ACPI_NOTIFY_BUS_CHECK) |
| 694 | return; | 576 | return; |
| 695 | 577 | ||
| 696 | eeepc_rfkill_hotplug(); | 578 | eeepc_rfkill_hotplug(eeepc); |
| 697 | } | 579 | } |
| 698 | 580 | ||
| 699 | static void eeepc_hotk_notify(struct acpi_device *device, u32 event) | 581 | static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc, |
| 582 | char *node) | ||
| 700 | { | 583 | { |
| 701 | static struct key_entry *key; | 584 | acpi_status status; |
| 702 | u16 count; | ||
| 703 | int brn = -ENODEV; | ||
| 704 | |||
| 705 | if (!ehotk) | ||
| 706 | return; | ||
| 707 | if (event > ACPI_MAX_SYS_NOTIFY) | ||
| 708 | return; | ||
| 709 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) | ||
| 710 | brn = notify_brn(); | ||
| 711 | count = ehotk->event_count[event % 128]++; | ||
| 712 | acpi_bus_generate_proc_event(ehotk->device, event, count); | ||
| 713 | acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class, | ||
| 714 | dev_name(&ehotk->device->dev), event, | ||
| 715 | count); | ||
| 716 | if (ehotk->inputdev) { | ||
| 717 | if (brn != -ENODEV) { | ||
| 718 | /* brightness-change events need special | ||
| 719 | * handling for conversion to key events | ||
| 720 | */ | ||
| 721 | if (brn < 0) | ||
| 722 | brn = event; | ||
| 723 | else | ||
| 724 | brn += NOTIFY_BRN_MIN; | ||
| 725 | if (event < brn) | ||
| 726 | event = NOTIFY_BRN_MIN; /* brightness down */ | ||
| 727 | else if (event > brn) | ||
| 728 | event = NOTIFY_BRN_MIN + 2; /* ... up */ | ||
| 729 | else | ||
| 730 | event = NOTIFY_BRN_MIN + 1; /* ... unchanged */ | ||
| 731 | } | ||
| 732 | key = eepc_get_entry_by_scancode(event); | ||
| 733 | if (key) { | ||
| 734 | switch (key->type) { | ||
| 735 | case KE_KEY: | ||
| 736 | input_report_key(ehotk->inputdev, key->keycode, | ||
| 737 | 1); | ||
| 738 | input_sync(ehotk->inputdev); | ||
| 739 | input_report_key(ehotk->inputdev, key->keycode, | ||
| 740 | 0); | ||
| 741 | input_sync(ehotk->inputdev); | ||
| 742 | break; | ||
| 743 | } | ||
| 744 | } | ||
| 745 | } | ||
| 746 | } | ||
| 747 | |||
| 748 | static int eeepc_register_rfkill_notifier(char *node) | ||
| 749 | { | ||
| 750 | acpi_status status = AE_OK; | ||
| 751 | acpi_handle handle; | 585 | acpi_handle handle; |
| 752 | 586 | ||
| 753 | status = acpi_get_handle(NULL, node, &handle); | 587 | status = acpi_get_handle(NULL, node, &handle); |
| @@ -756,7 +590,7 @@ static int eeepc_register_rfkill_notifier(char *node) | |||
| 756 | status = acpi_install_notify_handler(handle, | 590 | status = acpi_install_notify_handler(handle, |
| 757 | ACPI_SYSTEM_NOTIFY, | 591 | ACPI_SYSTEM_NOTIFY, |
| 758 | eeepc_rfkill_notify, | 592 | eeepc_rfkill_notify, |
| 759 | NULL); | 593 | eeepc); |
| 760 | if (ACPI_FAILURE(status)) | 594 | if (ACPI_FAILURE(status)) |
| 761 | pr_warning("Failed to register notify on %s\n", node); | 595 | pr_warning("Failed to register notify on %s\n", node); |
| 762 | } else | 596 | } else |
| @@ -765,7 +599,8 @@ static int eeepc_register_rfkill_notifier(char *node) | |||
| 765 | return 0; | 599 | return 0; |
| 766 | } | 600 | } |
| 767 | 601 | ||
| 768 | static void eeepc_unregister_rfkill_notifier(char *node) | 602 | static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc, |
| 603 | char *node) | ||
| 769 | { | 604 | { |
| 770 | acpi_status status = AE_OK; | 605 | acpi_status status = AE_OK; |
| 771 | acpi_handle handle; | 606 | acpi_handle handle; |
| @@ -782,13 +617,33 @@ static void eeepc_unregister_rfkill_notifier(char *node) | |||
| 782 | } | 617 | } |
| 783 | } | 618 | } |
| 784 | 619 | ||
| 620 | static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot, | ||
| 621 | u8 *value) | ||
| 622 | { | ||
| 623 | struct eeepc_laptop *eeepc = hotplug_slot->private; | ||
| 624 | int val = get_acpi(eeepc, CM_ASL_WLAN); | ||
| 625 | |||
| 626 | if (val == 1 || val == 0) | ||
| 627 | *value = val; | ||
| 628 | else | ||
| 629 | return -EINVAL; | ||
| 630 | |||
| 631 | return 0; | ||
| 632 | } | ||
| 633 | |||
| 785 | static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) | 634 | static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot) |
| 786 | { | 635 | { |
| 787 | kfree(hotplug_slot->info); | 636 | kfree(hotplug_slot->info); |
| 788 | kfree(hotplug_slot); | 637 | kfree(hotplug_slot); |
| 789 | } | 638 | } |
| 790 | 639 | ||
| 791 | static int eeepc_setup_pci_hotplug(void) | 640 | static struct hotplug_slot_ops eeepc_hotplug_slot_ops = { |
| 641 | .owner = THIS_MODULE, | ||
| 642 | .get_adapter_status = eeepc_get_adapter_status, | ||
| 643 | .get_power_status = eeepc_get_adapter_status, | ||
| 644 | }; | ||
| 645 | |||
| 646 | static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc) | ||
| 792 | { | 647 | { |
| 793 | int ret = -ENOMEM; | 648 | int ret = -ENOMEM; |
| 794 | struct pci_bus *bus = pci_find_bus(0, 1); | 649 | struct pci_bus *bus = pci_find_bus(0, 1); |
| @@ -798,22 +653,22 @@ static int eeepc_setup_pci_hotplug(void) | |||
| 798 | return -ENODEV; | 653 | return -ENODEV; |
| 799 | } | 654 | } |
| 800 | 655 | ||
| 801 | ehotk->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); | 656 | eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL); |
| 802 | if (!ehotk->hotplug_slot) | 657 | if (!eeepc->hotplug_slot) |
| 803 | goto error_slot; | 658 | goto error_slot; |
| 804 | 659 | ||
| 805 | ehotk->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), | 660 | eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info), |
| 806 | GFP_KERNEL); | 661 | GFP_KERNEL); |
| 807 | if (!ehotk->hotplug_slot->info) | 662 | if (!eeepc->hotplug_slot->info) |
| 808 | goto error_info; | 663 | goto error_info; |
| 809 | 664 | ||
| 810 | ehotk->hotplug_slot->private = ehotk; | 665 | eeepc->hotplug_slot->private = eeepc; |
| 811 | ehotk->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; | 666 | eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug; |
| 812 | ehotk->hotplug_slot->ops = &eeepc_hotplug_slot_ops; | 667 | eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops; |
| 813 | eeepc_get_adapter_status(ehotk->hotplug_slot, | 668 | eeepc_get_adapter_status(eeepc->hotplug_slot, |
| 814 | &ehotk->hotplug_slot->info->adapter_status); | 669 | &eeepc->hotplug_slot->info->adapter_status); |
| 815 | 670 | ||
| 816 | ret = pci_hp_register(ehotk->hotplug_slot, bus, 0, "eeepc-wifi"); | 671 | ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi"); |
| 817 | if (ret) { | 672 | if (ret) { |
| 818 | pr_err("Unable to register hotplug slot - %d\n", ret); | 673 | pr_err("Unable to register hotplug slot - %d\n", ret); |
| 819 | goto error_register; | 674 | goto error_register; |
| @@ -822,17 +677,156 @@ static int eeepc_setup_pci_hotplug(void) | |||
| 822 | return 0; | 677 | return 0; |
| 823 | 678 | ||
| 824 | error_register: | 679 | error_register: |
| 825 | kfree(ehotk->hotplug_slot->info); | 680 | kfree(eeepc->hotplug_slot->info); |
| 826 | error_info: | 681 | error_info: |
| 827 | kfree(ehotk->hotplug_slot); | 682 | kfree(eeepc->hotplug_slot); |
| 828 | ehotk->hotplug_slot = NULL; | 683 | eeepc->hotplug_slot = NULL; |
| 829 | error_slot: | 684 | error_slot: |
| 830 | return ret; | 685 | return ret; |
| 831 | } | 686 | } |
| 832 | 687 | ||
| 688 | /* | ||
| 689 | * Rfkill devices | ||
| 690 | */ | ||
| 691 | static int eeepc_rfkill_set(void *data, bool blocked) | ||
| 692 | { | ||
| 693 | acpi_handle handle = data; | ||
| 694 | |||
| 695 | return write_acpi_int(handle, NULL, !blocked); | ||
| 696 | } | ||
| 697 | |||
| 698 | static const struct rfkill_ops eeepc_rfkill_ops = { | ||
| 699 | .set_block = eeepc_rfkill_set, | ||
| 700 | }; | ||
| 701 | |||
| 702 | static int eeepc_new_rfkill(struct eeepc_laptop *eeepc, | ||
| 703 | struct rfkill **rfkill, | ||
| 704 | const char *name, | ||
| 705 | enum rfkill_type type, int cm) | ||
| 706 | { | ||
| 707 | acpi_handle handle; | ||
| 708 | int result; | ||
| 709 | |||
| 710 | result = acpi_setter_handle(eeepc, cm, &handle); | ||
| 711 | if (result < 0) | ||
| 712 | return result; | ||
| 713 | |||
| 714 | *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type, | ||
| 715 | &eeepc_rfkill_ops, handle); | ||
| 716 | |||
| 717 | if (!*rfkill) | ||
| 718 | return -EINVAL; | ||
| 719 | |||
| 720 | rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1); | ||
| 721 | result = rfkill_register(*rfkill); | ||
| 722 | if (result) { | ||
| 723 | rfkill_destroy(*rfkill); | ||
| 724 | *rfkill = NULL; | ||
| 725 | return result; | ||
| 726 | } | ||
| 727 | return 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc) | ||
| 731 | { | ||
| 732 | eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); | ||
| 733 | eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); | ||
| 734 | eeepc_unregister_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); | ||
| 735 | if (eeepc->wlan_rfkill) { | ||
| 736 | rfkill_unregister(eeepc->wlan_rfkill); | ||
| 737 | rfkill_destroy(eeepc->wlan_rfkill); | ||
| 738 | eeepc->wlan_rfkill = NULL; | ||
| 739 | } | ||
| 740 | /* | ||
| 741 | * Refresh pci hotplug in case the rfkill state was changed after | ||
| 742 | * eeepc_unregister_rfkill_notifier() | ||
| 743 | */ | ||
| 744 | eeepc_rfkill_hotplug(eeepc); | ||
| 745 | if (eeepc->hotplug_slot) | ||
| 746 | pci_hp_deregister(eeepc->hotplug_slot); | ||
| 747 | |||
| 748 | if (eeepc->bluetooth_rfkill) { | ||
| 749 | rfkill_unregister(eeepc->bluetooth_rfkill); | ||
| 750 | rfkill_destroy(eeepc->bluetooth_rfkill); | ||
| 751 | eeepc->bluetooth_rfkill = NULL; | ||
| 752 | } | ||
| 753 | if (eeepc->wwan3g_rfkill) { | ||
| 754 | rfkill_unregister(eeepc->wwan3g_rfkill); | ||
| 755 | rfkill_destroy(eeepc->wwan3g_rfkill); | ||
| 756 | eeepc->wwan3g_rfkill = NULL; | ||
| 757 | } | ||
| 758 | if (eeepc->wimax_rfkill) { | ||
| 759 | rfkill_unregister(eeepc->wimax_rfkill); | ||
| 760 | rfkill_destroy(eeepc->wimax_rfkill); | ||
| 761 | eeepc->wimax_rfkill = NULL; | ||
| 762 | } | ||
| 763 | } | ||
| 764 | |||
| 765 | static int eeepc_rfkill_init(struct eeepc_laptop *eeepc) | ||
| 766 | { | ||
| 767 | int result = 0; | ||
| 768 | |||
| 769 | mutex_init(&eeepc->hotplug_lock); | ||
| 770 | |||
| 771 | result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill, | ||
| 772 | "eeepc-wlan", RFKILL_TYPE_WLAN, | ||
| 773 | CM_ASL_WLAN); | ||
| 774 | |||
| 775 | if (result && result != -ENODEV) | ||
| 776 | goto exit; | ||
| 777 | |||
| 778 | result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill, | ||
| 779 | "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH, | ||
| 780 | CM_ASL_BLUETOOTH); | ||
| 781 | |||
| 782 | if (result && result != -ENODEV) | ||
| 783 | goto exit; | ||
| 784 | |||
| 785 | result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill, | ||
| 786 | "eeepc-wwan3g", RFKILL_TYPE_WWAN, | ||
| 787 | CM_ASL_3G); | ||
| 788 | |||
| 789 | if (result && result != -ENODEV) | ||
| 790 | goto exit; | ||
| 791 | |||
| 792 | result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill, | ||
| 793 | "eeepc-wimax", RFKILL_TYPE_WIMAX, | ||
| 794 | CM_ASL_WIMAX); | ||
| 795 | |||
| 796 | if (result && result != -ENODEV) | ||
| 797 | goto exit; | ||
| 798 | |||
| 799 | result = eeepc_setup_pci_hotplug(eeepc); | ||
| 800 | /* | ||
| 801 | * If we get -EBUSY then something else is handling the PCI hotplug - | ||
| 802 | * don't fail in this case | ||
| 803 | */ | ||
| 804 | if (result == -EBUSY) | ||
| 805 | result = 0; | ||
| 806 | |||
| 807 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P5"); | ||
| 808 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P6"); | ||
| 809 | eeepc_register_rfkill_notifier(eeepc, "\\_SB.PCI0.P0P7"); | ||
| 810 | /* | ||
| 811 | * Refresh pci hotplug in case the rfkill state was changed during | ||
| 812 | * setup. | ||
| 813 | */ | ||
| 814 | eeepc_rfkill_hotplug(eeepc); | ||
| 815 | |||
| 816 | exit: | ||
| 817 | if (result && result != -ENODEV) | ||
| 818 | eeepc_rfkill_exit(eeepc); | ||
| 819 | return result; | ||
| 820 | } | ||
| 821 | |||
| 822 | /* | ||
| 823 | * Platform driver - hibernate/resume callbacks | ||
| 824 | */ | ||
| 833 | static int eeepc_hotk_thaw(struct device *device) | 825 | static int eeepc_hotk_thaw(struct device *device) |
| 834 | { | 826 | { |
| 835 | if (ehotk->wlan_rfkill) { | 827 | struct eeepc_laptop *eeepc = dev_get_drvdata(device); |
| 828 | |||
| 829 | if (eeepc->wlan_rfkill) { | ||
| 836 | bool wlan; | 830 | bool wlan; |
| 837 | 831 | ||
| 838 | /* | 832 | /* |
| @@ -840,8 +834,8 @@ static int eeepc_hotk_thaw(struct device *device) | |||
| 840 | * during suspend. Normally it restores it on resume, but | 834 | * during suspend. Normally it restores it on resume, but |
| 841 | * we should kick it ourselves in case hibernation is aborted. | 835 | * we should kick it ourselves in case hibernation is aborted. |
| 842 | */ | 836 | */ |
| 843 | wlan = get_acpi(CM_ASL_WLAN); | 837 | wlan = get_acpi(eeepc, CM_ASL_WLAN); |
| 844 | set_acpi(CM_ASL_WLAN, wlan); | 838 | set_acpi(eeepc, CM_ASL_WLAN, wlan); |
| 845 | } | 839 | } |
| 846 | 840 | ||
| 847 | return 0; | 841 | return 0; |
| @@ -849,70 +843,96 @@ static int eeepc_hotk_thaw(struct device *device) | |||
| 849 | 843 | ||
| 850 | static int eeepc_hotk_restore(struct device *device) | 844 | static int eeepc_hotk_restore(struct device *device) |
| 851 | { | 845 | { |
| 846 | struct eeepc_laptop *eeepc = dev_get_drvdata(device); | ||
| 847 | |||
| 852 | /* Refresh both wlan rfkill state and pci hotplug */ | 848 | /* Refresh both wlan rfkill state and pci hotplug */ |
| 853 | if (ehotk->wlan_rfkill) | 849 | if (eeepc->wlan_rfkill) |
| 854 | eeepc_rfkill_hotplug(); | 850 | eeepc_rfkill_hotplug(eeepc); |
| 855 | 851 | ||
| 856 | if (ehotk->bluetooth_rfkill) | 852 | if (eeepc->bluetooth_rfkill) |
| 857 | rfkill_set_sw_state(ehotk->bluetooth_rfkill, | 853 | rfkill_set_sw_state(eeepc->bluetooth_rfkill, |
| 858 | get_acpi(CM_ASL_BLUETOOTH) != 1); | 854 | get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1); |
| 859 | if (ehotk->wwan3g_rfkill) | 855 | if (eeepc->wwan3g_rfkill) |
| 860 | rfkill_set_sw_state(ehotk->wwan3g_rfkill, | 856 | rfkill_set_sw_state(eeepc->wwan3g_rfkill, |
| 861 | get_acpi(CM_ASL_3G) != 1); | 857 | get_acpi(eeepc, CM_ASL_3G) != 1); |
| 862 | if (ehotk->wimax_rfkill) | 858 | if (eeepc->wimax_rfkill) |
| 863 | rfkill_set_sw_state(ehotk->wimax_rfkill, | 859 | rfkill_set_sw_state(eeepc->wimax_rfkill, |
| 864 | get_acpi(CM_ASL_WIMAX) != 1); | 860 | get_acpi(eeepc, CM_ASL_WIMAX) != 1); |
| 865 | 861 | ||
| 866 | return 0; | 862 | return 0; |
| 867 | } | 863 | } |
| 868 | 864 | ||
| 865 | static const struct dev_pm_ops eeepc_pm_ops = { | ||
| 866 | .thaw = eeepc_hotk_thaw, | ||
| 867 | .restore = eeepc_hotk_restore, | ||
| 868 | }; | ||
| 869 | |||
| 870 | static struct platform_driver platform_driver = { | ||
| 871 | .driver = { | ||
| 872 | .name = EEEPC_LAPTOP_FILE, | ||
| 873 | .owner = THIS_MODULE, | ||
| 874 | .pm = &eeepc_pm_ops, | ||
| 875 | } | ||
| 876 | }; | ||
| 877 | |||
| 869 | /* | 878 | /* |
| 870 | * Hwmon | 879 | * Hwmon device |
| 871 | */ | 880 | */ |
| 881 | |||
| 882 | #define EEEPC_EC_SC00 0x61 | ||
| 883 | #define EEEPC_EC_FAN_PWM (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */ | ||
| 884 | #define EEEPC_EC_FAN_HRPM (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */ | ||
| 885 | #define EEEPC_EC_FAN_LRPM (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */ | ||
| 886 | |||
| 887 | #define EEEPC_EC_SFB0 0xD0 | ||
| 888 | #define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */ | ||
| 889 | |||
| 872 | static int eeepc_get_fan_pwm(void) | 890 | static int eeepc_get_fan_pwm(void) |
| 873 | { | 891 | { |
| 874 | int value = 0; | 892 | u8 value = 0; |
| 875 | 893 | ||
| 876 | read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value); | 894 | ec_read(EEEPC_EC_FAN_PWM, &value); |
| 877 | value = value * 255 / 100; | 895 | return value * 255 / 100; |
| 878 | return (value); | ||
| 879 | } | 896 | } |
| 880 | 897 | ||
| 881 | static void eeepc_set_fan_pwm(int value) | 898 | static void eeepc_set_fan_pwm(int value) |
| 882 | { | 899 | { |
| 883 | value = SENSORS_LIMIT(value, 0, 255); | 900 | value = SENSORS_LIMIT(value, 0, 255); |
| 884 | value = value * 100 / 255; | 901 | value = value * 100 / 255; |
| 885 | ec_write(EEEPC_EC_SC02, value); | 902 | ec_write(EEEPC_EC_FAN_PWM, value); |
| 886 | } | 903 | } |
| 887 | 904 | ||
| 888 | static int eeepc_get_fan_rpm(void) | 905 | static int eeepc_get_fan_rpm(void) |
| 889 | { | 906 | { |
| 890 | int high = 0; | 907 | u8 high = 0; |
| 891 | int low = 0; | 908 | u8 low = 0; |
| 892 | 909 | ||
| 893 | read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high); | 910 | ec_read(EEEPC_EC_FAN_HRPM, &high); |
| 894 | read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low); | 911 | ec_read(EEEPC_EC_FAN_LRPM, &low); |
| 895 | return (high << 8 | low); | 912 | return high << 8 | low; |
| 896 | } | 913 | } |
| 897 | 914 | ||
| 898 | static int eeepc_get_fan_ctrl(void) | 915 | static int eeepc_get_fan_ctrl(void) |
| 899 | { | 916 | { |
| 900 | int value = 0; | 917 | u8 value = 0; |
| 901 | 918 | ||
| 902 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); | 919 | ec_read(EEEPC_EC_FAN_CTRL, &value); |
| 903 | return ((value & 0x02 ? 1 : 0)); | 920 | if (value & 0x02) |
| 921 | return 1; /* manual */ | ||
| 922 | else | ||
| 923 | return 2; /* automatic */ | ||
| 904 | } | 924 | } |
| 905 | 925 | ||
| 906 | static void eeepc_set_fan_ctrl(int manual) | 926 | static void eeepc_set_fan_ctrl(int manual) |
| 907 | { | 927 | { |
| 908 | int value = 0; | 928 | u8 value = 0; |
| 909 | 929 | ||
| 910 | read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value); | 930 | ec_read(EEEPC_EC_FAN_CTRL, &value); |
| 911 | if (manual) | 931 | if (manual == 1) |
| 912 | value |= 0x02; | 932 | value |= 0x02; |
| 913 | else | 933 | else |
| 914 | value &= ~0x02; | 934 | value &= ~0x02; |
| 915 | ec_write(EEEPC_EC_SFB3, value); | 935 | ec_write(EEEPC_EC_FAN_CTRL, value); |
| 916 | } | 936 | } |
| 917 | 937 | ||
| 918 | static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) | 938 | static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count) |
| @@ -970,348 +990,485 @@ static struct attribute_group hwmon_attribute_group = { | |||
| 970 | .attrs = hwmon_attributes | 990 | .attrs = hwmon_attributes |
| 971 | }; | 991 | }; |
| 972 | 992 | ||
| 973 | /* | 993 | static void eeepc_hwmon_exit(struct eeepc_laptop *eeepc) |
| 974 | * exit/init | ||
| 975 | */ | ||
| 976 | static void eeepc_backlight_exit(void) | ||
| 977 | { | 994 | { |
| 978 | if (eeepc_backlight_device) | 995 | struct device *hwmon; |
| 979 | backlight_device_unregister(eeepc_backlight_device); | 996 | |
| 980 | eeepc_backlight_device = NULL; | 997 | hwmon = eeepc->hwmon_device; |
| 998 | if (!hwmon) | ||
| 999 | return; | ||
| 1000 | sysfs_remove_group(&hwmon->kobj, | ||
| 1001 | &hwmon_attribute_group); | ||
| 1002 | hwmon_device_unregister(hwmon); | ||
| 1003 | eeepc->hwmon_device = NULL; | ||
| 981 | } | 1004 | } |
| 982 | 1005 | ||
| 983 | static void eeepc_rfkill_exit(void) | 1006 | static int eeepc_hwmon_init(struct eeepc_laptop *eeepc) |
| 984 | { | 1007 | { |
| 985 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P5"); | 1008 | struct device *hwmon; |
| 986 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6"); | 1009 | int result; |
| 987 | eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7"); | 1010 | |
| 988 | if (ehotk->wlan_rfkill) { | 1011 | hwmon = hwmon_device_register(&eeepc->platform_device->dev); |
| 989 | rfkill_unregister(ehotk->wlan_rfkill); | 1012 | if (IS_ERR(hwmon)) { |
| 990 | rfkill_destroy(ehotk->wlan_rfkill); | 1013 | pr_err("Could not register eeepc hwmon device\n"); |
| 991 | ehotk->wlan_rfkill = NULL; | 1014 | eeepc->hwmon_device = NULL; |
| 992 | } | 1015 | return PTR_ERR(hwmon); |
| 993 | /* | ||
| 994 | * Refresh pci hotplug in case the rfkill state was changed after | ||
| 995 | * eeepc_unregister_rfkill_notifier() | ||
| 996 | */ | ||
| 997 | eeepc_rfkill_hotplug(); | ||
| 998 | if (ehotk->hotplug_slot) | ||
| 999 | pci_hp_deregister(ehotk->hotplug_slot); | ||
| 1000 | |||
| 1001 | if (ehotk->bluetooth_rfkill) { | ||
| 1002 | rfkill_unregister(ehotk->bluetooth_rfkill); | ||
| 1003 | rfkill_destroy(ehotk->bluetooth_rfkill); | ||
| 1004 | ehotk->bluetooth_rfkill = NULL; | ||
| 1005 | } | ||
| 1006 | if (ehotk->wwan3g_rfkill) { | ||
| 1007 | rfkill_unregister(ehotk->wwan3g_rfkill); | ||
| 1008 | rfkill_destroy(ehotk->wwan3g_rfkill); | ||
| 1009 | ehotk->wwan3g_rfkill = NULL; | ||
| 1010 | } | ||
| 1011 | if (ehotk->wimax_rfkill) { | ||
| 1012 | rfkill_unregister(ehotk->wimax_rfkill); | ||
| 1013 | rfkill_destroy(ehotk->wimax_rfkill); | ||
| 1014 | ehotk->wimax_rfkill = NULL; | ||
| 1015 | } | 1016 | } |
| 1017 | eeepc->hwmon_device = hwmon; | ||
| 1018 | result = sysfs_create_group(&hwmon->kobj, | ||
| 1019 | &hwmon_attribute_group); | ||
| 1020 | if (result) | ||
| 1021 | eeepc_hwmon_exit(eeepc); | ||
| 1022 | return result; | ||
| 1016 | } | 1023 | } |
| 1017 | 1024 | ||
| 1018 | static void eeepc_input_exit(void) | 1025 | /* |
| 1026 | * Backlight device | ||
| 1027 | */ | ||
| 1028 | static int read_brightness(struct backlight_device *bd) | ||
| 1019 | { | 1029 | { |
| 1020 | if (ehotk->inputdev) | 1030 | struct eeepc_laptop *eeepc = bl_get_data(bd); |
| 1021 | input_unregister_device(ehotk->inputdev); | 1031 | |
| 1032 | return get_acpi(eeepc, CM_ASL_PANELBRIGHT); | ||
| 1022 | } | 1033 | } |
| 1023 | 1034 | ||
| 1024 | static void eeepc_hwmon_exit(void) | 1035 | static int set_brightness(struct backlight_device *bd, int value) |
| 1025 | { | 1036 | { |
| 1026 | struct device *hwmon; | 1037 | struct eeepc_laptop *eeepc = bl_get_data(bd); |
| 1027 | 1038 | ||
| 1028 | hwmon = eeepc_hwmon_device; | 1039 | return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value); |
| 1029 | if (!hwmon) | ||
| 1030 | return ; | ||
| 1031 | sysfs_remove_group(&hwmon->kobj, | ||
| 1032 | &hwmon_attribute_group); | ||
| 1033 | hwmon_device_unregister(hwmon); | ||
| 1034 | eeepc_hwmon_device = NULL; | ||
| 1035 | } | 1040 | } |
| 1036 | 1041 | ||
| 1037 | static int eeepc_new_rfkill(struct rfkill **rfkill, | 1042 | static int update_bl_status(struct backlight_device *bd) |
| 1038 | const char *name, struct device *dev, | ||
| 1039 | enum rfkill_type type, int cm) | ||
| 1040 | { | 1043 | { |
| 1041 | int result; | 1044 | return set_brightness(bd, bd->props.brightness); |
| 1045 | } | ||
| 1042 | 1046 | ||
| 1043 | result = get_acpi(cm); | 1047 | static struct backlight_ops eeepcbl_ops = { |
| 1044 | if (result < 0) | 1048 | .get_brightness = read_brightness, |
| 1045 | return result; | 1049 | .update_status = update_bl_status, |
| 1050 | }; | ||
| 1046 | 1051 | ||
| 1047 | *rfkill = rfkill_alloc(name, dev, type, | 1052 | static int eeepc_backlight_notify(struct eeepc_laptop *eeepc) |
| 1048 | &eeepc_rfkill_ops, (void *)(unsigned long)cm); | 1053 | { |
| 1054 | struct backlight_device *bd = eeepc->backlight_device; | ||
| 1055 | int old = bd->props.brightness; | ||
| 1049 | 1056 | ||
| 1050 | if (!*rfkill) | 1057 | backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY); |
| 1051 | return -EINVAL; | ||
| 1052 | 1058 | ||
| 1053 | rfkill_init_sw_state(*rfkill, get_acpi(cm) != 1); | 1059 | return old; |
| 1054 | result = rfkill_register(*rfkill); | ||
| 1055 | if (result) { | ||
| 1056 | rfkill_destroy(*rfkill); | ||
| 1057 | *rfkill = NULL; | ||
| 1058 | return result; | ||
| 1059 | } | ||
| 1060 | return 0; | ||
| 1061 | } | 1060 | } |
| 1062 | 1061 | ||
| 1063 | 1062 | static int eeepc_backlight_init(struct eeepc_laptop *eeepc) | |
| 1064 | static int eeepc_rfkill_init(struct device *dev) | ||
| 1065 | { | 1063 | { |
| 1066 | int result = 0; | 1064 | struct backlight_device *bd; |
| 1067 | |||
| 1068 | mutex_init(&ehotk->hotplug_lock); | ||
| 1069 | 1065 | ||
| 1070 | result = eeepc_new_rfkill(&ehotk->wlan_rfkill, | 1066 | bd = backlight_device_register(EEEPC_LAPTOP_FILE, |
| 1071 | "eeepc-wlan", dev, | 1067 | &eeepc->platform_device->dev, |
| 1072 | RFKILL_TYPE_WLAN, CM_ASL_WLAN); | 1068 | eeepc, &eeepcbl_ops); |
| 1069 | if (IS_ERR(bd)) { | ||
| 1070 | pr_err("Could not register eeepc backlight device\n"); | ||
| 1071 | eeepc->backlight_device = NULL; | ||
| 1072 | return PTR_ERR(bd); | ||
| 1073 | } | ||
| 1074 | eeepc->backlight_device = bd; | ||
| 1075 | bd->props.max_brightness = 15; | ||
| 1076 | bd->props.brightness = read_brightness(bd); | ||
| 1077 | bd->props.power = FB_BLANK_UNBLANK; | ||
| 1078 | backlight_update_status(bd); | ||
| 1079 | return 0; | ||
| 1080 | } | ||
| 1073 | 1081 | ||
| 1074 | if (result && result != -ENODEV) | 1082 | static void eeepc_backlight_exit(struct eeepc_laptop *eeepc) |
| 1075 | goto exit; | 1083 | { |
| 1084 | if (eeepc->backlight_device) | ||
| 1085 | backlight_device_unregister(eeepc->backlight_device); | ||
| 1086 | eeepc->backlight_device = NULL; | ||
| 1087 | } | ||
| 1076 | 1088 | ||
| 1077 | result = eeepc_new_rfkill(&ehotk->bluetooth_rfkill, | ||
| 1078 | "eeepc-bluetooth", dev, | ||
| 1079 | RFKILL_TYPE_BLUETOOTH, CM_ASL_BLUETOOTH); | ||
| 1080 | 1089 | ||
| 1081 | if (result && result != -ENODEV) | 1090 | /* |
| 1082 | goto exit; | 1091 | * Input device (i.e. hotkeys) |
| 1092 | */ | ||
| 1093 | static struct key_entry *eeepc_get_entry_by_scancode( | ||
| 1094 | struct eeepc_laptop *eeepc, | ||
| 1095 | int code) | ||
| 1096 | { | ||
| 1097 | struct key_entry *key; | ||
| 1083 | 1098 | ||
| 1084 | result = eeepc_new_rfkill(&ehotk->wwan3g_rfkill, | 1099 | for (key = eeepc->keymap; key->type != KE_END; key++) |
| 1085 | "eeepc-wwan3g", dev, | 1100 | if (code == key->code) |
| 1086 | RFKILL_TYPE_WWAN, CM_ASL_3G); | 1101 | return key; |
| 1087 | 1102 | ||
| 1088 | if (result && result != -ENODEV) | 1103 | return NULL; |
| 1089 | goto exit; | 1104 | } |
| 1090 | 1105 | ||
| 1091 | result = eeepc_new_rfkill(&ehotk->wimax_rfkill, | 1106 | static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event) |
| 1092 | "eeepc-wimax", dev, | 1107 | { |
| 1093 | RFKILL_TYPE_WIMAX, CM_ASL_WIMAX); | 1108 | static struct key_entry *key; |
| 1094 | 1109 | ||
| 1095 | if (result && result != -ENODEV) | 1110 | key = eeepc_get_entry_by_scancode(eeepc, event); |
| 1096 | goto exit; | 1111 | if (key) { |
| 1112 | switch (key->type) { | ||
| 1113 | case KE_KEY: | ||
| 1114 | input_report_key(eeepc->inputdev, key->keycode, | ||
| 1115 | 1); | ||
| 1116 | input_sync(eeepc->inputdev); | ||
| 1117 | input_report_key(eeepc->inputdev, key->keycode, | ||
| 1118 | 0); | ||
| 1119 | input_sync(eeepc->inputdev); | ||
| 1120 | break; | ||
| 1121 | } | ||
| 1122 | } | ||
| 1123 | } | ||
| 1097 | 1124 | ||
| 1098 | result = eeepc_setup_pci_hotplug(); | 1125 | static struct key_entry *eeepc_get_entry_by_keycode( |
| 1099 | /* | 1126 | struct eeepc_laptop *eeepc, int code) |
| 1100 | * If we get -EBUSY then something else is handling the PCI hotplug - | 1127 | { |
| 1101 | * don't fail in this case | 1128 | struct key_entry *key; |
| 1102 | */ | ||
| 1103 | if (result == -EBUSY) | ||
| 1104 | result = 0; | ||
| 1105 | 1129 | ||
| 1106 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P5"); | 1130 | for (key = eeepc->keymap; key->type != KE_END; key++) |
| 1107 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6"); | 1131 | if (code == key->keycode && key->type == KE_KEY) |
| 1108 | eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7"); | 1132 | return key; |
| 1109 | /* | ||
| 1110 | * Refresh pci hotplug in case the rfkill state was changed during | ||
| 1111 | * setup. | ||
| 1112 | */ | ||
| 1113 | eeepc_rfkill_hotplug(); | ||
| 1114 | 1133 | ||
| 1115 | exit: | 1134 | return NULL; |
| 1116 | if (result && result != -ENODEV) | ||
| 1117 | eeepc_rfkill_exit(); | ||
| 1118 | return result; | ||
| 1119 | } | 1135 | } |
| 1120 | 1136 | ||
| 1121 | static int eeepc_backlight_init(struct device *dev) | 1137 | static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode) |
| 1122 | { | 1138 | { |
| 1123 | struct backlight_device *bd; | 1139 | struct eeepc_laptop *eeepc = input_get_drvdata(dev); |
| 1140 | struct key_entry *key = eeepc_get_entry_by_scancode(eeepc, scancode); | ||
| 1124 | 1141 | ||
| 1125 | bd = backlight_device_register(EEEPC_HOTK_FILE, dev, | 1142 | if (key && key->type == KE_KEY) { |
| 1126 | NULL, &eeepcbl_ops); | 1143 | *keycode = key->keycode; |
| 1127 | if (IS_ERR(bd)) { | 1144 | return 0; |
| 1128 | pr_err("Could not register eeepc backlight device\n"); | ||
| 1129 | eeepc_backlight_device = NULL; | ||
| 1130 | return PTR_ERR(bd); | ||
| 1131 | } | 1145 | } |
| 1132 | eeepc_backlight_device = bd; | 1146 | |
| 1133 | bd->props.max_brightness = 15; | 1147 | return -EINVAL; |
| 1134 | bd->props.brightness = read_brightness(NULL); | ||
| 1135 | bd->props.power = FB_BLANK_UNBLANK; | ||
| 1136 | backlight_update_status(bd); | ||
| 1137 | return 0; | ||
| 1138 | } | 1148 | } |
| 1139 | 1149 | ||
| 1140 | static int eeepc_hwmon_init(struct device *dev) | 1150 | static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode) |
| 1141 | { | 1151 | { |
| 1142 | struct device *hwmon; | 1152 | struct eeepc_laptop *eeepc = input_get_drvdata(dev); |
| 1143 | int result; | 1153 | struct key_entry *key; |
| 1154 | int old_keycode; | ||
| 1144 | 1155 | ||
| 1145 | hwmon = hwmon_device_register(dev); | 1156 | if (keycode < 0 || keycode > KEY_MAX) |
| 1146 | if (IS_ERR(hwmon)) { | 1157 | return -EINVAL; |
| 1147 | pr_err("Could not register eeepc hwmon device\n"); | 1158 | |
| 1148 | eeepc_hwmon_device = NULL; | 1159 | key = eeepc_get_entry_by_scancode(eeepc, scancode); |
| 1149 | return PTR_ERR(hwmon); | 1160 | if (key && key->type == KE_KEY) { |
| 1161 | old_keycode = key->keycode; | ||
| 1162 | key->keycode = keycode; | ||
| 1163 | set_bit(keycode, dev->keybit); | ||
| 1164 | if (!eeepc_get_entry_by_keycode(eeepc, old_keycode)) | ||
| 1165 | clear_bit(old_keycode, dev->keybit); | ||
| 1166 | return 0; | ||
| 1150 | } | 1167 | } |
| 1151 | eeepc_hwmon_device = hwmon; | 1168 | |
| 1152 | result = sysfs_create_group(&hwmon->kobj, | 1169 | return -EINVAL; |
| 1153 | &hwmon_attribute_group); | ||
| 1154 | if (result) | ||
| 1155 | eeepc_hwmon_exit(); | ||
| 1156 | return result; | ||
| 1157 | } | 1170 | } |
| 1158 | 1171 | ||
| 1159 | static int eeepc_input_init(struct device *dev) | 1172 | static int eeepc_input_init(struct eeepc_laptop *eeepc) |
| 1160 | { | 1173 | { |
| 1161 | const struct key_entry *key; | 1174 | const struct key_entry *key; |
| 1162 | int result; | 1175 | int result; |
| 1163 | 1176 | ||
| 1164 | ehotk->inputdev = input_allocate_device(); | 1177 | eeepc->inputdev = input_allocate_device(); |
| 1165 | if (!ehotk->inputdev) { | 1178 | if (!eeepc->inputdev) { |
| 1166 | pr_info("Unable to allocate input device\n"); | 1179 | pr_info("Unable to allocate input device\n"); |
| 1167 | return -ENOMEM; | 1180 | return -ENOMEM; |
| 1168 | } | 1181 | } |
| 1169 | ehotk->inputdev->name = "Asus EeePC extra buttons"; | 1182 | eeepc->inputdev->name = "Asus EeePC extra buttons"; |
| 1170 | ehotk->inputdev->dev.parent = dev; | 1183 | eeepc->inputdev->dev.parent = &eeepc->platform_device->dev; |
| 1171 | ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0"; | 1184 | eeepc->inputdev->phys = EEEPC_LAPTOP_FILE "/input0"; |
| 1172 | ehotk->inputdev->id.bustype = BUS_HOST; | 1185 | eeepc->inputdev->id.bustype = BUS_HOST; |
| 1173 | ehotk->inputdev->getkeycode = eeepc_getkeycode; | 1186 | eeepc->inputdev->getkeycode = eeepc_getkeycode; |
| 1174 | ehotk->inputdev->setkeycode = eeepc_setkeycode; | 1187 | eeepc->inputdev->setkeycode = eeepc_setkeycode; |
| 1175 | 1188 | input_set_drvdata(eeepc->inputdev, eeepc); | |
| 1189 | |||
| 1190 | eeepc->keymap = kmemdup(eeepc_keymap, sizeof(eeepc_keymap), | ||
| 1191 | GFP_KERNEL); | ||
| 1176 | for (key = eeepc_keymap; key->type != KE_END; key++) { | 1192 | for (key = eeepc_keymap; key->type != KE_END; key++) { |
| 1177 | switch (key->type) { | 1193 | switch (key->type) { |
| 1178 | case KE_KEY: | 1194 | case KE_KEY: |
| 1179 | set_bit(EV_KEY, ehotk->inputdev->evbit); | 1195 | set_bit(EV_KEY, eeepc->inputdev->evbit); |
| 1180 | set_bit(key->keycode, ehotk->inputdev->keybit); | 1196 | set_bit(key->keycode, eeepc->inputdev->keybit); |
| 1181 | break; | 1197 | break; |
| 1182 | } | 1198 | } |
| 1183 | } | 1199 | } |
| 1184 | result = input_register_device(ehotk->inputdev); | 1200 | result = input_register_device(eeepc->inputdev); |
| 1185 | if (result) { | 1201 | if (result) { |
| 1186 | pr_info("Unable to register input device\n"); | 1202 | pr_info("Unable to register input device\n"); |
| 1187 | input_free_device(ehotk->inputdev); | 1203 | input_free_device(eeepc->inputdev); |
| 1188 | return result; | 1204 | return result; |
| 1189 | } | 1205 | } |
| 1190 | return 0; | 1206 | return 0; |
| 1191 | } | 1207 | } |
| 1192 | 1208 | ||
| 1193 | static int __devinit eeepc_hotk_add(struct acpi_device *device) | 1209 | static void eeepc_input_exit(struct eeepc_laptop *eeepc) |
| 1194 | { | 1210 | { |
| 1195 | struct device *dev; | 1211 | if (eeepc->inputdev) { |
| 1212 | input_unregister_device(eeepc->inputdev); | ||
| 1213 | kfree(eeepc->keymap); | ||
| 1214 | } | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | /* | ||
| 1218 | * ACPI driver | ||
| 1219 | */ | ||
| 1220 | static void eeepc_acpi_notify(struct acpi_device *device, u32 event) | ||
| 1221 | { | ||
| 1222 | struct eeepc_laptop *eeepc = acpi_driver_data(device); | ||
| 1223 | u16 count; | ||
| 1224 | |||
| 1225 | if (event > ACPI_MAX_SYS_NOTIFY) | ||
| 1226 | return; | ||
| 1227 | count = eeepc->event_count[event % 128]++; | ||
| 1228 | acpi_bus_generate_proc_event(device, event, count); | ||
| 1229 | acpi_bus_generate_netlink_event(device->pnp.device_class, | ||
| 1230 | dev_name(&device->dev), event, | ||
| 1231 | count); | ||
| 1232 | |||
| 1233 | /* Brightness events are special */ | ||
| 1234 | if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) { | ||
| 1235 | |||
| 1236 | /* Ignore them completely if the acpi video driver is used */ | ||
| 1237 | if (eeepc->backlight_device != NULL) { | ||
| 1238 | int old_brightness, new_brightness; | ||
| 1239 | |||
| 1240 | /* Update the backlight device. */ | ||
| 1241 | old_brightness = eeepc_backlight_notify(eeepc); | ||
| 1242 | |||
| 1243 | /* Convert event to keypress (obsolescent hack) */ | ||
| 1244 | new_brightness = event - NOTIFY_BRN_MIN; | ||
| 1245 | |||
| 1246 | if (new_brightness < old_brightness) { | ||
| 1247 | event = NOTIFY_BRN_MIN; /* brightness down */ | ||
| 1248 | } else if (new_brightness > old_brightness) { | ||
| 1249 | event = NOTIFY_BRN_MAX; /* brightness up */ | ||
| 1250 | } else { | ||
| 1251 | /* | ||
| 1252 | * no change in brightness - already at min/max, | ||
| 1253 | * event will be desired value (or else ignored) | ||
| 1254 | */ | ||
| 1255 | } | ||
| 1256 | eeepc_input_notify(eeepc, event); | ||
| 1257 | } | ||
| 1258 | } else { | ||
| 1259 | /* Everything else is a bona-fide keypress event */ | ||
| 1260 | eeepc_input_notify(eeepc, event); | ||
| 1261 | } | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name) | ||
| 1265 | { | ||
| 1266 | int dummy; | ||
| 1267 | |||
| 1268 | /* Some BIOSes do not report cm although it is avaliable. | ||
| 1269 | Check if cm_getv[cm] works and, if yes, assume cm should be set. */ | ||
| 1270 | if (!(eeepc->cm_supported & (1 << cm)) | ||
| 1271 | && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) { | ||
| 1272 | pr_info("%s (%x) not reported by BIOS," | ||
| 1273 | " enabling anyway\n", name, 1 << cm); | ||
| 1274 | eeepc->cm_supported |= 1 << cm; | ||
| 1275 | } | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | static void cmsg_quirks(struct eeepc_laptop *eeepc) | ||
| 1279 | { | ||
| 1280 | cmsg_quirk(eeepc, CM_ASL_LID, "LID"); | ||
| 1281 | cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE"); | ||
| 1282 | cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER"); | ||
| 1283 | cmsg_quirk(eeepc, CM_ASL_TPD, "TPD"); | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | static int eeepc_acpi_init(struct eeepc_laptop *eeepc, | ||
| 1287 | struct acpi_device *device) | ||
| 1288 | { | ||
| 1289 | unsigned int init_flags; | ||
| 1196 | int result; | 1290 | int result; |
| 1197 | 1291 | ||
| 1198 | if (!device) | 1292 | result = acpi_bus_get_status(device); |
| 1199 | return -EINVAL; | ||
| 1200 | pr_notice(EEEPC_HOTK_NAME "\n"); | ||
| 1201 | ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL); | ||
| 1202 | if (!ehotk) | ||
| 1203 | return -ENOMEM; | ||
| 1204 | ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; | ||
| 1205 | ehotk->handle = device->handle; | ||
| 1206 | strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME); | ||
| 1207 | strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS); | ||
| 1208 | device->driver_data = ehotk; | ||
| 1209 | ehotk->device = device; | ||
| 1210 | |||
| 1211 | result = eeepc_hotk_check(); | ||
| 1212 | if (result) | 1293 | if (result) |
| 1213 | goto fail_platform_driver; | 1294 | return result; |
| 1214 | eeepc_enable_camera(); | 1295 | if (!device->status.present) { |
| 1296 | pr_err("Hotkey device not present, aborting\n"); | ||
| 1297 | return -ENODEV; | ||
| 1298 | } | ||
| 1215 | 1299 | ||
| 1216 | /* Register platform stuff */ | 1300 | init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH; |
| 1217 | result = platform_driver_register(&platform_driver); | 1301 | pr_notice("Hotkey init flags 0x%x\n", init_flags); |
| 1218 | if (result) | 1302 | |
| 1219 | goto fail_platform_driver; | 1303 | if (write_acpi_int(eeepc->handle, "INIT", init_flags)) { |
| 1220 | platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1); | 1304 | pr_err("Hotkey initialization failed\n"); |
| 1221 | if (!platform_device) { | 1305 | return -ENODEV; |
| 1222 | result = -ENOMEM; | ||
| 1223 | goto fail_platform_device1; | ||
| 1224 | } | 1306 | } |
| 1225 | result = platform_device_add(platform_device); | 1307 | |
| 1226 | if (result) | 1308 | /* get control methods supported */ |
| 1227 | goto fail_platform_device2; | 1309 | if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) { |
| 1228 | result = sysfs_create_group(&platform_device->dev.kobj, | 1310 | pr_err("Get control methods supported failed\n"); |
| 1229 | &platform_attribute_group); | 1311 | return -ENODEV; |
| 1312 | } | ||
| 1313 | cmsg_quirks(eeepc); | ||
| 1314 | pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported); | ||
| 1315 | |||
| 1316 | return 0; | ||
| 1317 | } | ||
| 1318 | |||
| 1319 | static void __devinit eeepc_enable_camera(struct eeepc_laptop *eeepc) | ||
| 1320 | { | ||
| 1321 | /* | ||
| 1322 | * If the following call to set_acpi() fails, it's because there's no | ||
| 1323 | * camera so we can ignore the error. | ||
| 1324 | */ | ||
| 1325 | if (get_acpi(eeepc, CM_ASL_CAMERA) == 0) | ||
| 1326 | set_acpi(eeepc, CM_ASL_CAMERA, 1); | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | static bool eeepc_device_present; | ||
| 1330 | |||
| 1331 | static int __devinit eeepc_acpi_add(struct acpi_device *device) | ||
| 1332 | { | ||
| 1333 | struct eeepc_laptop *eeepc; | ||
| 1334 | int result; | ||
| 1335 | |||
| 1336 | pr_notice(EEEPC_LAPTOP_NAME "\n"); | ||
| 1337 | eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL); | ||
| 1338 | if (!eeepc) | ||
| 1339 | return -ENOMEM; | ||
| 1340 | eeepc->handle = device->handle; | ||
| 1341 | strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME); | ||
| 1342 | strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS); | ||
| 1343 | device->driver_data = eeepc; | ||
| 1344 | |||
| 1345 | result = eeepc_acpi_init(eeepc, device); | ||
| 1230 | if (result) | 1346 | if (result) |
| 1231 | goto fail_sysfs; | 1347 | goto fail_platform; |
| 1348 | eeepc_enable_camera(eeepc); | ||
| 1232 | 1349 | ||
| 1233 | dev = &platform_device->dev; | 1350 | /* |
| 1351 | * Register the platform device first. It is used as a parent for the | ||
| 1352 | * sub-devices below. | ||
| 1353 | * | ||
| 1354 | * Note that if there are multiple instances of this ACPI device it | ||
| 1355 | * will bail out, because the platform device is registered with a | ||
| 1356 | * fixed name. Of course it doesn't make sense to have more than one, | ||
| 1357 | * and machine-specific scripts find the fixed name convenient. But | ||
| 1358 | * It's also good for us to exclude multiple instances because both | ||
| 1359 | * our hwmon and our wlan rfkill subdevice use global ACPI objects | ||
| 1360 | * (the EC and the wlan PCI slot respectively). | ||
| 1361 | */ | ||
| 1362 | result = eeepc_platform_init(eeepc); | ||
| 1363 | if (result) | ||
| 1364 | goto fail_platform; | ||
| 1234 | 1365 | ||
| 1235 | if (!acpi_video_backlight_support()) { | 1366 | if (!acpi_video_backlight_support()) { |
| 1236 | result = eeepc_backlight_init(dev); | 1367 | result = eeepc_backlight_init(eeepc); |
| 1237 | if (result) | 1368 | if (result) |
| 1238 | goto fail_backlight; | 1369 | goto fail_backlight; |
| 1239 | } else | 1370 | } else |
| 1240 | pr_info("Backlight controlled by ACPI video " | 1371 | pr_info("Backlight controlled by ACPI video driver\n"); |
| 1241 | "driver\n"); | ||
| 1242 | 1372 | ||
| 1243 | result = eeepc_input_init(dev); | 1373 | result = eeepc_input_init(eeepc); |
| 1244 | if (result) | 1374 | if (result) |
| 1245 | goto fail_input; | 1375 | goto fail_input; |
| 1246 | 1376 | ||
| 1247 | result = eeepc_hwmon_init(dev); | 1377 | result = eeepc_hwmon_init(eeepc); |
| 1248 | if (result) | 1378 | if (result) |
| 1249 | goto fail_hwmon; | 1379 | goto fail_hwmon; |
| 1250 | 1380 | ||
| 1251 | result = eeepc_rfkill_init(dev); | 1381 | result = eeepc_led_init(eeepc); |
| 1382 | if (result) | ||
| 1383 | goto fail_led; | ||
| 1384 | |||
| 1385 | result = eeepc_rfkill_init(eeepc); | ||
| 1252 | if (result) | 1386 | if (result) |
| 1253 | goto fail_rfkill; | 1387 | goto fail_rfkill; |
| 1254 | 1388 | ||
| 1389 | eeepc_device_present = true; | ||
| 1255 | return 0; | 1390 | return 0; |
| 1256 | 1391 | ||
| 1257 | fail_rfkill: | 1392 | fail_rfkill: |
| 1258 | eeepc_hwmon_exit(); | 1393 | eeepc_led_exit(eeepc); |
| 1394 | fail_led: | ||
| 1395 | eeepc_hwmon_exit(eeepc); | ||
| 1259 | fail_hwmon: | 1396 | fail_hwmon: |
| 1260 | eeepc_input_exit(); | 1397 | eeepc_input_exit(eeepc); |
| 1261 | fail_input: | 1398 | fail_input: |
| 1262 | eeepc_backlight_exit(); | 1399 | eeepc_backlight_exit(eeepc); |
| 1263 | fail_backlight: | 1400 | fail_backlight: |
| 1264 | sysfs_remove_group(&platform_device->dev.kobj, | 1401 | eeepc_platform_exit(eeepc); |
| 1265 | &platform_attribute_group); | 1402 | fail_platform: |
| 1266 | fail_sysfs: | 1403 | kfree(eeepc); |
| 1267 | platform_device_del(platform_device); | ||
| 1268 | fail_platform_device2: | ||
| 1269 | platform_device_put(platform_device); | ||
| 1270 | fail_platform_device1: | ||
| 1271 | platform_driver_unregister(&platform_driver); | ||
| 1272 | fail_platform_driver: | ||
| 1273 | kfree(ehotk); | ||
| 1274 | 1404 | ||
| 1275 | return result; | 1405 | return result; |
| 1276 | } | 1406 | } |
| 1277 | 1407 | ||
| 1278 | static int eeepc_hotk_remove(struct acpi_device *device, int type) | 1408 | static int eeepc_acpi_remove(struct acpi_device *device, int type) |
| 1279 | { | 1409 | { |
| 1280 | if (!device || !acpi_driver_data(device)) | 1410 | struct eeepc_laptop *eeepc = acpi_driver_data(device); |
| 1281 | return -EINVAL; | ||
| 1282 | 1411 | ||
| 1283 | eeepc_backlight_exit(); | 1412 | eeepc_backlight_exit(eeepc); |
| 1284 | eeepc_rfkill_exit(); | 1413 | eeepc_rfkill_exit(eeepc); |
| 1285 | eeepc_input_exit(); | 1414 | eeepc_input_exit(eeepc); |
| 1286 | eeepc_hwmon_exit(); | 1415 | eeepc_hwmon_exit(eeepc); |
| 1287 | sysfs_remove_group(&platform_device->dev.kobj, | 1416 | eeepc_led_exit(eeepc); |
| 1288 | &platform_attribute_group); | 1417 | eeepc_platform_exit(eeepc); |
| 1289 | platform_device_unregister(platform_device); | ||
| 1290 | platform_driver_unregister(&platform_driver); | ||
| 1291 | 1418 | ||
| 1292 | kfree(ehotk); | 1419 | kfree(eeepc); |
| 1293 | return 0; | 1420 | return 0; |
| 1294 | } | 1421 | } |
| 1295 | 1422 | ||
| 1423 | |||
| 1424 | static const struct acpi_device_id eeepc_device_ids[] = { | ||
| 1425 | {EEEPC_ACPI_HID, 0}, | ||
| 1426 | {"", 0}, | ||
| 1427 | }; | ||
| 1428 | MODULE_DEVICE_TABLE(acpi, eeepc_device_ids); | ||
| 1429 | |||
| 1430 | static struct acpi_driver eeepc_acpi_driver = { | ||
| 1431 | .name = EEEPC_LAPTOP_NAME, | ||
| 1432 | .class = EEEPC_ACPI_CLASS, | ||
| 1433 | .owner = THIS_MODULE, | ||
| 1434 | .ids = eeepc_device_ids, | ||
| 1435 | .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS, | ||
| 1436 | .ops = { | ||
| 1437 | .add = eeepc_acpi_add, | ||
| 1438 | .remove = eeepc_acpi_remove, | ||
| 1439 | .notify = eeepc_acpi_notify, | ||
| 1440 | }, | ||
| 1441 | }; | ||
| 1442 | |||
| 1443 | |||
| 1296 | static int __init eeepc_laptop_init(void) | 1444 | static int __init eeepc_laptop_init(void) |
| 1297 | { | 1445 | { |
| 1298 | int result; | 1446 | int result; |
| 1299 | 1447 | ||
| 1300 | if (acpi_disabled) | 1448 | result = platform_driver_register(&platform_driver); |
| 1301 | return -ENODEV; | ||
| 1302 | result = acpi_bus_register_driver(&eeepc_hotk_driver); | ||
| 1303 | if (result < 0) | 1449 | if (result < 0) |
| 1304 | return result; | 1450 | return result; |
| 1305 | if (!ehotk) { | 1451 | |
| 1306 | acpi_bus_unregister_driver(&eeepc_hotk_driver); | 1452 | result = acpi_bus_register_driver(&eeepc_acpi_driver); |
| 1307 | return -ENODEV; | 1453 | if (result < 0) |
| 1454 | goto fail_acpi_driver; | ||
| 1455 | if (!eeepc_device_present) { | ||
| 1456 | result = -ENODEV; | ||
| 1457 | goto fail_no_device; | ||
| 1308 | } | 1458 | } |
| 1309 | return 0; | 1459 | return 0; |
| 1460 | |||
| 1461 | fail_no_device: | ||
| 1462 | acpi_bus_unregister_driver(&eeepc_acpi_driver); | ||
| 1463 | fail_acpi_driver: | ||
| 1464 | platform_driver_unregister(&platform_driver); | ||
| 1465 | return result; | ||
| 1310 | } | 1466 | } |
| 1311 | 1467 | ||
| 1312 | static void __exit eeepc_laptop_exit(void) | 1468 | static void __exit eeepc_laptop_exit(void) |
| 1313 | { | 1469 | { |
| 1314 | acpi_bus_unregister_driver(&eeepc_hotk_driver); | 1470 | acpi_bus_unregister_driver(&eeepc_acpi_driver); |
| 1471 | platform_driver_unregister(&platform_driver); | ||
| 1315 | } | 1472 | } |
| 1316 | 1473 | ||
| 1317 | module_init(eeepc_laptop_init); | 1474 | module_init(eeepc_laptop_init); |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index f00a71c58e69..63c3e658a884 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
| @@ -51,6 +51,12 @@ MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4"); | |||
| 51 | #define HPWMI_WIRELESS_QUERY 0x5 | 51 | #define HPWMI_WIRELESS_QUERY 0x5 |
| 52 | #define HPWMI_HOTKEY_QUERY 0xc | 52 | #define HPWMI_HOTKEY_QUERY 0xc |
| 53 | 53 | ||
| 54 | enum hp_wmi_radio { | ||
| 55 | HPWMI_WIFI = 0, | ||
| 56 | HPWMI_BLUETOOTH = 1, | ||
| 57 | HPWMI_WWAN = 2, | ||
| 58 | }; | ||
| 59 | |||
| 54 | static int __init hp_wmi_bios_setup(struct platform_device *device); | 60 | static int __init hp_wmi_bios_setup(struct platform_device *device); |
| 55 | static int __exit hp_wmi_bios_remove(struct platform_device *device); | 61 | static int __exit hp_wmi_bios_remove(struct platform_device *device); |
| 56 | static int hp_wmi_resume_handler(struct device *device); | 62 | static int hp_wmi_resume_handler(struct device *device); |
| @@ -175,8 +181,8 @@ static int hp_wmi_tablet_state(void) | |||
| 175 | 181 | ||
| 176 | static int hp_wmi_set_block(void *data, bool blocked) | 182 | static int hp_wmi_set_block(void *data, bool blocked) |
| 177 | { | 183 | { |
| 178 | unsigned long b = (unsigned long) data; | 184 | enum hp_wmi_radio r = (enum hp_wmi_radio) data; |
| 179 | int query = BIT(b + 8) | ((!blocked) << b); | 185 | int query = BIT(r + 8) | ((!blocked) << r); |
| 180 | 186 | ||
| 181 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); | 187 | return hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1, query); |
| 182 | } | 188 | } |
| @@ -185,31 +191,23 @@ static const struct rfkill_ops hp_wmi_rfkill_ops = { | |||
| 185 | .set_block = hp_wmi_set_block, | 191 | .set_block = hp_wmi_set_block, |
| 186 | }; | 192 | }; |
| 187 | 193 | ||
| 188 | static bool hp_wmi_wifi_state(void) | 194 | static bool hp_wmi_get_sw_state(enum hp_wmi_radio r) |
| 189 | { | ||
| 190 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | ||
| 191 | |||
| 192 | if (wireless & 0x100) | ||
| 193 | return false; | ||
| 194 | else | ||
| 195 | return true; | ||
| 196 | } | ||
| 197 | |||
| 198 | static bool hp_wmi_bluetooth_state(void) | ||
| 199 | { | 195 | { |
| 200 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 196 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
| 197 | int mask = 0x200 << (r * 8); | ||
| 201 | 198 | ||
| 202 | if (wireless & 0x10000) | 199 | if (wireless & mask) |
| 203 | return false; | 200 | return false; |
| 204 | else | 201 | else |
| 205 | return true; | 202 | return true; |
| 206 | } | 203 | } |
| 207 | 204 | ||
| 208 | static bool hp_wmi_wwan_state(void) | 205 | static bool hp_wmi_get_hw_state(enum hp_wmi_radio r) |
| 209 | { | 206 | { |
| 210 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); | 207 | int wireless = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, 0); |
| 208 | int mask = 0x800 << (r * 8); | ||
| 211 | 209 | ||
| 212 | if (wireless & 0x1000000) | 210 | if (wireless & mask) |
| 213 | return false; | 211 | return false; |
| 214 | else | 212 | else |
| 215 | return true; | 213 | return true; |
| @@ -334,49 +332,55 @@ static void hp_wmi_notify(u32 value, void *context) | |||
| 334 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | 332 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 335 | static struct key_entry *key; | 333 | static struct key_entry *key; |
| 336 | union acpi_object *obj; | 334 | union acpi_object *obj; |
| 335 | int eventcode; | ||
| 337 | 336 | ||
| 338 | wmi_get_event_data(value, &response); | 337 | wmi_get_event_data(value, &response); |
| 339 | 338 | ||
| 340 | obj = (union acpi_object *)response.pointer; | 339 | obj = (union acpi_object *)response.pointer; |
| 341 | 340 | ||
| 342 | if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == 8) { | 341 | if (!obj || obj->type != ACPI_TYPE_BUFFER || obj->buffer.length != 8) { |
| 343 | int eventcode = *((u8 *) obj->buffer.pointer); | 342 | printk(KERN_INFO "HP WMI: Unknown response received\n"); |
| 344 | if (eventcode == 0x4) | 343 | return; |
| 345 | eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, | 344 | } |
| 346 | 0); | 345 | |
| 347 | key = hp_wmi_get_entry_by_scancode(eventcode); | 346 | eventcode = *((u8 *) obj->buffer.pointer); |
| 348 | if (key) { | 347 | if (eventcode == 0x4) |
| 349 | switch (key->type) { | 348 | eventcode = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0, |
| 350 | case KE_KEY: | 349 | 0); |
| 351 | input_report_key(hp_wmi_input_dev, | 350 | key = hp_wmi_get_entry_by_scancode(eventcode); |
| 352 | key->keycode, 1); | 351 | if (key) { |
| 353 | input_sync(hp_wmi_input_dev); | 352 | switch (key->type) { |
| 354 | input_report_key(hp_wmi_input_dev, | 353 | case KE_KEY: |
| 355 | key->keycode, 0); | 354 | input_report_key(hp_wmi_input_dev, |
| 356 | input_sync(hp_wmi_input_dev); | 355 | key->keycode, 1); |
| 357 | break; | 356 | input_sync(hp_wmi_input_dev); |
| 358 | } | 357 | input_report_key(hp_wmi_input_dev, |
| 359 | } else if (eventcode == 0x1) { | 358 | key->keycode, 0); |
| 360 | input_report_switch(hp_wmi_input_dev, SW_DOCK, | ||
| 361 | hp_wmi_dock_state()); | ||
| 362 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, | ||
| 363 | hp_wmi_tablet_state()); | ||
| 364 | input_sync(hp_wmi_input_dev); | 359 | input_sync(hp_wmi_input_dev); |
| 365 | } else if (eventcode == 0x5) { | 360 | break; |
| 366 | if (wifi_rfkill) | 361 | } |
| 367 | rfkill_set_sw_state(wifi_rfkill, | 362 | } else if (eventcode == 0x1) { |
| 368 | hp_wmi_wifi_state()); | 363 | input_report_switch(hp_wmi_input_dev, SW_DOCK, |
| 369 | if (bluetooth_rfkill) | 364 | hp_wmi_dock_state()); |
| 370 | rfkill_set_sw_state(bluetooth_rfkill, | 365 | input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, |
| 371 | hp_wmi_bluetooth_state()); | 366 | hp_wmi_tablet_state()); |
| 372 | if (wwan_rfkill) | 367 | input_sync(hp_wmi_input_dev); |
| 373 | rfkill_set_sw_state(wwan_rfkill, | 368 | } else if (eventcode == 0x5) { |
| 374 | hp_wmi_wwan_state()); | 369 | if (wifi_rfkill) |
| 375 | } else | 370 | rfkill_set_states(wifi_rfkill, |
| 376 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", | 371 | hp_wmi_get_sw_state(HPWMI_WIFI), |
| 377 | eventcode); | 372 | hp_wmi_get_hw_state(HPWMI_WIFI)); |
| 373 | if (bluetooth_rfkill) | ||
| 374 | rfkill_set_states(bluetooth_rfkill, | ||
| 375 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH), | ||
| 376 | hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); | ||
| 377 | if (wwan_rfkill) | ||
| 378 | rfkill_set_states(wwan_rfkill, | ||
| 379 | hp_wmi_get_sw_state(HPWMI_WWAN), | ||
| 380 | hp_wmi_get_hw_state(HPWMI_WWAN)); | ||
| 378 | } else | 381 | } else |
| 379 | printk(KERN_INFO "HP WMI: Unknown response received\n"); | 382 | printk(KERN_INFO "HP WMI: Unknown key pressed - %x\n", |
| 383 | eventcode); | ||
| 380 | } | 384 | } |
| 381 | 385 | ||
| 382 | static int __init hp_wmi_input_setup(void) | 386 | static int __init hp_wmi_input_setup(void) |
| @@ -455,7 +459,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
| 455 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, | 459 | wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev, |
| 456 | RFKILL_TYPE_WLAN, | 460 | RFKILL_TYPE_WLAN, |
| 457 | &hp_wmi_rfkill_ops, | 461 | &hp_wmi_rfkill_ops, |
| 458 | (void *) 0); | 462 | (void *) HPWMI_WIFI); |
| 463 | rfkill_init_sw_state(wifi_rfkill, | ||
| 464 | hp_wmi_get_sw_state(HPWMI_WIFI)); | ||
| 465 | rfkill_set_hw_state(wifi_rfkill, | ||
| 466 | hp_wmi_get_hw_state(HPWMI_WIFI)); | ||
| 459 | err = rfkill_register(wifi_rfkill); | 467 | err = rfkill_register(wifi_rfkill); |
| 460 | if (err) | 468 | if (err) |
| 461 | goto register_wifi_error; | 469 | goto register_wifi_error; |
| @@ -465,7 +473,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
| 465 | bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, | 473 | bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev, |
| 466 | RFKILL_TYPE_BLUETOOTH, | 474 | RFKILL_TYPE_BLUETOOTH, |
| 467 | &hp_wmi_rfkill_ops, | 475 | &hp_wmi_rfkill_ops, |
| 468 | (void *) 1); | 476 | (void *) HPWMI_BLUETOOTH); |
| 477 | rfkill_init_sw_state(bluetooth_rfkill, | ||
| 478 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); | ||
| 479 | rfkill_set_hw_state(bluetooth_rfkill, | ||
| 480 | hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); | ||
| 469 | err = rfkill_register(bluetooth_rfkill); | 481 | err = rfkill_register(bluetooth_rfkill); |
| 470 | if (err) | 482 | if (err) |
| 471 | goto register_bluetooth_error; | 483 | goto register_bluetooth_error; |
| @@ -475,7 +487,11 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
| 475 | wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, | 487 | wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev, |
| 476 | RFKILL_TYPE_WWAN, | 488 | RFKILL_TYPE_WWAN, |
| 477 | &hp_wmi_rfkill_ops, | 489 | &hp_wmi_rfkill_ops, |
| 478 | (void *) 2); | 490 | (void *) HPWMI_WWAN); |
| 491 | rfkill_init_sw_state(wwan_rfkill, | ||
| 492 | hp_wmi_get_sw_state(HPWMI_WWAN)); | ||
| 493 | rfkill_set_hw_state(wwan_rfkill, | ||
| 494 | hp_wmi_get_hw_state(HPWMI_WWAN)); | ||
| 479 | err = rfkill_register(wwan_rfkill); | 495 | err = rfkill_register(wwan_rfkill); |
| 480 | if (err) | 496 | if (err) |
| 481 | goto register_wwan_err; | 497 | goto register_wwan_err; |
| @@ -533,6 +549,19 @@ static int hp_wmi_resume_handler(struct device *device) | |||
| 533 | input_sync(hp_wmi_input_dev); | 549 | input_sync(hp_wmi_input_dev); |
| 534 | } | 550 | } |
| 535 | 551 | ||
| 552 | if (wifi_rfkill) | ||
| 553 | rfkill_set_states(wifi_rfkill, | ||
| 554 | hp_wmi_get_sw_state(HPWMI_WIFI), | ||
| 555 | hp_wmi_get_hw_state(HPWMI_WIFI)); | ||
| 556 | if (bluetooth_rfkill) | ||
| 557 | rfkill_set_states(bluetooth_rfkill, | ||
| 558 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH), | ||
| 559 | hp_wmi_get_hw_state(HPWMI_BLUETOOTH)); | ||
| 560 | if (wwan_rfkill) | ||
| 561 | rfkill_set_states(wwan_rfkill, | ||
| 562 | hp_wmi_get_sw_state(HPWMI_WWAN), | ||
| 563 | hp_wmi_get_hw_state(HPWMI_WWAN)); | ||
| 564 | |||
| 536 | return 0; | 565 | return 0; |
| 537 | } | 566 | } |
| 538 | 567 | ||
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c new file mode 100644 index 000000000000..0c8fe145c4af --- /dev/null +++ b/drivers/platform/x86/msi-wmi.c | |||
| @@ -0,0 +1,293 @@ | |||
| 1 | /* | ||
| 2 | * MSI WMI hotkeys | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Novell <trenn@suse.de> | ||
| 5 | * | ||
| 6 | * Most stuff taken over from hp-wmi | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or modify | ||
| 9 | * it under the terms of the GNU General Public License as published by | ||
| 10 | * the Free Software Foundation; either version 2 of the License, or | ||
| 11 | * (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 21 | */ | ||
| 22 | |||
| 23 | |||
| 24 | #include <linux/kernel.h> | ||
| 25 | #include <linux/input.h> | ||
| 26 | #include <linux/input/sparse-keymap.h> | ||
| 27 | #include <linux/acpi.h> | ||
| 28 | #include <linux/backlight.h> | ||
| 29 | |||
| 30 | MODULE_AUTHOR("Thomas Renninger <trenn@suse.de>"); | ||
| 31 | MODULE_DESCRIPTION("MSI laptop WMI hotkeys driver"); | ||
| 32 | MODULE_LICENSE("GPL"); | ||
| 33 | |||
| 34 | MODULE_ALIAS("wmi:551A1F84-FBDD-4125-91DB-3EA8F44F1D45"); | ||
| 35 | MODULE_ALIAS("wmi:B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2"); | ||
| 36 | |||
| 37 | /* Temporary workaround until the WMI sysfs interface goes in | ||
| 38 | { "svn", DMI_SYS_VENDOR }, | ||
| 39 | { "pn", DMI_PRODUCT_NAME }, | ||
| 40 | { "pvr", DMI_PRODUCT_VERSION }, | ||
| 41 | { "rvn", DMI_BOARD_VENDOR }, | ||
| 42 | { "rn", DMI_BOARD_NAME }, | ||
| 43 | */ | ||
| 44 | |||
| 45 | MODULE_ALIAS("dmi:*:svnMICRO-STARINTERNATIONAL*:pnMS-6638:*"); | ||
| 46 | |||
| 47 | #define DRV_NAME "msi-wmi" | ||
| 48 | #define DRV_PFX DRV_NAME ": " | ||
| 49 | |||
| 50 | #define MSIWMI_BIOS_GUID "551A1F84-FBDD-4125-91DB-3EA8F44F1D45" | ||
| 51 | #define MSIWMI_EVENT_GUID "B6F3EEF2-3D2F-49DC-9DE3-85BCE18C62F2" | ||
| 52 | |||
| 53 | #define dprintk(msg...) pr_debug(DRV_PFX msg) | ||
| 54 | |||
| 55 | #define KEYCODE_BASE 0xD0 | ||
| 56 | #define MSI_WMI_BRIGHTNESSUP KEYCODE_BASE | ||
| 57 | #define MSI_WMI_BRIGHTNESSDOWN (KEYCODE_BASE + 1) | ||
| 58 | #define MSI_WMI_VOLUMEUP (KEYCODE_BASE + 2) | ||
| 59 | #define MSI_WMI_VOLUMEDOWN (KEYCODE_BASE + 3) | ||
| 60 | static struct key_entry msi_wmi_keymap[] = { | ||
| 61 | { KE_KEY, MSI_WMI_BRIGHTNESSUP, {KEY_BRIGHTNESSUP} }, | ||
| 62 | { KE_KEY, MSI_WMI_BRIGHTNESSDOWN, {KEY_BRIGHTNESSDOWN} }, | ||
| 63 | { KE_KEY, MSI_WMI_VOLUMEUP, {KEY_VOLUMEUP} }, | ||
| 64 | { KE_KEY, MSI_WMI_VOLUMEDOWN, {KEY_VOLUMEDOWN} }, | ||
| 65 | { KE_END, 0} | ||
| 66 | }; | ||
| 67 | static ktime_t last_pressed[ARRAY_SIZE(msi_wmi_keymap) - 1]; | ||
| 68 | |||
| 69 | struct backlight_device *backlight; | ||
| 70 | |||
| 71 | static int backlight_map[] = { 0x00, 0x33, 0x66, 0x99, 0xCC, 0xFF }; | ||
| 72 | |||
| 73 | static struct input_dev *msi_wmi_input_dev; | ||
| 74 | |||
| 75 | static int msi_wmi_query_block(int instance, int *ret) | ||
| 76 | { | ||
| 77 | acpi_status status; | ||
| 78 | union acpi_object *obj; | ||
| 79 | |||
| 80 | struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 81 | |||
| 82 | status = wmi_query_block(MSIWMI_BIOS_GUID, instance, &output); | ||
| 83 | |||
| 84 | obj = output.pointer; | ||
| 85 | |||
| 86 | if (!obj || obj->type != ACPI_TYPE_INTEGER) { | ||
| 87 | if (obj) { | ||
| 88 | printk(KERN_ERR DRV_PFX "query block returned object " | ||
| 89 | "type: %d - buffer length:%d\n", obj->type, | ||
| 90 | obj->type == ACPI_TYPE_BUFFER ? | ||
| 91 | obj->buffer.length : 0); | ||
| 92 | } | ||
| 93 | kfree(obj); | ||
| 94 | return -EINVAL; | ||
| 95 | } | ||
| 96 | *ret = obj->integer.value; | ||
| 97 | kfree(obj); | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int msi_wmi_set_block(int instance, int value) | ||
| 102 | { | ||
| 103 | acpi_status status; | ||
| 104 | |||
| 105 | struct acpi_buffer input = { sizeof(int), &value }; | ||
| 106 | |||
| 107 | dprintk("Going to set block of instance: %d - value: %d\n", | ||
| 108 | instance, value); | ||
| 109 | |||
| 110 | status = wmi_set_block(MSIWMI_BIOS_GUID, instance, &input); | ||
| 111 | |||
| 112 | return ACPI_SUCCESS(status) ? 0 : 1; | ||
| 113 | } | ||
| 114 | |||
| 115 | static int bl_get(struct backlight_device *bd) | ||
| 116 | { | ||
| 117 | int level, err, ret; | ||
| 118 | |||
| 119 | /* Instance 1 is "get backlight", cmp with DSDT */ | ||
| 120 | err = msi_wmi_query_block(1, &ret); | ||
| 121 | if (err) { | ||
| 122 | printk(KERN_ERR DRV_PFX "Could not query backlight: %d\n", err); | ||
| 123 | return -EINVAL; | ||
| 124 | } | ||
| 125 | dprintk("Get: Query block returned: %d\n", ret); | ||
| 126 | for (level = 0; level < ARRAY_SIZE(backlight_map); level++) { | ||
| 127 | if (backlight_map[level] == ret) { | ||
| 128 | dprintk("Current backlight level: 0x%X - index: %d\n", | ||
| 129 | backlight_map[level], level); | ||
| 130 | break; | ||
| 131 | } | ||
| 132 | } | ||
| 133 | if (level == ARRAY_SIZE(backlight_map)) { | ||
| 134 | printk(KERN_ERR DRV_PFX "get: Invalid brightness value: 0x%X\n", | ||
| 135 | ret); | ||
| 136 | return -EINVAL; | ||
| 137 | } | ||
| 138 | return level; | ||
| 139 | } | ||
| 140 | |||
| 141 | static int bl_set_status(struct backlight_device *bd) | ||
| 142 | { | ||
| 143 | int bright = bd->props.brightness; | ||
| 144 | if (bright >= ARRAY_SIZE(backlight_map) || bright < 0) | ||
| 145 | return -EINVAL; | ||
| 146 | |||
| 147 | /* Instance 0 is "set backlight" */ | ||
| 148 | return msi_wmi_set_block(0, backlight_map[bright]); | ||
| 149 | } | ||
| 150 | |||
| 151 | static struct backlight_ops msi_backlight_ops = { | ||
| 152 | .get_brightness = bl_get, | ||
| 153 | .update_status = bl_set_status, | ||
| 154 | }; | ||
| 155 | |||
| 156 | static void msi_wmi_notify(u32 value, void *context) | ||
| 157 | { | ||
| 158 | struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 159 | static struct key_entry *key; | ||
| 160 | union acpi_object *obj; | ||
| 161 | ktime_t cur; | ||
| 162 | |||
| 163 | wmi_get_event_data(value, &response); | ||
| 164 | |||
| 165 | obj = (union acpi_object *)response.pointer; | ||
| 166 | |||
| 167 | if (obj && obj->type == ACPI_TYPE_INTEGER) { | ||
| 168 | int eventcode = obj->integer.value; | ||
| 169 | dprintk("Eventcode: 0x%x\n", eventcode); | ||
| 170 | key = sparse_keymap_entry_from_scancode(msi_wmi_input_dev, | ||
| 171 | eventcode); | ||
| 172 | if (key) { | ||
| 173 | ktime_t diff; | ||
| 174 | cur = ktime_get_real(); | ||
| 175 | diff = ktime_sub(cur, last_pressed[key->code - | ||
| 176 | KEYCODE_BASE]); | ||
| 177 | /* Ignore event if the same event happened in a 50 ms | ||
| 178 | timeframe -> Key press may result in 10-20 GPEs */ | ||
| 179 | if (ktime_to_us(diff) < 1000 * 50) { | ||
| 180 | dprintk("Suppressed key event 0x%X - " | ||
| 181 | "Last press was %lld us ago\n", | ||
| 182 | key->code, ktime_to_us(diff)); | ||
| 183 | return; | ||
| 184 | } | ||
| 185 | last_pressed[key->code - KEYCODE_BASE] = cur; | ||
| 186 | |||
| 187 | if (key->type == KE_KEY && | ||
| 188 | /* Brightness is served via acpi video driver */ | ||
| 189 | (!acpi_video_backlight_support() || | ||
| 190 | (key->code != MSI_WMI_BRIGHTNESSUP && | ||
| 191 | key->code != MSI_WMI_BRIGHTNESSDOWN))) { | ||
| 192 | dprintk("Send key: 0x%X - " | ||
| 193 | "Input layer keycode: %d\n", key->code, | ||
| 194 | key->keycode); | ||
| 195 | sparse_keymap_report_entry(msi_wmi_input_dev, | ||
| 196 | key, 1, true); | ||
| 197 | } | ||
| 198 | } else | ||
| 199 | printk(KERN_INFO "Unknown key pressed - %x\n", | ||
| 200 | eventcode); | ||
| 201 | } else | ||
| 202 | printk(KERN_INFO DRV_PFX "Unknown event received\n"); | ||
| 203 | kfree(response.pointer); | ||
| 204 | } | ||
| 205 | |||
| 206 | static int __init msi_wmi_input_setup(void) | ||
| 207 | { | ||
| 208 | int err; | ||
| 209 | |||
| 210 | msi_wmi_input_dev = input_allocate_device(); | ||
| 211 | if (!msi_wmi_input_dev) | ||
| 212 | return -ENOMEM; | ||
| 213 | |||
| 214 | msi_wmi_input_dev->name = "MSI WMI hotkeys"; | ||
| 215 | msi_wmi_input_dev->phys = "wmi/input0"; | ||
| 216 | msi_wmi_input_dev->id.bustype = BUS_HOST; | ||
| 217 | |||
| 218 | err = sparse_keymap_setup(msi_wmi_input_dev, msi_wmi_keymap, NULL); | ||
| 219 | if (err) | ||
| 220 | goto err_free_dev; | ||
| 221 | |||
| 222 | err = input_register_device(msi_wmi_input_dev); | ||
| 223 | |||
| 224 | if (err) | ||
| 225 | goto err_free_keymap; | ||
| 226 | |||
| 227 | memset(last_pressed, 0, sizeof(last_pressed)); | ||
| 228 | |||
| 229 | return 0; | ||
| 230 | |||
| 231 | err_free_keymap: | ||
| 232 | sparse_keymap_free(msi_wmi_input_dev); | ||
| 233 | err_free_dev: | ||
| 234 | input_free_device(msi_wmi_input_dev); | ||
| 235 | return err; | ||
| 236 | } | ||
| 237 | |||
| 238 | static int __init msi_wmi_init(void) | ||
| 239 | { | ||
| 240 | int err; | ||
| 241 | |||
| 242 | if (!wmi_has_guid(MSIWMI_EVENT_GUID)) { | ||
| 243 | printk(KERN_ERR | ||
| 244 | "This machine doesn't have MSI-hotkeys through WMI\n"); | ||
| 245 | return -ENODEV; | ||
| 246 | } | ||
| 247 | err = wmi_install_notify_handler(MSIWMI_EVENT_GUID, | ||
| 248 | msi_wmi_notify, NULL); | ||
| 249 | if (err) | ||
| 250 | return -EINVAL; | ||
| 251 | |||
| 252 | err = msi_wmi_input_setup(); | ||
| 253 | if (err) | ||
| 254 | goto err_uninstall_notifier; | ||
| 255 | |||
| 256 | if (!acpi_video_backlight_support()) { | ||
| 257 | backlight = backlight_device_register(DRV_NAME, | ||
| 258 | NULL, NULL, &msi_backlight_ops); | ||
| 259 | if (IS_ERR(backlight)) | ||
| 260 | goto err_free_input; | ||
| 261 | |||
| 262 | backlight->props.max_brightness = ARRAY_SIZE(backlight_map) - 1; | ||
| 263 | err = bl_get(NULL); | ||
| 264 | if (err < 0) | ||
| 265 | goto err_free_backlight; | ||
| 266 | |||
| 267 | backlight->props.brightness = err; | ||
| 268 | } | ||
| 269 | dprintk("Event handler installed\n"); | ||
| 270 | |||
| 271 | return 0; | ||
| 272 | |||
| 273 | err_free_backlight: | ||
| 274 | backlight_device_unregister(backlight); | ||
| 275 | err_free_input: | ||
| 276 | input_unregister_device(msi_wmi_input_dev); | ||
| 277 | err_uninstall_notifier: | ||
| 278 | wmi_remove_notify_handler(MSIWMI_EVENT_GUID); | ||
| 279 | return err; | ||
| 280 | } | ||
| 281 | |||
| 282 | static void __exit msi_wmi_exit(void) | ||
| 283 | { | ||
| 284 | if (wmi_has_guid(MSIWMI_EVENT_GUID)) { | ||
| 285 | wmi_remove_notify_handler(MSIWMI_EVENT_GUID); | ||
| 286 | sparse_keymap_free(msi_wmi_input_dev); | ||
| 287 | input_unregister_device(msi_wmi_input_dev); | ||
| 288 | backlight_device_unregister(backlight); | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | module_init(msi_wmi_init); | ||
| 293 | module_exit(msi_wmi_exit); | ||
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cf61d6a8ef6f..448c8aeb166b 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
| @@ -21,8 +21,8 @@ | |||
| 21 | * 02110-1301, USA. | 21 | * 02110-1301, USA. |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #define TPACPI_VERSION "0.23" | 24 | #define TPACPI_VERSION "0.24" |
| 25 | #define TPACPI_SYSFS_VERSION 0x020500 | 25 | #define TPACPI_SYSFS_VERSION 0x020700 |
| 26 | 26 | ||
| 27 | /* | 27 | /* |
| 28 | * Changelog: | 28 | * Changelog: |
| @@ -61,6 +61,7 @@ | |||
| 61 | 61 | ||
| 62 | #include <linux/nvram.h> | 62 | #include <linux/nvram.h> |
| 63 | #include <linux/proc_fs.h> | 63 | #include <linux/proc_fs.h> |
| 64 | #include <linux/seq_file.h> | ||
| 64 | #include <linux/sysfs.h> | 65 | #include <linux/sysfs.h> |
| 65 | #include <linux/backlight.h> | 66 | #include <linux/backlight.h> |
| 66 | #include <linux/fb.h> | 67 | #include <linux/fb.h> |
| @@ -76,6 +77,10 @@ | |||
| 76 | #include <linux/jiffies.h> | 77 | #include <linux/jiffies.h> |
| 77 | #include <linux/workqueue.h> | 78 | #include <linux/workqueue.h> |
| 78 | 79 | ||
| 80 | #include <sound/core.h> | ||
| 81 | #include <sound/control.h> | ||
| 82 | #include <sound/initval.h> | ||
| 83 | |||
| 79 | #include <acpi/acpi_drivers.h> | 84 | #include <acpi/acpi_drivers.h> |
| 80 | 85 | ||
| 81 | #include <linux/pci_ids.h> | 86 | #include <linux/pci_ids.h> |
| @@ -231,6 +236,7 @@ enum tpacpi_hkey_event_t { | |||
| 231 | #define TPACPI_DBG_HKEY 0x0008 | 236 | #define TPACPI_DBG_HKEY 0x0008 |
| 232 | #define TPACPI_DBG_FAN 0x0010 | 237 | #define TPACPI_DBG_FAN 0x0010 |
| 233 | #define TPACPI_DBG_BRGHT 0x0020 | 238 | #define TPACPI_DBG_BRGHT 0x0020 |
| 239 | #define TPACPI_DBG_MIXER 0x0040 | ||
| 234 | 240 | ||
| 235 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") | 241 | #define onoff(status, bit) ((status) & (1 << (bit)) ? "on" : "off") |
| 236 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") | 242 | #define enabled(status, bit) ((status) & (1 << (bit)) ? "enabled" : "disabled") |
| @@ -256,7 +262,7 @@ struct tp_acpi_drv_struct { | |||
| 256 | struct ibm_struct { | 262 | struct ibm_struct { |
| 257 | char *name; | 263 | char *name; |
| 258 | 264 | ||
| 259 | int (*read) (char *); | 265 | int (*read) (struct seq_file *); |
| 260 | int (*write) (char *); | 266 | int (*write) (char *); |
| 261 | void (*exit) (void); | 267 | void (*exit) (void); |
| 262 | void (*resume) (void); | 268 | void (*resume) (void); |
| @@ -298,6 +304,7 @@ static struct { | |||
| 298 | u32 fan_ctrl_status_undef:1; | 304 | u32 fan_ctrl_status_undef:1; |
| 299 | u32 second_fan:1; | 305 | u32 second_fan:1; |
| 300 | u32 beep_needs_two_args:1; | 306 | u32 beep_needs_two_args:1; |
| 307 | u32 mixer_no_level_control:1; | ||
| 301 | u32 input_device_registered:1; | 308 | u32 input_device_registered:1; |
| 302 | u32 platform_drv_registered:1; | 309 | u32 platform_drv_registered:1; |
| 303 | u32 platform_drv_attrs_registered:1; | 310 | u32 platform_drv_attrs_registered:1; |
| @@ -309,6 +316,7 @@ static struct { | |||
| 309 | 316 | ||
| 310 | static struct { | 317 | static struct { |
| 311 | u16 hotkey_mask_ff:1; | 318 | u16 hotkey_mask_ff:1; |
| 319 | u16 volume_ctrl_forbidden:1; | ||
| 312 | } tp_warned; | 320 | } tp_warned; |
| 313 | 321 | ||
| 314 | struct thinkpad_id_data { | 322 | struct thinkpad_id_data { |
| @@ -425,6 +433,12 @@ static void tpacpi_log_usertask(const char * const what) | |||
| 425 | .ec = TPACPI_MATCH_ANY, \ | 433 | .ec = TPACPI_MATCH_ANY, \ |
| 426 | .quirks = (__quirk) } | 434 | .quirks = (__quirk) } |
| 427 | 435 | ||
| 436 | #define TPACPI_QEC_LNV(__id1, __id2, __quirk) \ | ||
| 437 | { .vendor = PCI_VENDOR_ID_LENOVO, \ | ||
| 438 | .bios = TPACPI_MATCH_ANY, \ | ||
| 439 | .ec = TPID(__id1, __id2), \ | ||
| 440 | .quirks = (__quirk) } | ||
| 441 | |||
| 428 | struct tpacpi_quirk { | 442 | struct tpacpi_quirk { |
| 429 | unsigned int vendor; | 443 | unsigned int vendor; |
| 430 | u16 bios; | 444 | u16 bios; |
| @@ -776,36 +790,25 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm) | |||
| 776 | **************************************************************************** | 790 | **************************************************************************** |
| 777 | ****************************************************************************/ | 791 | ****************************************************************************/ |
| 778 | 792 | ||
| 779 | static int dispatch_procfs_read(char *page, char **start, off_t off, | 793 | static int dispatch_proc_show(struct seq_file *m, void *v) |
| 780 | int count, int *eof, void *data) | ||
| 781 | { | 794 | { |
| 782 | struct ibm_struct *ibm = data; | 795 | struct ibm_struct *ibm = m->private; |
| 783 | int len; | ||
| 784 | 796 | ||
| 785 | if (!ibm || !ibm->read) | 797 | if (!ibm || !ibm->read) |
| 786 | return -EINVAL; | 798 | return -EINVAL; |
| 799 | return ibm->read(m); | ||
| 800 | } | ||
| 787 | 801 | ||
| 788 | len = ibm->read(page); | 802 | static int dispatch_proc_open(struct inode *inode, struct file *file) |
| 789 | if (len < 0) | 803 | { |
| 790 | return len; | 804 | return single_open(file, dispatch_proc_show, PDE(inode)->data); |
| 791 | |||
| 792 | if (len <= off + count) | ||
| 793 | *eof = 1; | ||
| 794 | *start = page + off; | ||
| 795 | len -= off; | ||
| 796 | if (len > count) | ||
| 797 | len = count; | ||
| 798 | if (len < 0) | ||
| 799 | len = 0; | ||
| 800 | |||
| 801 | return len; | ||
| 802 | } | 805 | } |
| 803 | 806 | ||
| 804 | static int dispatch_procfs_write(struct file *file, | 807 | static ssize_t dispatch_proc_write(struct file *file, |
| 805 | const char __user *userbuf, | 808 | const char __user *userbuf, |
| 806 | unsigned long count, void *data) | 809 | size_t count, loff_t *pos) |
| 807 | { | 810 | { |
| 808 | struct ibm_struct *ibm = data; | 811 | struct ibm_struct *ibm = PDE(file->f_path.dentry->d_inode)->data; |
| 809 | char *kernbuf; | 812 | char *kernbuf; |
| 810 | int ret; | 813 | int ret; |
| 811 | 814 | ||
| @@ -834,6 +837,15 @@ static int dispatch_procfs_write(struct file *file, | |||
| 834 | return ret; | 837 | return ret; |
| 835 | } | 838 | } |
| 836 | 839 | ||
| 840 | static const struct file_operations dispatch_proc_fops = { | ||
| 841 | .owner = THIS_MODULE, | ||
| 842 | .open = dispatch_proc_open, | ||
| 843 | .read = seq_read, | ||
| 844 | .llseek = seq_lseek, | ||
| 845 | .release = single_release, | ||
| 846 | .write = dispatch_proc_write, | ||
| 847 | }; | ||
| 848 | |||
| 837 | static char *next_cmd(char **cmds) | 849 | static char *next_cmd(char **cmds) |
| 838 | { | 850 | { |
| 839 | char *start = *cmds; | 851 | char *start = *cmds; |
| @@ -1261,6 +1273,7 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | |||
| 1261 | struct tpacpi_rfk *atp_rfk; | 1273 | struct tpacpi_rfk *atp_rfk; |
| 1262 | int res; | 1274 | int res; |
| 1263 | bool sw_state = false; | 1275 | bool sw_state = false; |
| 1276 | bool hw_state; | ||
| 1264 | int sw_status; | 1277 | int sw_status; |
| 1265 | 1278 | ||
| 1266 | BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); | 1279 | BUG_ON(id >= TPACPI_RFK_SW_MAX || tpacpi_rfkill_switches[id]); |
| @@ -1295,7 +1308,8 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | |||
| 1295 | rfkill_init_sw_state(atp_rfk->rfkill, sw_state); | 1308 | rfkill_init_sw_state(atp_rfk->rfkill, sw_state); |
| 1296 | } | 1309 | } |
| 1297 | } | 1310 | } |
| 1298 | rfkill_set_hw_state(atp_rfk->rfkill, tpacpi_rfk_check_hwblock_state()); | 1311 | hw_state = tpacpi_rfk_check_hwblock_state(); |
| 1312 | rfkill_set_hw_state(atp_rfk->rfkill, hw_state); | ||
| 1299 | 1313 | ||
| 1300 | res = rfkill_register(atp_rfk->rfkill); | 1314 | res = rfkill_register(atp_rfk->rfkill); |
| 1301 | if (res < 0) { | 1315 | if (res < 0) { |
| @@ -1308,6 +1322,9 @@ static int __init tpacpi_new_rfkill(const enum tpacpi_rfk_id id, | |||
| 1308 | } | 1322 | } |
| 1309 | 1323 | ||
| 1310 | tpacpi_rfkill_switches[id] = atp_rfk; | 1324 | tpacpi_rfkill_switches[id] = atp_rfk; |
| 1325 | |||
| 1326 | printk(TPACPI_INFO "rfkill switch %s: radio is %sblocked\n", | ||
| 1327 | name, (sw_state || hw_state) ? "" : "un"); | ||
| 1311 | return 0; | 1328 | return 0; |
| 1312 | } | 1329 | } |
| 1313 | 1330 | ||
| @@ -1380,12 +1397,10 @@ static ssize_t tpacpi_rfk_sysfs_enable_store(const enum tpacpi_rfk_id id, | |||
| 1380 | } | 1397 | } |
| 1381 | 1398 | ||
| 1382 | /* procfs -------------------------------------------------------------- */ | 1399 | /* procfs -------------------------------------------------------------- */ |
| 1383 | static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) | 1400 | static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, struct seq_file *m) |
| 1384 | { | 1401 | { |
| 1385 | int len = 0; | ||
| 1386 | |||
| 1387 | if (id >= TPACPI_RFK_SW_MAX) | 1402 | if (id >= TPACPI_RFK_SW_MAX) |
| 1388 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 1403 | seq_printf(m, "status:\t\tnot supported\n"); |
| 1389 | else { | 1404 | else { |
| 1390 | int status; | 1405 | int status; |
| 1391 | 1406 | ||
| @@ -1399,13 +1414,13 @@ static int tpacpi_rfk_procfs_read(const enum tpacpi_rfk_id id, char *p) | |||
| 1399 | return status; | 1414 | return status; |
| 1400 | } | 1415 | } |
| 1401 | 1416 | ||
| 1402 | len += sprintf(p + len, "status:\t\t%s\n", | 1417 | seq_printf(m, "status:\t\t%s\n", |
| 1403 | (status == TPACPI_RFK_RADIO_ON) ? | 1418 | (status == TPACPI_RFK_RADIO_ON) ? |
| 1404 | "enabled" : "disabled"); | 1419 | "enabled" : "disabled"); |
| 1405 | len += sprintf(p + len, "commands:\tenable, disable\n"); | 1420 | seq_printf(m, "commands:\tenable, disable\n"); |
| 1406 | } | 1421 | } |
| 1407 | 1422 | ||
| 1408 | return len; | 1423 | return 0; |
| 1409 | } | 1424 | } |
| 1410 | 1425 | ||
| 1411 | static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) | 1426 | static int tpacpi_rfk_procfs_write(const enum tpacpi_rfk_id id, char *buf) |
| @@ -1776,7 +1791,7 @@ static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = { | |||
| 1776 | 1791 | ||
| 1777 | TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ | 1792 | TPV_QL1('7', '9', 'E', '3', '5', '0'), /* T60/p */ |
| 1778 | TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ | 1793 | TPV_QL1('7', 'C', 'D', '2', '2', '2'), /* R60, R60i */ |
| 1779 | TPV_QL0('7', 'E', 'D', '0'), /* R60e, R60i */ | 1794 | TPV_QL1('7', 'E', 'D', '0', '1', '5'), /* R60e, R60i */ |
| 1780 | 1795 | ||
| 1781 | /* BIOS FW BIOS VERS EC FW EC VERS */ | 1796 | /* BIOS FW BIOS VERS EC FW EC VERS */ |
| 1782 | TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ | 1797 | TPV_QI2('1', 'W', '9', '0', '1', 'V', '2', '8'), /* R50e (1) */ |
| @@ -1792,8 +1807,8 @@ static const struct tpacpi_quirk tpacpi_bios_version_qtable[] __initconst = { | |||
| 1792 | TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ | 1807 | TPV_QI1('7', '4', '6', '4', '2', '7'), /* X41 (0) */ |
| 1793 | TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ | 1808 | TPV_QI1('7', '5', '6', '0', '2', '0'), /* X41t (0) */ |
| 1794 | 1809 | ||
| 1795 | TPV_QL0('7', 'B', 'D', '7'), /* X60/s */ | 1810 | TPV_QL1('7', 'B', 'D', '7', '4', '0'), /* X60/s */ |
| 1796 | TPV_QL0('7', 'J', '3', '0'), /* X60t */ | 1811 | TPV_QL1('7', 'J', '3', '0', '1', '3'), /* X60t */ |
| 1797 | 1812 | ||
| 1798 | /* (0) - older versions lack DMI EC fw string and functionality */ | 1813 | /* (0) - older versions lack DMI EC fw string and functionality */ |
| 1799 | /* (1) - older versions known to lack functionality */ | 1814 | /* (1) - older versions known to lack functionality */ |
| @@ -1883,14 +1898,11 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm) | |||
| 1883 | return 0; | 1898 | return 0; |
| 1884 | } | 1899 | } |
| 1885 | 1900 | ||
| 1886 | static int thinkpad_acpi_driver_read(char *p) | 1901 | static int thinkpad_acpi_driver_read(struct seq_file *m) |
| 1887 | { | 1902 | { |
| 1888 | int len = 0; | 1903 | seq_printf(m, "driver:\t\t%s\n", TPACPI_DESC); |
| 1889 | 1904 | seq_printf(m, "version:\t%s\n", TPACPI_VERSION); | |
| 1890 | len += sprintf(p + len, "driver:\t\t%s\n", TPACPI_DESC); | 1905 | return 0; |
| 1891 | len += sprintf(p + len, "version:\t%s\n", TPACPI_VERSION); | ||
| 1892 | |||
| 1893 | return len; | ||
| 1894 | } | 1906 | } |
| 1895 | 1907 | ||
| 1896 | static struct ibm_struct thinkpad_acpi_driver_data = { | 1908 | static struct ibm_struct thinkpad_acpi_driver_data = { |
| @@ -2186,7 +2198,8 @@ static int hotkey_mask_set(u32 mask) | |||
| 2186 | fwmask, hotkey_acpi_mask); | 2198 | fwmask, hotkey_acpi_mask); |
| 2187 | } | 2199 | } |
| 2188 | 2200 | ||
| 2189 | hotkey_mask_warn_incomplete_mask(); | 2201 | if (tpacpi_lifecycle != TPACPI_LIFE_EXITING) |
| 2202 | hotkey_mask_warn_incomplete_mask(); | ||
| 2190 | 2203 | ||
| 2191 | return rc; | 2204 | return rc; |
| 2192 | } | 2205 | } |
| @@ -3182,6 +3195,8 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3182 | int res, i; | 3195 | int res, i; |
| 3183 | int status; | 3196 | int status; |
| 3184 | int hkeyv; | 3197 | int hkeyv; |
| 3198 | bool radiosw_state = false; | ||
| 3199 | bool tabletsw_state = false; | ||
| 3185 | 3200 | ||
| 3186 | unsigned long quirks; | 3201 | unsigned long quirks; |
| 3187 | 3202 | ||
| @@ -3287,6 +3302,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3287 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 3302 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
| 3288 | if (dbg_wlswemul) { | 3303 | if (dbg_wlswemul) { |
| 3289 | tp_features.hotkey_wlsw = 1; | 3304 | tp_features.hotkey_wlsw = 1; |
| 3305 | radiosw_state = !!tpacpi_wlsw_emulstate; | ||
| 3290 | printk(TPACPI_INFO | 3306 | printk(TPACPI_INFO |
| 3291 | "radio switch emulation enabled\n"); | 3307 | "radio switch emulation enabled\n"); |
| 3292 | } else | 3308 | } else |
| @@ -3294,6 +3310,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3294 | /* Not all thinkpads have a hardware radio switch */ | 3310 | /* Not all thinkpads have a hardware radio switch */ |
| 3295 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { | 3311 | if (acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { |
| 3296 | tp_features.hotkey_wlsw = 1; | 3312 | tp_features.hotkey_wlsw = 1; |
| 3313 | radiosw_state = !!status; | ||
| 3297 | printk(TPACPI_INFO | 3314 | printk(TPACPI_INFO |
| 3298 | "radio switch found; radios are %s\n", | 3315 | "radio switch found; radios are %s\n", |
| 3299 | enabled(status, 0)); | 3316 | enabled(status, 0)); |
| @@ -3305,11 +3322,11 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3305 | /* For X41t, X60t, X61t Tablets... */ | 3322 | /* For X41t, X60t, X61t Tablets... */ |
| 3306 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { | 3323 | if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { |
| 3307 | tp_features.hotkey_tablet = 1; | 3324 | tp_features.hotkey_tablet = 1; |
| 3325 | tabletsw_state = !!(status & TP_HOTKEY_TABLET_MASK); | ||
| 3308 | printk(TPACPI_INFO | 3326 | printk(TPACPI_INFO |
| 3309 | "possible tablet mode switch found; " | 3327 | "possible tablet mode switch found; " |
| 3310 | "ThinkPad in %s mode\n", | 3328 | "ThinkPad in %s mode\n", |
| 3311 | (status & TP_HOTKEY_TABLET_MASK)? | 3329 | (tabletsw_state) ? "tablet" : "laptop"); |
| 3312 | "tablet" : "laptop"); | ||
| 3313 | res = add_to_attr_set(hotkey_dev_attributes, | 3330 | res = add_to_attr_set(hotkey_dev_attributes, |
| 3314 | &dev_attr_hotkey_tablet_mode.attr); | 3331 | &dev_attr_hotkey_tablet_mode.attr); |
| 3315 | } | 3332 | } |
| @@ -3344,16 +3361,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3344 | TPACPI_HOTKEY_MAP_SIZE); | 3361 | TPACPI_HOTKEY_MAP_SIZE); |
| 3345 | } | 3362 | } |
| 3346 | 3363 | ||
| 3347 | set_bit(EV_KEY, tpacpi_inputdev->evbit); | 3364 | input_set_capability(tpacpi_inputdev, EV_MSC, MSC_SCAN); |
| 3348 | set_bit(EV_MSC, tpacpi_inputdev->evbit); | ||
| 3349 | set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); | ||
| 3350 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; | 3365 | tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; |
| 3351 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; | 3366 | tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; |
| 3352 | tpacpi_inputdev->keycode = hotkey_keycode_map; | 3367 | tpacpi_inputdev->keycode = hotkey_keycode_map; |
| 3353 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { | 3368 | for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { |
| 3354 | if (hotkey_keycode_map[i] != KEY_RESERVED) { | 3369 | if (hotkey_keycode_map[i] != KEY_RESERVED) { |
| 3355 | set_bit(hotkey_keycode_map[i], | 3370 | input_set_capability(tpacpi_inputdev, EV_KEY, |
| 3356 | tpacpi_inputdev->keybit); | 3371 | hotkey_keycode_map[i]); |
| 3357 | } else { | 3372 | } else { |
| 3358 | if (i < sizeof(hotkey_reserved_mask)*8) | 3373 | if (i < sizeof(hotkey_reserved_mask)*8) |
| 3359 | hotkey_reserved_mask |= 1 << i; | 3374 | hotkey_reserved_mask |= 1 << i; |
| @@ -3361,12 +3376,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3361 | } | 3376 | } |
| 3362 | 3377 | ||
| 3363 | if (tp_features.hotkey_wlsw) { | 3378 | if (tp_features.hotkey_wlsw) { |
| 3364 | set_bit(EV_SW, tpacpi_inputdev->evbit); | 3379 | input_set_capability(tpacpi_inputdev, EV_SW, SW_RFKILL_ALL); |
| 3365 | set_bit(SW_RFKILL_ALL, tpacpi_inputdev->swbit); | 3380 | input_report_switch(tpacpi_inputdev, |
| 3381 | SW_RFKILL_ALL, radiosw_state); | ||
| 3366 | } | 3382 | } |
| 3367 | if (tp_features.hotkey_tablet) { | 3383 | if (tp_features.hotkey_tablet) { |
| 3368 | set_bit(EV_SW, tpacpi_inputdev->evbit); | 3384 | input_set_capability(tpacpi_inputdev, EV_SW, SW_TABLET_MODE); |
| 3369 | set_bit(SW_TABLET_MODE, tpacpi_inputdev->swbit); | 3385 | input_report_switch(tpacpi_inputdev, |
| 3386 | SW_TABLET_MODE, tabletsw_state); | ||
| 3370 | } | 3387 | } |
| 3371 | 3388 | ||
| 3372 | /* Do not issue duplicate brightness change events to | 3389 | /* Do not issue duplicate brightness change events to |
| @@ -3433,8 +3450,6 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) | |||
| 3433 | tpacpi_inputdev->close = &hotkey_inputdev_close; | 3450 | tpacpi_inputdev->close = &hotkey_inputdev_close; |
| 3434 | 3451 | ||
| 3435 | hotkey_poll_setup_safe(true); | 3452 | hotkey_poll_setup_safe(true); |
| 3436 | tpacpi_send_radiosw_update(); | ||
| 3437 | tpacpi_input_send_tabletsw(); | ||
| 3438 | 3453 | ||
| 3439 | return 0; | 3454 | return 0; |
| 3440 | 3455 | ||
| @@ -3542,49 +3557,57 @@ static bool hotkey_notify_usrevent(const u32 hkey, | |||
| 3542 | } | 3557 | } |
| 3543 | } | 3558 | } |
| 3544 | 3559 | ||
| 3560 | static void thermal_dump_all_sensors(void); | ||
| 3561 | |||
| 3545 | static bool hotkey_notify_thermal(const u32 hkey, | 3562 | static bool hotkey_notify_thermal(const u32 hkey, |
| 3546 | bool *send_acpi_ev, | 3563 | bool *send_acpi_ev, |
| 3547 | bool *ignore_acpi_ev) | 3564 | bool *ignore_acpi_ev) |
| 3548 | { | 3565 | { |
| 3566 | bool known = true; | ||
| 3567 | |||
| 3549 | /* 0x6000-0x6FFF: thermal alarms */ | 3568 | /* 0x6000-0x6FFF: thermal alarms */ |
| 3550 | *send_acpi_ev = true; | 3569 | *send_acpi_ev = true; |
| 3551 | *ignore_acpi_ev = false; | 3570 | *ignore_acpi_ev = false; |
| 3552 | 3571 | ||
| 3553 | switch (hkey) { | 3572 | switch (hkey) { |
| 3573 | case TP_HKEY_EV_THM_TABLE_CHANGED: | ||
| 3574 | printk(TPACPI_INFO | ||
| 3575 | "EC reports that Thermal Table has changed\n"); | ||
| 3576 | /* recommended action: do nothing, we don't have | ||
| 3577 | * Lenovo ATM information */ | ||
| 3578 | return true; | ||
| 3554 | case TP_HKEY_EV_ALARM_BAT_HOT: | 3579 | case TP_HKEY_EV_ALARM_BAT_HOT: |
| 3555 | printk(TPACPI_CRIT | 3580 | printk(TPACPI_CRIT |
| 3556 | "THERMAL ALARM: battery is too hot!\n"); | 3581 | "THERMAL ALARM: battery is too hot!\n"); |
| 3557 | /* recommended action: warn user through gui */ | 3582 | /* recommended action: warn user through gui */ |
| 3558 | return true; | 3583 | break; |
| 3559 | case TP_HKEY_EV_ALARM_BAT_XHOT: | 3584 | case TP_HKEY_EV_ALARM_BAT_XHOT: |
| 3560 | printk(TPACPI_ALERT | 3585 | printk(TPACPI_ALERT |
| 3561 | "THERMAL EMERGENCY: battery is extremely hot!\n"); | 3586 | "THERMAL EMERGENCY: battery is extremely hot!\n"); |
| 3562 | /* recommended action: immediate sleep/hibernate */ | 3587 | /* recommended action: immediate sleep/hibernate */ |
| 3563 | return true; | 3588 | break; |
| 3564 | case TP_HKEY_EV_ALARM_SENSOR_HOT: | 3589 | case TP_HKEY_EV_ALARM_SENSOR_HOT: |
| 3565 | printk(TPACPI_CRIT | 3590 | printk(TPACPI_CRIT |
| 3566 | "THERMAL ALARM: " | 3591 | "THERMAL ALARM: " |
| 3567 | "a sensor reports something is too hot!\n"); | 3592 | "a sensor reports something is too hot!\n"); |
| 3568 | /* recommended action: warn user through gui, that */ | 3593 | /* recommended action: warn user through gui, that */ |
| 3569 | /* some internal component is too hot */ | 3594 | /* some internal component is too hot */ |
| 3570 | return true; | 3595 | break; |
| 3571 | case TP_HKEY_EV_ALARM_SENSOR_XHOT: | 3596 | case TP_HKEY_EV_ALARM_SENSOR_XHOT: |
| 3572 | printk(TPACPI_ALERT | 3597 | printk(TPACPI_ALERT |
| 3573 | "THERMAL EMERGENCY: " | 3598 | "THERMAL EMERGENCY: " |
| 3574 | "a sensor reports something is extremely hot!\n"); | 3599 | "a sensor reports something is extremely hot!\n"); |
| 3575 | /* recommended action: immediate sleep/hibernate */ | 3600 | /* recommended action: immediate sleep/hibernate */ |
| 3576 | return true; | 3601 | break; |
| 3577 | case TP_HKEY_EV_THM_TABLE_CHANGED: | ||
| 3578 | printk(TPACPI_INFO | ||
| 3579 | "EC reports that Thermal Table has changed\n"); | ||
| 3580 | /* recommended action: do nothing, we don't have | ||
| 3581 | * Lenovo ATM information */ | ||
| 3582 | return true; | ||
| 3583 | default: | 3602 | default: |
| 3584 | printk(TPACPI_ALERT | 3603 | printk(TPACPI_ALERT |
| 3585 | "THERMAL ALERT: unknown thermal alarm received\n"); | 3604 | "THERMAL ALERT: unknown thermal alarm received\n"); |
| 3586 | return false; | 3605 | known = false; |
| 3587 | } | 3606 | } |
| 3607 | |||
| 3608 | thermal_dump_all_sensors(); | ||
| 3609 | |||
| 3610 | return known; | ||
| 3588 | } | 3611 | } |
| 3589 | 3612 | ||
| 3590 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) | 3613 | static void hotkey_notify(struct ibm_struct *ibm, u32 event) |
| @@ -3727,14 +3750,13 @@ static void hotkey_resume(void) | |||
| 3727 | } | 3750 | } |
| 3728 | 3751 | ||
| 3729 | /* procfs -------------------------------------------------------------- */ | 3752 | /* procfs -------------------------------------------------------------- */ |
| 3730 | static int hotkey_read(char *p) | 3753 | static int hotkey_read(struct seq_file *m) |
| 3731 | { | 3754 | { |
| 3732 | int res, status; | 3755 | int res, status; |
| 3733 | int len = 0; | ||
| 3734 | 3756 | ||
| 3735 | if (!tp_features.hotkey) { | 3757 | if (!tp_features.hotkey) { |
| 3736 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 3758 | seq_printf(m, "status:\t\tnot supported\n"); |
| 3737 | return len; | 3759 | return 0; |
| 3738 | } | 3760 | } |
| 3739 | 3761 | ||
| 3740 | if (mutex_lock_killable(&hotkey_mutex)) | 3762 | if (mutex_lock_killable(&hotkey_mutex)) |
| @@ -3746,17 +3768,16 @@ static int hotkey_read(char *p) | |||
| 3746 | if (res) | 3768 | if (res) |
| 3747 | return res; | 3769 | return res; |
| 3748 | 3770 | ||
| 3749 | len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); | 3771 | seq_printf(m, "status:\t\t%s\n", enabled(status, 0)); |
| 3750 | if (hotkey_all_mask) { | 3772 | if (hotkey_all_mask) { |
| 3751 | len += sprintf(p + len, "mask:\t\t0x%08x\n", hotkey_user_mask); | 3773 | seq_printf(m, "mask:\t\t0x%08x\n", hotkey_user_mask); |
| 3752 | len += sprintf(p + len, | 3774 | seq_printf(m, "commands:\tenable, disable, reset, <mask>\n"); |
| 3753 | "commands:\tenable, disable, reset, <mask>\n"); | ||
| 3754 | } else { | 3775 | } else { |
| 3755 | len += sprintf(p + len, "mask:\t\tnot supported\n"); | 3776 | seq_printf(m, "mask:\t\tnot supported\n"); |
| 3756 | len += sprintf(p + len, "commands:\tenable, disable, reset\n"); | 3777 | seq_printf(m, "commands:\tenable, disable, reset\n"); |
| 3757 | } | 3778 | } |
| 3758 | 3779 | ||
| 3759 | return len; | 3780 | return 0; |
| 3760 | } | 3781 | } |
| 3761 | 3782 | ||
| 3762 | static void hotkey_enabledisable_warn(bool enable) | 3783 | static void hotkey_enabledisable_warn(bool enable) |
| @@ -3863,15 +3884,6 @@ enum { | |||
| 3863 | 3884 | ||
| 3864 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" | 3885 | #define TPACPI_RFK_BLUETOOTH_SW_NAME "tpacpi_bluetooth_sw" |
| 3865 | 3886 | ||
| 3866 | static void bluetooth_suspend(pm_message_t state) | ||
| 3867 | { | ||
| 3868 | /* Try to make sure radio will resume powered off */ | ||
| 3869 | if (!acpi_evalf(NULL, NULL, "\\BLTH", "vd", | ||
| 3870 | TP_ACPI_BLTH_PWR_OFF_ON_RESUME)) | ||
| 3871 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 3872 | "bluetooth power down on resume request failed\n"); | ||
| 3873 | } | ||
| 3874 | |||
| 3875 | static int bluetooth_get_status(void) | 3887 | static int bluetooth_get_status(void) |
| 3876 | { | 3888 | { |
| 3877 | int status; | 3889 | int status; |
| @@ -3905,10 +3917,9 @@ static int bluetooth_set_status(enum tpacpi_rfkill_state state) | |||
| 3905 | #endif | 3917 | #endif |
| 3906 | 3918 | ||
| 3907 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ | 3919 | /* We make sure to keep TP_ACPI_BLUETOOTH_RESUMECTRL off */ |
| 3920 | status = TP_ACPI_BLUETOOTH_RESUMECTRL; | ||
| 3908 | if (state == TPACPI_RFK_RADIO_ON) | 3921 | if (state == TPACPI_RFK_RADIO_ON) |
| 3909 | status = TP_ACPI_BLUETOOTH_RADIOSSW; | 3922 | status |= TP_ACPI_BLUETOOTH_RADIOSSW; |
| 3910 | else | ||
| 3911 | status = 0; | ||
| 3912 | 3923 | ||
| 3913 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) | 3924 | if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) |
| 3914 | return -EIO; | 3925 | return -EIO; |
| @@ -4032,9 +4043,9 @@ static int __init bluetooth_init(struct ibm_init_struct *iibm) | |||
| 4032 | } | 4043 | } |
| 4033 | 4044 | ||
| 4034 | /* procfs -------------------------------------------------------------- */ | 4045 | /* procfs -------------------------------------------------------------- */ |
| 4035 | static int bluetooth_read(char *p) | 4046 | static int bluetooth_read(struct seq_file *m) |
| 4036 | { | 4047 | { |
| 4037 | return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, p); | 4048 | return tpacpi_rfk_procfs_read(TPACPI_RFK_BLUETOOTH_SW_ID, m); |
| 4038 | } | 4049 | } |
| 4039 | 4050 | ||
| 4040 | static int bluetooth_write(char *buf) | 4051 | static int bluetooth_write(char *buf) |
| @@ -4047,7 +4058,6 @@ static struct ibm_struct bluetooth_driver_data = { | |||
| 4047 | .read = bluetooth_read, | 4058 | .read = bluetooth_read, |
| 4048 | .write = bluetooth_write, | 4059 | .write = bluetooth_write, |
| 4049 | .exit = bluetooth_exit, | 4060 | .exit = bluetooth_exit, |
| 4050 | .suspend = bluetooth_suspend, | ||
| 4051 | .shutdown = bluetooth_shutdown, | 4061 | .shutdown = bluetooth_shutdown, |
| 4052 | }; | 4062 | }; |
| 4053 | 4063 | ||
| @@ -4065,15 +4075,6 @@ enum { | |||
| 4065 | 4075 | ||
| 4066 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" | 4076 | #define TPACPI_RFK_WWAN_SW_NAME "tpacpi_wwan_sw" |
| 4067 | 4077 | ||
| 4068 | static void wan_suspend(pm_message_t state) | ||
| 4069 | { | ||
| 4070 | /* Try to make sure radio will resume powered off */ | ||
| 4071 | if (!acpi_evalf(NULL, NULL, "\\WGSV", "qvd", | ||
| 4072 | TP_ACPI_WGSV_PWR_OFF_ON_RESUME)) | ||
| 4073 | vdbg_printk(TPACPI_DBG_RFKILL, | ||
| 4074 | "WWAN power down on resume request failed\n"); | ||
| 4075 | } | ||
| 4076 | |||
| 4077 | static int wan_get_status(void) | 4078 | static int wan_get_status(void) |
| 4078 | { | 4079 | { |
| 4079 | int status; | 4080 | int status; |
| @@ -4106,11 +4107,10 @@ static int wan_set_status(enum tpacpi_rfkill_state state) | |||
| 4106 | } | 4107 | } |
| 4107 | #endif | 4108 | #endif |
| 4108 | 4109 | ||
| 4109 | /* We make sure to keep TP_ACPI_WANCARD_RESUMECTRL off */ | 4110 | /* We make sure to set TP_ACPI_WANCARD_RESUMECTRL */ |
| 4111 | status = TP_ACPI_WANCARD_RESUMECTRL; | ||
| 4110 | if (state == TPACPI_RFK_RADIO_ON) | 4112 | if (state == TPACPI_RFK_RADIO_ON) |
| 4111 | status = TP_ACPI_WANCARD_RADIOSSW; | 4113 | status |= TP_ACPI_WANCARD_RADIOSSW; |
| 4112 | else | ||
| 4113 | status = 0; | ||
| 4114 | 4114 | ||
| 4115 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) | 4115 | if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status)) |
| 4116 | return -EIO; | 4116 | return -EIO; |
| @@ -4233,9 +4233,9 @@ static int __init wan_init(struct ibm_init_struct *iibm) | |||
| 4233 | } | 4233 | } |
| 4234 | 4234 | ||
| 4235 | /* procfs -------------------------------------------------------------- */ | 4235 | /* procfs -------------------------------------------------------------- */ |
| 4236 | static int wan_read(char *p) | 4236 | static int wan_read(struct seq_file *m) |
| 4237 | { | 4237 | { |
| 4238 | return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, p); | 4238 | return tpacpi_rfk_procfs_read(TPACPI_RFK_WWAN_SW_ID, m); |
| 4239 | } | 4239 | } |
| 4240 | 4240 | ||
| 4241 | static int wan_write(char *buf) | 4241 | static int wan_write(char *buf) |
| @@ -4248,7 +4248,6 @@ static struct ibm_struct wan_driver_data = { | |||
| 4248 | .read = wan_read, | 4248 | .read = wan_read, |
| 4249 | .write = wan_write, | 4249 | .write = wan_write, |
| 4250 | .exit = wan_exit, | 4250 | .exit = wan_exit, |
| 4251 | .suspend = wan_suspend, | ||
| 4252 | .shutdown = wan_shutdown, | 4251 | .shutdown = wan_shutdown, |
| 4253 | }; | 4252 | }; |
| 4254 | 4253 | ||
| @@ -4611,14 +4610,13 @@ static int video_expand_toggle(void) | |||
| 4611 | /* not reached */ | 4610 | /* not reached */ |
| 4612 | } | 4611 | } |
| 4613 | 4612 | ||
| 4614 | static int video_read(char *p) | 4613 | static int video_read(struct seq_file *m) |
| 4615 | { | 4614 | { |
| 4616 | int status, autosw; | 4615 | int status, autosw; |
| 4617 | int len = 0; | ||
| 4618 | 4616 | ||
| 4619 | if (video_supported == TPACPI_VIDEO_NONE) { | 4617 | if (video_supported == TPACPI_VIDEO_NONE) { |
| 4620 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4618 | seq_printf(m, "status:\t\tnot supported\n"); |
| 4621 | return len; | 4619 | return 0; |
| 4622 | } | 4620 | } |
| 4623 | 4621 | ||
| 4624 | status = video_outputsw_get(); | 4622 | status = video_outputsw_get(); |
| @@ -4629,20 +4627,20 @@ static int video_read(char *p) | |||
| 4629 | if (autosw < 0) | 4627 | if (autosw < 0) |
| 4630 | return autosw; | 4628 | return autosw; |
| 4631 | 4629 | ||
| 4632 | len += sprintf(p + len, "status:\t\tsupported\n"); | 4630 | seq_printf(m, "status:\t\tsupported\n"); |
| 4633 | len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0)); | 4631 | seq_printf(m, "lcd:\t\t%s\n", enabled(status, 0)); |
| 4634 | len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1)); | 4632 | seq_printf(m, "crt:\t\t%s\n", enabled(status, 1)); |
| 4635 | if (video_supported == TPACPI_VIDEO_NEW) | 4633 | if (video_supported == TPACPI_VIDEO_NEW) |
| 4636 | len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3)); | 4634 | seq_printf(m, "dvi:\t\t%s\n", enabled(status, 3)); |
| 4637 | len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0)); | 4635 | seq_printf(m, "auto:\t\t%s\n", enabled(autosw, 0)); |
| 4638 | len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n"); | 4636 | seq_printf(m, "commands:\tlcd_enable, lcd_disable\n"); |
| 4639 | len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n"); | 4637 | seq_printf(m, "commands:\tcrt_enable, crt_disable\n"); |
| 4640 | if (video_supported == TPACPI_VIDEO_NEW) | 4638 | if (video_supported == TPACPI_VIDEO_NEW) |
| 4641 | len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n"); | 4639 | seq_printf(m, "commands:\tdvi_enable, dvi_disable\n"); |
| 4642 | len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n"); | 4640 | seq_printf(m, "commands:\tauto_enable, auto_disable\n"); |
| 4643 | len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n"); | 4641 | seq_printf(m, "commands:\tvideo_switch, expand_toggle\n"); |
| 4644 | 4642 | ||
| 4645 | return len; | 4643 | return 0; |
| 4646 | } | 4644 | } |
| 4647 | 4645 | ||
| 4648 | static int video_write(char *buf) | 4646 | static int video_write(char *buf) |
| @@ -4834,25 +4832,24 @@ static void light_exit(void) | |||
| 4834 | flush_workqueue(tpacpi_wq); | 4832 | flush_workqueue(tpacpi_wq); |
| 4835 | } | 4833 | } |
| 4836 | 4834 | ||
| 4837 | static int light_read(char *p) | 4835 | static int light_read(struct seq_file *m) |
| 4838 | { | 4836 | { |
| 4839 | int len = 0; | ||
| 4840 | int status; | 4837 | int status; |
| 4841 | 4838 | ||
| 4842 | if (!tp_features.light) { | 4839 | if (!tp_features.light) { |
| 4843 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4840 | seq_printf(m, "status:\t\tnot supported\n"); |
| 4844 | } else if (!tp_features.light_status) { | 4841 | } else if (!tp_features.light_status) { |
| 4845 | len += sprintf(p + len, "status:\t\tunknown\n"); | 4842 | seq_printf(m, "status:\t\tunknown\n"); |
| 4846 | len += sprintf(p + len, "commands:\ton, off\n"); | 4843 | seq_printf(m, "commands:\ton, off\n"); |
| 4847 | } else { | 4844 | } else { |
| 4848 | status = light_get_status(); | 4845 | status = light_get_status(); |
| 4849 | if (status < 0) | 4846 | if (status < 0) |
| 4850 | return status; | 4847 | return status; |
| 4851 | len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0)); | 4848 | seq_printf(m, "status:\t\t%s\n", onoff(status, 0)); |
| 4852 | len += sprintf(p + len, "commands:\ton, off\n"); | 4849 | seq_printf(m, "commands:\ton, off\n"); |
| 4853 | } | 4850 | } |
| 4854 | 4851 | ||
| 4855 | return len; | 4852 | return 0; |
| 4856 | } | 4853 | } |
| 4857 | 4854 | ||
| 4858 | static int light_write(char *buf) | 4855 | static int light_write(char *buf) |
| @@ -4930,20 +4927,18 @@ static void cmos_exit(void) | |||
| 4930 | device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); | 4927 | device_remove_file(&tpacpi_pdev->dev, &dev_attr_cmos_command); |
| 4931 | } | 4928 | } |
| 4932 | 4929 | ||
| 4933 | static int cmos_read(char *p) | 4930 | static int cmos_read(struct seq_file *m) |
| 4934 | { | 4931 | { |
| 4935 | int len = 0; | ||
| 4936 | |||
| 4937 | /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, | 4932 | /* cmos not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, |
| 4938 | R30, R31, T20-22, X20-21 */ | 4933 | R30, R31, T20-22, X20-21 */ |
| 4939 | if (!cmos_handle) | 4934 | if (!cmos_handle) |
| 4940 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 4935 | seq_printf(m, "status:\t\tnot supported\n"); |
| 4941 | else { | 4936 | else { |
| 4942 | len += sprintf(p + len, "status:\t\tsupported\n"); | 4937 | seq_printf(m, "status:\t\tsupported\n"); |
| 4943 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-21)\n"); | 4938 | seq_printf(m, "commands:\t<cmd> (<cmd> is 0-21)\n"); |
| 4944 | } | 4939 | } |
| 4945 | 4940 | ||
| 4946 | return len; | 4941 | return 0; |
| 4947 | } | 4942 | } |
| 4948 | 4943 | ||
| 4949 | static int cmos_write(char *buf) | 4944 | static int cmos_write(char *buf) |
| @@ -5318,15 +5313,13 @@ static int __init led_init(struct ibm_init_struct *iibm) | |||
| 5318 | ((s) == TPACPI_LED_OFF ? "off" : \ | 5313 | ((s) == TPACPI_LED_OFF ? "off" : \ |
| 5319 | ((s) == TPACPI_LED_ON ? "on" : "blinking")) | 5314 | ((s) == TPACPI_LED_ON ? "on" : "blinking")) |
| 5320 | 5315 | ||
| 5321 | static int led_read(char *p) | 5316 | static int led_read(struct seq_file *m) |
| 5322 | { | 5317 | { |
| 5323 | int len = 0; | ||
| 5324 | |||
| 5325 | if (!led_supported) { | 5318 | if (!led_supported) { |
| 5326 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 5319 | seq_printf(m, "status:\t\tnot supported\n"); |
| 5327 | return len; | 5320 | return 0; |
| 5328 | } | 5321 | } |
| 5329 | len += sprintf(p + len, "status:\t\tsupported\n"); | 5322 | seq_printf(m, "status:\t\tsupported\n"); |
| 5330 | 5323 | ||
| 5331 | if (led_supported == TPACPI_LED_570) { | 5324 | if (led_supported == TPACPI_LED_570) { |
| 5332 | /* 570 */ | 5325 | /* 570 */ |
| @@ -5335,15 +5328,15 @@ static int led_read(char *p) | |||
| 5335 | status = led_get_status(i); | 5328 | status = led_get_status(i); |
| 5336 | if (status < 0) | 5329 | if (status < 0) |
| 5337 | return -EIO; | 5330 | return -EIO; |
| 5338 | len += sprintf(p + len, "%d:\t\t%s\n", | 5331 | seq_printf(m, "%d:\t\t%s\n", |
| 5339 | i, str_led_status(status)); | 5332 | i, str_led_status(status)); |
| 5340 | } | 5333 | } |
| 5341 | } | 5334 | } |
| 5342 | 5335 | ||
| 5343 | len += sprintf(p + len, "commands:\t" | 5336 | seq_printf(m, "commands:\t" |
| 5344 | "<led> on, <led> off, <led> blink (<led> is 0-15)\n"); | 5337 | "<led> on, <led> off, <led> blink (<led> is 0-15)\n"); |
| 5345 | 5338 | ||
| 5346 | return len; | 5339 | return 0; |
| 5347 | } | 5340 | } |
| 5348 | 5341 | ||
| 5349 | static int led_write(char *buf) | 5342 | static int led_write(char *buf) |
| @@ -5416,18 +5409,16 @@ static int __init beep_init(struct ibm_init_struct *iibm) | |||
| 5416 | return (beep_handle)? 0 : 1; | 5409 | return (beep_handle)? 0 : 1; |
| 5417 | } | 5410 | } |
| 5418 | 5411 | ||
| 5419 | static int beep_read(char *p) | 5412 | static int beep_read(struct seq_file *m) |
| 5420 | { | 5413 | { |
| 5421 | int len = 0; | ||
| 5422 | |||
| 5423 | if (!beep_handle) | 5414 | if (!beep_handle) |
| 5424 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 5415 | seq_printf(m, "status:\t\tnot supported\n"); |
| 5425 | else { | 5416 | else { |
| 5426 | len += sprintf(p + len, "status:\t\tsupported\n"); | 5417 | seq_printf(m, "status:\t\tsupported\n"); |
| 5427 | len += sprintf(p + len, "commands:\t<cmd> (<cmd> is 0-17)\n"); | 5418 | seq_printf(m, "commands:\t<cmd> (<cmd> is 0-17)\n"); |
| 5428 | } | 5419 | } |
| 5429 | 5420 | ||
| 5430 | return len; | 5421 | return 0; |
| 5431 | } | 5422 | } |
| 5432 | 5423 | ||
| 5433 | static int beep_write(char *buf) | 5424 | static int beep_write(char *buf) |
| @@ -5480,8 +5471,11 @@ enum { /* TPACPI_THERMAL_TPEC_* */ | |||
| 5480 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ | 5471 | TP_EC_THERMAL_TMP0 = 0x78, /* ACPI EC regs TMP 0..7 */ |
| 5481 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ | 5472 | TP_EC_THERMAL_TMP8 = 0xC0, /* ACPI EC regs TMP 8..15 */ |
| 5482 | TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ | 5473 | TP_EC_THERMAL_TMP_NA = -128, /* ACPI EC sensor not available */ |
| 5474 | |||
| 5475 | TPACPI_THERMAL_SENSOR_NA = -128000, /* Sensor not available */ | ||
| 5483 | }; | 5476 | }; |
| 5484 | 5477 | ||
| 5478 | |||
| 5485 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ | 5479 | #define TPACPI_MAX_THERMAL_SENSORS 16 /* Max thermal sensors supported */ |
| 5486 | struct ibm_thermal_sensors_struct { | 5480 | struct ibm_thermal_sensors_struct { |
| 5487 | s32 temp[TPACPI_MAX_THERMAL_SENSORS]; | 5481 | s32 temp[TPACPI_MAX_THERMAL_SENSORS]; |
| @@ -5571,6 +5565,28 @@ static int thermal_get_sensors(struct ibm_thermal_sensors_struct *s) | |||
| 5571 | return n; | 5565 | return n; |
| 5572 | } | 5566 | } |
| 5573 | 5567 | ||
| 5568 | static void thermal_dump_all_sensors(void) | ||
| 5569 | { | ||
| 5570 | int n, i; | ||
| 5571 | struct ibm_thermal_sensors_struct t; | ||
| 5572 | |||
| 5573 | n = thermal_get_sensors(&t); | ||
| 5574 | if (n <= 0) | ||
| 5575 | return; | ||
| 5576 | |||
| 5577 | printk(TPACPI_NOTICE | ||
| 5578 | "temperatures (Celsius):"); | ||
| 5579 | |||
| 5580 | for (i = 0; i < n; i++) { | ||
| 5581 | if (t.temp[i] != TPACPI_THERMAL_SENSOR_NA) | ||
| 5582 | printk(KERN_CONT " %d", (int)(t.temp[i] / 1000)); | ||
| 5583 | else | ||
| 5584 | printk(KERN_CONT " N/A"); | ||
| 5585 | } | ||
| 5586 | |||
| 5587 | printk(KERN_CONT "\n"); | ||
| 5588 | } | ||
| 5589 | |||
| 5574 | /* sysfs temp##_input -------------------------------------------------- */ | 5590 | /* sysfs temp##_input -------------------------------------------------- */ |
| 5575 | 5591 | ||
| 5576 | static ssize_t thermal_temp_input_show(struct device *dev, | 5592 | static ssize_t thermal_temp_input_show(struct device *dev, |
| @@ -5586,7 +5602,7 @@ static ssize_t thermal_temp_input_show(struct device *dev, | |||
| 5586 | res = thermal_get_sensor(idx, &value); | 5602 | res = thermal_get_sensor(idx, &value); |
| 5587 | if (res) | 5603 | if (res) |
| 5588 | return res; | 5604 | return res; |
| 5589 | if (value == TP_EC_THERMAL_TMP_NA * 1000) | 5605 | if (value == TPACPI_THERMAL_SENSOR_NA) |
| 5590 | return -ENXIO; | 5606 | return -ENXIO; |
| 5591 | 5607 | ||
| 5592 | return snprintf(buf, PAGE_SIZE, "%d\n", value); | 5608 | return snprintf(buf, PAGE_SIZE, "%d\n", value); |
| @@ -5763,9 +5779,8 @@ static void thermal_exit(void) | |||
| 5763 | } | 5779 | } |
| 5764 | } | 5780 | } |
| 5765 | 5781 | ||
| 5766 | static int thermal_read(char *p) | 5782 | static int thermal_read(struct seq_file *m) |
| 5767 | { | 5783 | { |
| 5768 | int len = 0; | ||
| 5769 | int n, i; | 5784 | int n, i; |
| 5770 | struct ibm_thermal_sensors_struct t; | 5785 | struct ibm_thermal_sensors_struct t; |
| 5771 | 5786 | ||
| @@ -5773,16 +5788,16 @@ static int thermal_read(char *p) | |||
| 5773 | if (unlikely(n < 0)) | 5788 | if (unlikely(n < 0)) |
| 5774 | return n; | 5789 | return n; |
| 5775 | 5790 | ||
| 5776 | len += sprintf(p + len, "temperatures:\t"); | 5791 | seq_printf(m, "temperatures:\t"); |
| 5777 | 5792 | ||
| 5778 | if (n > 0) { | 5793 | if (n > 0) { |
| 5779 | for (i = 0; i < (n - 1); i++) | 5794 | for (i = 0; i < (n - 1); i++) |
| 5780 | len += sprintf(p + len, "%d ", t.temp[i] / 1000); | 5795 | seq_printf(m, "%d ", t.temp[i] / 1000); |
| 5781 | len += sprintf(p + len, "%d\n", t.temp[i] / 1000); | 5796 | seq_printf(m, "%d\n", t.temp[i] / 1000); |
| 5782 | } else | 5797 | } else |
| 5783 | len += sprintf(p + len, "not supported\n"); | 5798 | seq_printf(m, "not supported\n"); |
| 5784 | 5799 | ||
| 5785 | return len; | 5800 | return 0; |
| 5786 | } | 5801 | } |
| 5787 | 5802 | ||
| 5788 | static struct ibm_struct thermal_driver_data = { | 5803 | static struct ibm_struct thermal_driver_data = { |
| @@ -5797,39 +5812,38 @@ static struct ibm_struct thermal_driver_data = { | |||
| 5797 | 5812 | ||
| 5798 | static u8 ecdump_regs[256]; | 5813 | static u8 ecdump_regs[256]; |
| 5799 | 5814 | ||
| 5800 | static int ecdump_read(char *p) | 5815 | static int ecdump_read(struct seq_file *m) |
| 5801 | { | 5816 | { |
| 5802 | int len = 0; | ||
| 5803 | int i, j; | 5817 | int i, j; |
| 5804 | u8 v; | 5818 | u8 v; |
| 5805 | 5819 | ||
| 5806 | len += sprintf(p + len, "EC " | 5820 | seq_printf(m, "EC " |
| 5807 | " +00 +01 +02 +03 +04 +05 +06 +07" | 5821 | " +00 +01 +02 +03 +04 +05 +06 +07" |
| 5808 | " +08 +09 +0a +0b +0c +0d +0e +0f\n"); | 5822 | " +08 +09 +0a +0b +0c +0d +0e +0f\n"); |
| 5809 | for (i = 0; i < 256; i += 16) { | 5823 | for (i = 0; i < 256; i += 16) { |
| 5810 | len += sprintf(p + len, "EC 0x%02x:", i); | 5824 | seq_printf(m, "EC 0x%02x:", i); |
| 5811 | for (j = 0; j < 16; j++) { | 5825 | for (j = 0; j < 16; j++) { |
| 5812 | if (!acpi_ec_read(i + j, &v)) | 5826 | if (!acpi_ec_read(i + j, &v)) |
| 5813 | break; | 5827 | break; |
| 5814 | if (v != ecdump_regs[i + j]) | 5828 | if (v != ecdump_regs[i + j]) |
| 5815 | len += sprintf(p + len, " *%02x", v); | 5829 | seq_printf(m, " *%02x", v); |
| 5816 | else | 5830 | else |
| 5817 | len += sprintf(p + len, " %02x", v); | 5831 | seq_printf(m, " %02x", v); |
| 5818 | ecdump_regs[i + j] = v; | 5832 | ecdump_regs[i + j] = v; |
| 5819 | } | 5833 | } |
| 5820 | len += sprintf(p + len, "\n"); | 5834 | seq_putc(m, '\n'); |
| 5821 | if (j != 16) | 5835 | if (j != 16) |
| 5822 | break; | 5836 | break; |
| 5823 | } | 5837 | } |
| 5824 | 5838 | ||
| 5825 | /* These are way too dangerous to advertise openly... */ | 5839 | /* These are way too dangerous to advertise openly... */ |
| 5826 | #if 0 | 5840 | #if 0 |
| 5827 | len += sprintf(p + len, "commands:\t0x<offset> 0x<value>" | 5841 | seq_printf(m, "commands:\t0x<offset> 0x<value>" |
| 5828 | " (<offset> is 00-ff, <value> is 00-ff)\n"); | 5842 | " (<offset> is 00-ff, <value> is 00-ff)\n"); |
| 5829 | len += sprintf(p + len, "commands:\t0x<offset> <value> " | 5843 | seq_printf(m, "commands:\t0x<offset> <value> " |
| 5830 | " (<offset> is 00-ff, <value> is 0-255)\n"); | 5844 | " (<offset> is 00-ff, <value> is 0-255)\n"); |
| 5831 | #endif | 5845 | #endif |
| 5832 | return len; | 5846 | return 0; |
| 5833 | } | 5847 | } |
| 5834 | 5848 | ||
| 5835 | static int ecdump_write(char *buf) | 5849 | static int ecdump_write(char *buf) |
| @@ -6092,6 +6106,12 @@ static int brightness_get(struct backlight_device *bd) | |||
| 6092 | return status & TP_EC_BACKLIGHT_LVLMSK; | 6106 | return status & TP_EC_BACKLIGHT_LVLMSK; |
| 6093 | } | 6107 | } |
| 6094 | 6108 | ||
| 6109 | static void tpacpi_brightness_notify_change(void) | ||
| 6110 | { | ||
| 6111 | backlight_force_update(ibm_backlight_device, | ||
| 6112 | BACKLIGHT_UPDATE_HOTKEY); | ||
| 6113 | } | ||
| 6114 | |||
| 6095 | static struct backlight_ops ibm_backlight_data = { | 6115 | static struct backlight_ops ibm_backlight_data = { |
| 6096 | .get_brightness = brightness_get, | 6116 | .get_brightness = brightness_get, |
| 6097 | .update_status = brightness_update_status, | 6117 | .update_status = brightness_update_status, |
| @@ -6120,8 +6140,8 @@ static const struct tpacpi_quirk brightness_quirk_table[] __initconst = { | |||
| 6120 | 6140 | ||
| 6121 | /* Models with Intel Extreme Graphics 2 */ | 6141 | /* Models with Intel Extreme Graphics 2 */ |
| 6122 | TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), | 6142 | TPACPI_Q_IBM('1', 'U', TPACPI_BRGHT_Q_NOEC), |
| 6123 | TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), | 6143 | TPACPI_Q_IBM('1', 'V', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), |
| 6124 | TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_NOEC), | 6144 | TPACPI_Q_IBM('1', 'W', TPACPI_BRGHT_Q_ASK|TPACPI_BRGHT_Q_EC), |
| 6125 | 6145 | ||
| 6126 | /* Models with Intel GMA900 */ | 6146 | /* Models with Intel GMA900 */ |
| 6127 | TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ | 6147 | TPACPI_Q_IBM('7', '0', TPACPI_BRGHT_Q_NOEC), /* T43, R52 */ |
| @@ -6246,6 +6266,12 @@ static int __init brightness_init(struct ibm_init_struct *iibm) | |||
| 6246 | ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; | 6266 | ibm_backlight_device->props.brightness = b & TP_EC_BACKLIGHT_LVLMSK; |
| 6247 | backlight_update_status(ibm_backlight_device); | 6267 | backlight_update_status(ibm_backlight_device); |
| 6248 | 6268 | ||
| 6269 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_BRGHT, | ||
| 6270 | "brightness: registering brightness hotkeys " | ||
| 6271 | "as change notification\n"); | ||
| 6272 | tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | ||
| 6273 | | TP_ACPI_HKEY_BRGHTUP_MASK | ||
| 6274 | | TP_ACPI_HKEY_BRGHTDWN_MASK);; | ||
| 6249 | return 0; | 6275 | return 0; |
| 6250 | } | 6276 | } |
| 6251 | 6277 | ||
| @@ -6270,23 +6296,22 @@ static void brightness_exit(void) | |||
| 6270 | tpacpi_brightness_checkpoint_nvram(); | 6296 | tpacpi_brightness_checkpoint_nvram(); |
| 6271 | } | 6297 | } |
| 6272 | 6298 | ||
| 6273 | static int brightness_read(char *p) | 6299 | static int brightness_read(struct seq_file *m) |
| 6274 | { | 6300 | { |
| 6275 | int len = 0; | ||
| 6276 | int level; | 6301 | int level; |
| 6277 | 6302 | ||
| 6278 | level = brightness_get(NULL); | 6303 | level = brightness_get(NULL); |
| 6279 | if (level < 0) { | 6304 | if (level < 0) { |
| 6280 | len += sprintf(p + len, "level:\t\tunreadable\n"); | 6305 | seq_printf(m, "level:\t\tunreadable\n"); |
| 6281 | } else { | 6306 | } else { |
| 6282 | len += sprintf(p + len, "level:\t\t%d\n", level); | 6307 | seq_printf(m, "level:\t\t%d\n", level); |
| 6283 | len += sprintf(p + len, "commands:\tup, down\n"); | 6308 | seq_printf(m, "commands:\tup, down\n"); |
| 6284 | len += sprintf(p + len, "commands:\tlevel <level>" | 6309 | seq_printf(m, "commands:\tlevel <level>" |
| 6285 | " (<level> is 0-%d)\n", | 6310 | " (<level> is 0-%d)\n", |
| 6286 | (tp_features.bright_16levels) ? 15 : 7); | 6311 | (tp_features.bright_16levels) ? 15 : 7); |
| 6287 | } | 6312 | } |
| 6288 | 6313 | ||
| 6289 | return len; | 6314 | return 0; |
| 6290 | } | 6315 | } |
| 6291 | 6316 | ||
| 6292 | static int brightness_write(char *buf) | 6317 | static int brightness_write(char *buf) |
| @@ -6322,6 +6347,9 @@ static int brightness_write(char *buf) | |||
| 6322 | * Doing it this way makes the syscall restartable in case of EINTR | 6347 | * Doing it this way makes the syscall restartable in case of EINTR |
| 6323 | */ | 6348 | */ |
| 6324 | rc = brightness_set(level); | 6349 | rc = brightness_set(level); |
| 6350 | if (!rc && ibm_backlight_device) | ||
| 6351 | backlight_force_update(ibm_backlight_device, | ||
| 6352 | BACKLIGHT_UPDATE_SYSFS); | ||
| 6325 | return (rc == -EINTR)? -ERESTARTSYS : rc; | 6353 | return (rc == -EINTR)? -ERESTARTSYS : rc; |
| 6326 | } | 6354 | } |
| 6327 | 6355 | ||
| @@ -6338,99 +6366,654 @@ static struct ibm_struct brightness_driver_data = { | |||
| 6338 | * Volume subdriver | 6366 | * Volume subdriver |
| 6339 | */ | 6367 | */ |
| 6340 | 6368 | ||
| 6341 | static int volume_offset = 0x30; | 6369 | /* |
| 6370 | * IBM ThinkPads have a simple volume controller with MUTE gating. | ||
| 6371 | * Very early Lenovo ThinkPads follow the IBM ThinkPad spec. | ||
| 6372 | * | ||
| 6373 | * Since the *61 series (and probably also the later *60 series), Lenovo | ||
| 6374 | * ThinkPads only implement the MUTE gate. | ||
| 6375 | * | ||
| 6376 | * EC register 0x30 | ||
| 6377 | * Bit 6: MUTE (1 mutes sound) | ||
| 6378 | * Bit 3-0: Volume | ||
| 6379 | * Other bits should be zero as far as we know. | ||
| 6380 | * | ||
| 6381 | * This is also stored in CMOS NVRAM, byte 0x60, bit 6 (MUTE), and | ||
| 6382 | * bits 3-0 (volume). Other bits in NVRAM may have other functions, | ||
| 6383 | * such as bit 7 which is used to detect repeated presses of MUTE, | ||
| 6384 | * and we leave them unchanged. | ||
| 6385 | */ | ||
| 6386 | |||
| 6387 | #define TPACPI_ALSA_DRVNAME "ThinkPad EC" | ||
| 6388 | #define TPACPI_ALSA_SHRTNAME "ThinkPad Console Audio Control" | ||
| 6389 | #define TPACPI_ALSA_MIXERNAME TPACPI_ALSA_SHRTNAME | ||
| 6390 | |||
| 6391 | static int alsa_index = SNDRV_DEFAULT_IDX1; | ||
| 6392 | static char *alsa_id = "ThinkPadEC"; | ||
| 6393 | static int alsa_enable = SNDRV_DEFAULT_ENABLE1; | ||
| 6394 | |||
| 6395 | struct tpacpi_alsa_data { | ||
| 6396 | struct snd_card *card; | ||
| 6397 | struct snd_ctl_elem_id *ctl_mute_id; | ||
| 6398 | struct snd_ctl_elem_id *ctl_vol_id; | ||
| 6399 | }; | ||
| 6400 | |||
| 6401 | static struct snd_card *alsa_card; | ||
| 6402 | |||
| 6403 | enum { | ||
| 6404 | TP_EC_AUDIO = 0x30, | ||
| 6405 | |||
| 6406 | /* TP_EC_AUDIO bits */ | ||
| 6407 | TP_EC_AUDIO_MUTESW = 6, | ||
| 6408 | |||
| 6409 | /* TP_EC_AUDIO bitmasks */ | ||
| 6410 | TP_EC_AUDIO_LVL_MSK = 0x0F, | ||
| 6411 | TP_EC_AUDIO_MUTESW_MSK = (1 << TP_EC_AUDIO_MUTESW), | ||
| 6412 | |||
| 6413 | /* Maximum volume */ | ||
| 6414 | TP_EC_VOLUME_MAX = 14, | ||
| 6415 | }; | ||
| 6416 | |||
| 6417 | enum tpacpi_volume_access_mode { | ||
| 6418 | TPACPI_VOL_MODE_AUTO = 0, /* Not implemented yet */ | ||
| 6419 | TPACPI_VOL_MODE_EC, /* Pure EC control */ | ||
| 6420 | TPACPI_VOL_MODE_UCMS_STEP, /* UCMS step-based control: N/A */ | ||
| 6421 | TPACPI_VOL_MODE_ECNVRAM, /* EC control w/ NVRAM store */ | ||
| 6422 | TPACPI_VOL_MODE_MAX | ||
| 6423 | }; | ||
| 6424 | |||
| 6425 | enum tpacpi_volume_capabilities { | ||
| 6426 | TPACPI_VOL_CAP_AUTO = 0, /* Use white/blacklist */ | ||
| 6427 | TPACPI_VOL_CAP_VOLMUTE, /* Output vol and mute */ | ||
| 6428 | TPACPI_VOL_CAP_MUTEONLY, /* Output mute only */ | ||
| 6429 | TPACPI_VOL_CAP_MAX | ||
| 6430 | }; | ||
| 6431 | |||
| 6432 | static enum tpacpi_volume_access_mode volume_mode = | ||
| 6433 | TPACPI_VOL_MODE_MAX; | ||
| 6434 | |||
| 6435 | static enum tpacpi_volume_capabilities volume_capabilities; | ||
| 6436 | static int volume_control_allowed; | ||
| 6342 | 6437 | ||
| 6343 | static int volume_read(char *p) | 6438 | /* |
| 6439 | * Used to syncronize writers to TP_EC_AUDIO and | ||
| 6440 | * TP_NVRAM_ADDR_MIXER, as we need to do read-modify-write | ||
| 6441 | */ | ||
| 6442 | static struct mutex volume_mutex; | ||
| 6443 | |||
| 6444 | static void tpacpi_volume_checkpoint_nvram(void) | ||
| 6344 | { | 6445 | { |
| 6345 | int len = 0; | 6446 | u8 lec = 0; |
| 6346 | u8 level; | 6447 | u8 b_nvram; |
| 6448 | u8 ec_mask; | ||
| 6449 | |||
| 6450 | if (volume_mode != TPACPI_VOL_MODE_ECNVRAM) | ||
| 6451 | return; | ||
| 6452 | if (!volume_control_allowed) | ||
| 6453 | return; | ||
| 6454 | |||
| 6455 | vdbg_printk(TPACPI_DBG_MIXER, | ||
| 6456 | "trying to checkpoint mixer state to NVRAM...\n"); | ||
| 6347 | 6457 | ||
| 6348 | if (!acpi_ec_read(volume_offset, &level)) { | 6458 | if (tp_features.mixer_no_level_control) |
| 6349 | len += sprintf(p + len, "level:\t\tunreadable\n"); | 6459 | ec_mask = TP_EC_AUDIO_MUTESW_MSK; |
| 6460 | else | ||
| 6461 | ec_mask = TP_EC_AUDIO_MUTESW_MSK | TP_EC_AUDIO_LVL_MSK; | ||
| 6462 | |||
| 6463 | if (mutex_lock_killable(&volume_mutex) < 0) | ||
| 6464 | return; | ||
| 6465 | |||
| 6466 | if (unlikely(!acpi_ec_read(TP_EC_AUDIO, &lec))) | ||
| 6467 | goto unlock; | ||
| 6468 | lec &= ec_mask; | ||
| 6469 | b_nvram = nvram_read_byte(TP_NVRAM_ADDR_MIXER); | ||
| 6470 | |||
| 6471 | if (lec != (b_nvram & ec_mask)) { | ||
| 6472 | /* NVRAM needs update */ | ||
| 6473 | b_nvram &= ~ec_mask; | ||
| 6474 | b_nvram |= lec; | ||
| 6475 | nvram_write_byte(b_nvram, TP_NVRAM_ADDR_MIXER); | ||
| 6476 | dbg_printk(TPACPI_DBG_MIXER, | ||
| 6477 | "updated NVRAM mixer status to 0x%02x (0x%02x)\n", | ||
| 6478 | (unsigned int) lec, (unsigned int) b_nvram); | ||
| 6350 | } else { | 6479 | } else { |
| 6351 | len += sprintf(p + len, "level:\t\t%d\n", level & 0xf); | 6480 | vdbg_printk(TPACPI_DBG_MIXER, |
| 6352 | len += sprintf(p + len, "mute:\t\t%s\n", onoff(level, 6)); | 6481 | "NVRAM mixer status already is 0x%02x (0x%02x)\n", |
| 6353 | len += sprintf(p + len, "commands:\tup, down, mute\n"); | 6482 | (unsigned int) lec, (unsigned int) b_nvram); |
| 6354 | len += sprintf(p + len, "commands:\tlevel <level>" | ||
| 6355 | " (<level> is 0-15)\n"); | ||
| 6356 | } | 6483 | } |
| 6357 | 6484 | ||
| 6358 | return len; | 6485 | unlock: |
| 6486 | mutex_unlock(&volume_mutex); | ||
| 6359 | } | 6487 | } |
| 6360 | 6488 | ||
| 6361 | static int volume_write(char *buf) | 6489 | static int volume_get_status_ec(u8 *status) |
| 6362 | { | 6490 | { |
| 6363 | int cmos_cmd, inc, i; | 6491 | u8 s; |
| 6364 | u8 level, mute; | ||
| 6365 | int new_level, new_mute; | ||
| 6366 | char *cmd; | ||
| 6367 | 6492 | ||
| 6368 | while ((cmd = next_cmd(&buf))) { | 6493 | if (!acpi_ec_read(TP_EC_AUDIO, &s)) |
| 6369 | if (!acpi_ec_read(volume_offset, &level)) | 6494 | return -EIO; |
| 6370 | return -EIO; | ||
| 6371 | new_mute = mute = level & 0x40; | ||
| 6372 | new_level = level = level & 0xf; | ||
| 6373 | 6495 | ||
| 6374 | if (strlencmp(cmd, "up") == 0) { | 6496 | *status = s; |
| 6375 | if (mute) | ||
| 6376 | new_mute = 0; | ||
| 6377 | else | ||
| 6378 | new_level = level == 15 ? 15 : level + 1; | ||
| 6379 | } else if (strlencmp(cmd, "down") == 0) { | ||
| 6380 | if (mute) | ||
| 6381 | new_mute = 0; | ||
| 6382 | else | ||
| 6383 | new_level = level == 0 ? 0 : level - 1; | ||
| 6384 | } else if (sscanf(cmd, "level %d", &new_level) == 1 && | ||
| 6385 | new_level >= 0 && new_level <= 15) { | ||
| 6386 | /* new_level set */ | ||
| 6387 | } else if (strlencmp(cmd, "mute") == 0) { | ||
| 6388 | new_mute = 0x40; | ||
| 6389 | } else | ||
| 6390 | return -EINVAL; | ||
| 6391 | 6497 | ||
| 6392 | if (new_level != level) { | 6498 | dbg_printk(TPACPI_DBG_MIXER, "status 0x%02x\n", s); |
| 6393 | /* mute doesn't change */ | ||
| 6394 | 6499 | ||
| 6395 | cmos_cmd = (new_level > level) ? | 6500 | return 0; |
| 6396 | TP_CMOS_VOLUME_UP : TP_CMOS_VOLUME_DOWN; | 6501 | } |
| 6397 | inc = new_level > level ? 1 : -1; | ||
| 6398 | 6502 | ||
| 6399 | if (mute && (issue_thinkpad_cmos_command(cmos_cmd) || | 6503 | static int volume_get_status(u8 *status) |
| 6400 | !acpi_ec_write(volume_offset, level))) | 6504 | { |
| 6401 | return -EIO; | 6505 | return volume_get_status_ec(status); |
| 6506 | } | ||
| 6402 | 6507 | ||
| 6403 | for (i = level; i != new_level; i += inc) | 6508 | static int volume_set_status_ec(const u8 status) |
| 6404 | if (issue_thinkpad_cmos_command(cmos_cmd) || | 6509 | { |
| 6405 | !acpi_ec_write(volume_offset, i + inc)) | 6510 | if (!acpi_ec_write(TP_EC_AUDIO, status)) |
| 6406 | return -EIO; | 6511 | return -EIO; |
| 6407 | 6512 | ||
| 6408 | if (mute && | 6513 | dbg_printk(TPACPI_DBG_MIXER, "set EC mixer to 0x%02x\n", status); |
| 6409 | (issue_thinkpad_cmos_command(TP_CMOS_VOLUME_MUTE) || | 6514 | |
| 6410 | !acpi_ec_write(volume_offset, new_level + mute))) { | 6515 | return 0; |
| 6411 | return -EIO; | 6516 | } |
| 6412 | } | 6517 | |
| 6518 | static int volume_set_status(const u8 status) | ||
| 6519 | { | ||
| 6520 | return volume_set_status_ec(status); | ||
| 6521 | } | ||
| 6522 | |||
| 6523 | static int volume_set_mute_ec(const bool mute) | ||
| 6524 | { | ||
| 6525 | int rc; | ||
| 6526 | u8 s, n; | ||
| 6527 | |||
| 6528 | if (mutex_lock_killable(&volume_mutex) < 0) | ||
| 6529 | return -EINTR; | ||
| 6530 | |||
| 6531 | rc = volume_get_status_ec(&s); | ||
| 6532 | if (rc) | ||
| 6533 | goto unlock; | ||
| 6534 | |||
| 6535 | n = (mute) ? s | TP_EC_AUDIO_MUTESW_MSK : | ||
| 6536 | s & ~TP_EC_AUDIO_MUTESW_MSK; | ||
| 6537 | |||
| 6538 | if (n != s) | ||
| 6539 | rc = volume_set_status_ec(n); | ||
| 6540 | |||
| 6541 | unlock: | ||
| 6542 | mutex_unlock(&volume_mutex); | ||
| 6543 | return rc; | ||
| 6544 | } | ||
| 6545 | |||
| 6546 | static int volume_set_mute(const bool mute) | ||
| 6547 | { | ||
| 6548 | dbg_printk(TPACPI_DBG_MIXER, "trying to %smute\n", | ||
| 6549 | (mute) ? "" : "un"); | ||
| 6550 | return volume_set_mute_ec(mute); | ||
| 6551 | } | ||
| 6552 | |||
| 6553 | static int volume_set_volume_ec(const u8 vol) | ||
| 6554 | { | ||
| 6555 | int rc; | ||
| 6556 | u8 s, n; | ||
| 6557 | |||
| 6558 | if (vol > TP_EC_VOLUME_MAX) | ||
| 6559 | return -EINVAL; | ||
| 6560 | |||
| 6561 | if (mutex_lock_killable(&volume_mutex) < 0) | ||
| 6562 | return -EINTR; | ||
| 6563 | |||
| 6564 | rc = volume_get_status_ec(&s); | ||
| 6565 | if (rc) | ||
| 6566 | goto unlock; | ||
| 6567 | |||
| 6568 | n = (s & ~TP_EC_AUDIO_LVL_MSK) | vol; | ||
| 6569 | |||
| 6570 | if (n != s) | ||
| 6571 | rc = volume_set_status_ec(n); | ||
| 6572 | |||
| 6573 | unlock: | ||
| 6574 | mutex_unlock(&volume_mutex); | ||
| 6575 | return rc; | ||
| 6576 | } | ||
| 6577 | |||
| 6578 | static int volume_set_volume(const u8 vol) | ||
| 6579 | { | ||
| 6580 | dbg_printk(TPACPI_DBG_MIXER, | ||
| 6581 | "trying to set volume level to %hu\n", vol); | ||
| 6582 | return volume_set_volume_ec(vol); | ||
| 6583 | } | ||
| 6584 | |||
| 6585 | static void volume_alsa_notify_change(void) | ||
| 6586 | { | ||
| 6587 | struct tpacpi_alsa_data *d; | ||
| 6588 | |||
| 6589 | if (alsa_card && alsa_card->private_data) { | ||
| 6590 | d = alsa_card->private_data; | ||
| 6591 | if (d->ctl_mute_id) | ||
| 6592 | snd_ctl_notify(alsa_card, | ||
| 6593 | SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 6594 | d->ctl_mute_id); | ||
| 6595 | if (d->ctl_vol_id) | ||
| 6596 | snd_ctl_notify(alsa_card, | ||
| 6597 | SNDRV_CTL_EVENT_MASK_VALUE, | ||
| 6598 | d->ctl_vol_id); | ||
| 6599 | } | ||
| 6600 | } | ||
| 6601 | |||
| 6602 | static int volume_alsa_vol_info(struct snd_kcontrol *kcontrol, | ||
| 6603 | struct snd_ctl_elem_info *uinfo) | ||
| 6604 | { | ||
| 6605 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 6606 | uinfo->count = 1; | ||
| 6607 | uinfo->value.integer.min = 0; | ||
| 6608 | uinfo->value.integer.max = TP_EC_VOLUME_MAX; | ||
| 6609 | return 0; | ||
| 6610 | } | ||
| 6611 | |||
| 6612 | static int volume_alsa_vol_get(struct snd_kcontrol *kcontrol, | ||
| 6613 | struct snd_ctl_elem_value *ucontrol) | ||
| 6614 | { | ||
| 6615 | u8 s; | ||
| 6616 | int rc; | ||
| 6617 | |||
| 6618 | rc = volume_get_status(&s); | ||
| 6619 | if (rc < 0) | ||
| 6620 | return rc; | ||
| 6621 | |||
| 6622 | ucontrol->value.integer.value[0] = s & TP_EC_AUDIO_LVL_MSK; | ||
| 6623 | return 0; | ||
| 6624 | } | ||
| 6625 | |||
| 6626 | static int volume_alsa_vol_put(struct snd_kcontrol *kcontrol, | ||
| 6627 | struct snd_ctl_elem_value *ucontrol) | ||
| 6628 | { | ||
| 6629 | return volume_set_volume(ucontrol->value.integer.value[0]); | ||
| 6630 | } | ||
| 6631 | |||
| 6632 | #define volume_alsa_mute_info snd_ctl_boolean_mono_info | ||
| 6633 | |||
| 6634 | static int volume_alsa_mute_get(struct snd_kcontrol *kcontrol, | ||
| 6635 | struct snd_ctl_elem_value *ucontrol) | ||
| 6636 | { | ||
| 6637 | u8 s; | ||
| 6638 | int rc; | ||
| 6639 | |||
| 6640 | rc = volume_get_status(&s); | ||
| 6641 | if (rc < 0) | ||
| 6642 | return rc; | ||
| 6643 | |||
| 6644 | ucontrol->value.integer.value[0] = | ||
| 6645 | (s & TP_EC_AUDIO_MUTESW_MSK) ? 0 : 1; | ||
| 6646 | return 0; | ||
| 6647 | } | ||
| 6648 | |||
| 6649 | static int volume_alsa_mute_put(struct snd_kcontrol *kcontrol, | ||
| 6650 | struct snd_ctl_elem_value *ucontrol) | ||
| 6651 | { | ||
| 6652 | return volume_set_mute(!ucontrol->value.integer.value[0]); | ||
| 6653 | } | ||
| 6654 | |||
| 6655 | static struct snd_kcontrol_new volume_alsa_control_vol __devinitdata = { | ||
| 6656 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 6657 | .name = "Console Playback Volume", | ||
| 6658 | .index = 0, | ||
| 6659 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 6660 | .info = volume_alsa_vol_info, | ||
| 6661 | .get = volume_alsa_vol_get, | ||
| 6662 | }; | ||
| 6663 | |||
| 6664 | static struct snd_kcontrol_new volume_alsa_control_mute __devinitdata = { | ||
| 6665 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 6666 | .name = "Console Playback Switch", | ||
| 6667 | .index = 0, | ||
| 6668 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
| 6669 | .info = volume_alsa_mute_info, | ||
| 6670 | .get = volume_alsa_mute_get, | ||
| 6671 | }; | ||
| 6672 | |||
| 6673 | static void volume_suspend(pm_message_t state) | ||
| 6674 | { | ||
| 6675 | tpacpi_volume_checkpoint_nvram(); | ||
| 6676 | } | ||
| 6677 | |||
| 6678 | static void volume_resume(void) | ||
| 6679 | { | ||
| 6680 | volume_alsa_notify_change(); | ||
| 6681 | } | ||
| 6682 | |||
| 6683 | static void volume_shutdown(void) | ||
| 6684 | { | ||
| 6685 | tpacpi_volume_checkpoint_nvram(); | ||
| 6686 | } | ||
| 6687 | |||
| 6688 | static void volume_exit(void) | ||
| 6689 | { | ||
| 6690 | if (alsa_card) { | ||
| 6691 | snd_card_free(alsa_card); | ||
| 6692 | alsa_card = NULL; | ||
| 6693 | } | ||
| 6694 | |||
| 6695 | tpacpi_volume_checkpoint_nvram(); | ||
| 6696 | } | ||
| 6697 | |||
| 6698 | static int __init volume_create_alsa_mixer(void) | ||
| 6699 | { | ||
| 6700 | struct snd_card *card; | ||
| 6701 | struct tpacpi_alsa_data *data; | ||
| 6702 | struct snd_kcontrol *ctl_vol; | ||
| 6703 | struct snd_kcontrol *ctl_mute; | ||
| 6704 | int rc; | ||
| 6705 | |||
| 6706 | rc = snd_card_create(alsa_index, alsa_id, THIS_MODULE, | ||
| 6707 | sizeof(struct tpacpi_alsa_data), &card); | ||
| 6708 | if (rc < 0) | ||
| 6709 | return rc; | ||
| 6710 | if (!card) | ||
| 6711 | return -ENOMEM; | ||
| 6712 | |||
| 6713 | BUG_ON(!card->private_data); | ||
| 6714 | data = card->private_data; | ||
| 6715 | data->card = card; | ||
| 6716 | |||
| 6717 | strlcpy(card->driver, TPACPI_ALSA_DRVNAME, | ||
| 6718 | sizeof(card->driver)); | ||
| 6719 | strlcpy(card->shortname, TPACPI_ALSA_SHRTNAME, | ||
| 6720 | sizeof(card->shortname)); | ||
| 6721 | snprintf(card->mixername, sizeof(card->mixername), "ThinkPad EC %s", | ||
| 6722 | (thinkpad_id.ec_version_str) ? | ||
| 6723 | thinkpad_id.ec_version_str : "(unknown)"); | ||
| 6724 | snprintf(card->longname, sizeof(card->longname), | ||
| 6725 | "%s at EC reg 0x%02x, fw %s", card->shortname, TP_EC_AUDIO, | ||
| 6726 | (thinkpad_id.ec_version_str) ? | ||
| 6727 | thinkpad_id.ec_version_str : "unknown"); | ||
| 6728 | |||
| 6729 | if (volume_control_allowed) { | ||
| 6730 | volume_alsa_control_vol.put = volume_alsa_vol_put; | ||
| 6731 | volume_alsa_control_vol.access = | ||
| 6732 | SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
| 6733 | |||
| 6734 | volume_alsa_control_mute.put = volume_alsa_mute_put; | ||
| 6735 | volume_alsa_control_mute.access = | ||
| 6736 | SNDRV_CTL_ELEM_ACCESS_READWRITE; | ||
| 6737 | } | ||
| 6738 | |||
| 6739 | if (!tp_features.mixer_no_level_control) { | ||
| 6740 | ctl_vol = snd_ctl_new1(&volume_alsa_control_vol, NULL); | ||
| 6741 | rc = snd_ctl_add(card, ctl_vol); | ||
| 6742 | if (rc < 0) { | ||
| 6743 | printk(TPACPI_ERR | ||
| 6744 | "Failed to create ALSA volume control\n"); | ||
| 6745 | goto err_out; | ||
| 6413 | } | 6746 | } |
| 6747 | data->ctl_vol_id = &ctl_vol->id; | ||
| 6748 | } | ||
| 6414 | 6749 | ||
| 6415 | if (new_mute != mute) { | 6750 | ctl_mute = snd_ctl_new1(&volume_alsa_control_mute, NULL); |
| 6416 | /* level doesn't change */ | 6751 | rc = snd_ctl_add(card, ctl_mute); |
| 6752 | if (rc < 0) { | ||
| 6753 | printk(TPACPI_ERR "Failed to create ALSA mute control\n"); | ||
| 6754 | goto err_out; | ||
| 6755 | } | ||
| 6756 | data->ctl_mute_id = &ctl_mute->id; | ||
| 6417 | 6757 | ||
| 6418 | cmos_cmd = (new_mute) ? | 6758 | snd_card_set_dev(card, &tpacpi_pdev->dev); |
| 6419 | TP_CMOS_VOLUME_MUTE : TP_CMOS_VOLUME_UP; | 6759 | rc = snd_card_register(card); |
| 6420 | 6760 | ||
| 6421 | if (issue_thinkpad_cmos_command(cmos_cmd) || | 6761 | err_out: |
| 6422 | !acpi_ec_write(volume_offset, level + new_mute)) | 6762 | if (rc < 0) { |
| 6423 | return -EIO; | 6763 | snd_card_free(card); |
| 6764 | card = NULL; | ||
| 6765 | } | ||
| 6766 | |||
| 6767 | alsa_card = card; | ||
| 6768 | return rc; | ||
| 6769 | } | ||
| 6770 | |||
| 6771 | #define TPACPI_VOL_Q_MUTEONLY 0x0001 /* Mute-only control available */ | ||
| 6772 | #define TPACPI_VOL_Q_LEVEL 0x0002 /* Volume control available */ | ||
| 6773 | |||
| 6774 | static const struct tpacpi_quirk volume_quirk_table[] __initconst = { | ||
| 6775 | /* Whitelist volume level on all IBM by default */ | ||
| 6776 | { .vendor = PCI_VENDOR_ID_IBM, | ||
| 6777 | .bios = TPACPI_MATCH_ANY, | ||
| 6778 | .ec = TPACPI_MATCH_ANY, | ||
| 6779 | .quirks = TPACPI_VOL_Q_LEVEL }, | ||
| 6780 | |||
| 6781 | /* Lenovo models with volume control (needs confirmation) */ | ||
| 6782 | TPACPI_QEC_LNV('7', 'C', TPACPI_VOL_Q_LEVEL), /* R60/i */ | ||
| 6783 | TPACPI_QEC_LNV('7', 'E', TPACPI_VOL_Q_LEVEL), /* R60e/i */ | ||
| 6784 | TPACPI_QEC_LNV('7', '9', TPACPI_VOL_Q_LEVEL), /* T60/p */ | ||
| 6785 | TPACPI_QEC_LNV('7', 'B', TPACPI_VOL_Q_LEVEL), /* X60/s */ | ||
| 6786 | TPACPI_QEC_LNV('7', 'J', TPACPI_VOL_Q_LEVEL), /* X60t */ | ||
| 6787 | TPACPI_QEC_LNV('7', '7', TPACPI_VOL_Q_LEVEL), /* Z60 */ | ||
| 6788 | TPACPI_QEC_LNV('7', 'F', TPACPI_VOL_Q_LEVEL), /* Z61 */ | ||
| 6789 | |||
| 6790 | /* Whitelist mute-only on all Lenovo by default */ | ||
| 6791 | { .vendor = PCI_VENDOR_ID_LENOVO, | ||
| 6792 | .bios = TPACPI_MATCH_ANY, | ||
| 6793 | .ec = TPACPI_MATCH_ANY, | ||
| 6794 | .quirks = TPACPI_VOL_Q_MUTEONLY } | ||
| 6795 | }; | ||
| 6796 | |||
| 6797 | static int __init volume_init(struct ibm_init_struct *iibm) | ||
| 6798 | { | ||
| 6799 | unsigned long quirks; | ||
| 6800 | int rc; | ||
| 6801 | |||
| 6802 | vdbg_printk(TPACPI_DBG_INIT, "initializing volume subdriver\n"); | ||
| 6803 | |||
| 6804 | mutex_init(&volume_mutex); | ||
| 6805 | |||
| 6806 | /* | ||
| 6807 | * Check for module parameter bogosity, note that we | ||
| 6808 | * init volume_mode to TPACPI_VOL_MODE_MAX in order to be | ||
| 6809 | * able to detect "unspecified" | ||
| 6810 | */ | ||
| 6811 | if (volume_mode > TPACPI_VOL_MODE_MAX) | ||
| 6812 | return -EINVAL; | ||
| 6813 | |||
| 6814 | if (volume_mode == TPACPI_VOL_MODE_UCMS_STEP) { | ||
| 6815 | printk(TPACPI_ERR | ||
| 6816 | "UCMS step volume mode not implemented, " | ||
| 6817 | "please contact %s\n", TPACPI_MAIL); | ||
| 6818 | return 1; | ||
| 6819 | } | ||
| 6820 | |||
| 6821 | if (volume_capabilities >= TPACPI_VOL_CAP_MAX) | ||
| 6822 | return -EINVAL; | ||
| 6823 | |||
| 6824 | /* | ||
| 6825 | * The ALSA mixer is our primary interface. | ||
| 6826 | * When disabled, don't install the subdriver at all | ||
| 6827 | */ | ||
| 6828 | if (!alsa_enable) { | ||
| 6829 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
| 6830 | "ALSA mixer disabled by parameter, " | ||
| 6831 | "not loading volume subdriver...\n"); | ||
| 6832 | return 1; | ||
| 6833 | } | ||
| 6834 | |||
| 6835 | quirks = tpacpi_check_quirks(volume_quirk_table, | ||
| 6836 | ARRAY_SIZE(volume_quirk_table)); | ||
| 6837 | |||
| 6838 | switch (volume_capabilities) { | ||
| 6839 | case TPACPI_VOL_CAP_AUTO: | ||
| 6840 | if (quirks & TPACPI_VOL_Q_MUTEONLY) | ||
| 6841 | tp_features.mixer_no_level_control = 1; | ||
| 6842 | else if (quirks & TPACPI_VOL_Q_LEVEL) | ||
| 6843 | tp_features.mixer_no_level_control = 0; | ||
| 6844 | else | ||
| 6845 | return 1; /* no mixer */ | ||
| 6846 | break; | ||
| 6847 | case TPACPI_VOL_CAP_VOLMUTE: | ||
| 6848 | tp_features.mixer_no_level_control = 0; | ||
| 6849 | break; | ||
| 6850 | case TPACPI_VOL_CAP_MUTEONLY: | ||
| 6851 | tp_features.mixer_no_level_control = 1; | ||
| 6852 | break; | ||
| 6853 | default: | ||
| 6854 | return 1; | ||
| 6855 | } | ||
| 6856 | |||
| 6857 | if (volume_capabilities != TPACPI_VOL_CAP_AUTO) | ||
| 6858 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
| 6859 | "using user-supplied volume_capabilities=%d\n", | ||
| 6860 | volume_capabilities); | ||
| 6861 | |||
| 6862 | if (volume_mode == TPACPI_VOL_MODE_AUTO || | ||
| 6863 | volume_mode == TPACPI_VOL_MODE_MAX) { | ||
| 6864 | volume_mode = TPACPI_VOL_MODE_ECNVRAM; | ||
| 6865 | |||
| 6866 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
| 6867 | "driver auto-selected volume_mode=%d\n", | ||
| 6868 | volume_mode); | ||
| 6869 | } else { | ||
| 6870 | dbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
| 6871 | "using user-supplied volume_mode=%d\n", | ||
| 6872 | volume_mode); | ||
| 6873 | } | ||
| 6874 | |||
| 6875 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
| 6876 | "mute is supported, volume control is %s\n", | ||
| 6877 | str_supported(!tp_features.mixer_no_level_control)); | ||
| 6878 | |||
| 6879 | rc = volume_create_alsa_mixer(); | ||
| 6880 | if (rc) { | ||
| 6881 | printk(TPACPI_ERR | ||
| 6882 | "Could not create the ALSA mixer interface\n"); | ||
| 6883 | return rc; | ||
| 6884 | } | ||
| 6885 | |||
| 6886 | printk(TPACPI_INFO | ||
| 6887 | "Console audio control enabled, mode: %s\n", | ||
| 6888 | (volume_control_allowed) ? | ||
| 6889 | "override (read/write)" : | ||
| 6890 | "monitor (read only)"); | ||
| 6891 | |||
| 6892 | vdbg_printk(TPACPI_DBG_INIT | TPACPI_DBG_MIXER, | ||
| 6893 | "registering volume hotkeys as change notification\n"); | ||
| 6894 | tpacpi_hotkey_driver_mask_set(hotkey_driver_mask | ||
| 6895 | | TP_ACPI_HKEY_VOLUP_MASK | ||
| 6896 | | TP_ACPI_HKEY_VOLDWN_MASK | ||
| 6897 | | TP_ACPI_HKEY_MUTE_MASK); | ||
| 6898 | |||
| 6899 | return 0; | ||
| 6900 | } | ||
| 6901 | |||
| 6902 | static int volume_read(struct seq_file *m) | ||
| 6903 | { | ||
| 6904 | u8 status; | ||
| 6905 | |||
| 6906 | if (volume_get_status(&status) < 0) { | ||
| 6907 | seq_printf(m, "level:\t\tunreadable\n"); | ||
| 6908 | } else { | ||
| 6909 | if (tp_features.mixer_no_level_control) | ||
| 6910 | seq_printf(m, "level:\t\tunsupported\n"); | ||
| 6911 | else | ||
| 6912 | seq_printf(m, "level:\t\t%d\n", | ||
| 6913 | status & TP_EC_AUDIO_LVL_MSK); | ||
| 6914 | |||
| 6915 | seq_printf(m, "mute:\t\t%s\n", | ||
| 6916 | onoff(status, TP_EC_AUDIO_MUTESW)); | ||
| 6917 | |||
| 6918 | if (volume_control_allowed) { | ||
| 6919 | seq_printf(m, "commands:\tunmute, mute\n"); | ||
| 6920 | if (!tp_features.mixer_no_level_control) { | ||
| 6921 | seq_printf(m, | ||
| 6922 | "commands:\tup, down\n"); | ||
| 6923 | seq_printf(m, | ||
| 6924 | "commands:\tlevel <level>" | ||
| 6925 | " (<level> is 0-%d)\n", | ||
| 6926 | TP_EC_VOLUME_MAX); | ||
| 6927 | } | ||
| 6424 | } | 6928 | } |
| 6425 | } | 6929 | } |
| 6426 | 6930 | ||
| 6427 | return 0; | 6931 | return 0; |
| 6428 | } | 6932 | } |
| 6429 | 6933 | ||
| 6934 | static int volume_write(char *buf) | ||
| 6935 | { | ||
| 6936 | u8 s; | ||
| 6937 | u8 new_level, new_mute; | ||
| 6938 | int l; | ||
| 6939 | char *cmd; | ||
| 6940 | int rc; | ||
| 6941 | |||
| 6942 | /* | ||
| 6943 | * We do allow volume control at driver startup, so that the | ||
| 6944 | * user can set initial state through the volume=... parameter hack. | ||
| 6945 | */ | ||
| 6946 | if (!volume_control_allowed && tpacpi_lifecycle != TPACPI_LIFE_INIT) { | ||
| 6947 | if (unlikely(!tp_warned.volume_ctrl_forbidden)) { | ||
| 6948 | tp_warned.volume_ctrl_forbidden = 1; | ||
| 6949 | printk(TPACPI_NOTICE | ||
| 6950 | "Console audio control in monitor mode, " | ||
| 6951 | "changes are not allowed.\n"); | ||
| 6952 | printk(TPACPI_NOTICE | ||
| 6953 | "Use the volume_control=1 module parameter " | ||
| 6954 | "to enable volume control\n"); | ||
| 6955 | } | ||
| 6956 | return -EPERM; | ||
| 6957 | } | ||
| 6958 | |||
| 6959 | rc = volume_get_status(&s); | ||
| 6960 | if (rc < 0) | ||
| 6961 | return rc; | ||
| 6962 | |||
| 6963 | new_level = s & TP_EC_AUDIO_LVL_MSK; | ||
| 6964 | new_mute = s & TP_EC_AUDIO_MUTESW_MSK; | ||
| 6965 | |||
| 6966 | while ((cmd = next_cmd(&buf))) { | ||
| 6967 | if (!tp_features.mixer_no_level_control) { | ||
| 6968 | if (strlencmp(cmd, "up") == 0) { | ||
| 6969 | if (new_mute) | ||
| 6970 | new_mute = 0; | ||
| 6971 | else if (new_level < TP_EC_VOLUME_MAX) | ||
| 6972 | new_level++; | ||
| 6973 | continue; | ||
| 6974 | } else if (strlencmp(cmd, "down") == 0) { | ||
| 6975 | if (new_mute) | ||
| 6976 | new_mute = 0; | ||
| 6977 | else if (new_level > 0) | ||
| 6978 | new_level--; | ||
| 6979 | continue; | ||
| 6980 | } else if (sscanf(cmd, "level %u", &l) == 1 && | ||
| 6981 | l >= 0 && l <= TP_EC_VOLUME_MAX) { | ||
| 6982 | new_level = l; | ||
| 6983 | continue; | ||
| 6984 | } | ||
| 6985 | } | ||
| 6986 | if (strlencmp(cmd, "mute") == 0) | ||
| 6987 | new_mute = TP_EC_AUDIO_MUTESW_MSK; | ||
| 6988 | else if (strlencmp(cmd, "unmute") == 0) | ||
| 6989 | new_mute = 0; | ||
| 6990 | else | ||
| 6991 | return -EINVAL; | ||
| 6992 | } | ||
| 6993 | |||
| 6994 | if (tp_features.mixer_no_level_control) { | ||
| 6995 | tpacpi_disclose_usertask("procfs volume", "%smute\n", | ||
| 6996 | new_mute ? "" : "un"); | ||
| 6997 | rc = volume_set_mute(!!new_mute); | ||
| 6998 | } else { | ||
| 6999 | tpacpi_disclose_usertask("procfs volume", | ||
| 7000 | "%smute and set level to %d\n", | ||
| 7001 | new_mute ? "" : "un", new_level); | ||
| 7002 | rc = volume_set_status(new_mute | new_level); | ||
| 7003 | } | ||
| 7004 | volume_alsa_notify_change(); | ||
| 7005 | |||
| 7006 | return (rc == -EINTR) ? -ERESTARTSYS : rc; | ||
| 7007 | } | ||
| 7008 | |||
| 6430 | static struct ibm_struct volume_driver_data = { | 7009 | static struct ibm_struct volume_driver_data = { |
| 6431 | .name = "volume", | 7010 | .name = "volume", |
| 6432 | .read = volume_read, | 7011 | .read = volume_read, |
| 6433 | .write = volume_write, | 7012 | .write = volume_write, |
| 7013 | .exit = volume_exit, | ||
| 7014 | .suspend = volume_suspend, | ||
| 7015 | .resume = volume_resume, | ||
| 7016 | .shutdown = volume_shutdown, | ||
| 6434 | }; | 7017 | }; |
| 6435 | 7018 | ||
| 6436 | /************************************************************************* | 7019 | /************************************************************************* |
| @@ -7507,9 +8090,8 @@ static void fan_resume(void) | |||
| 7507 | } | 8090 | } |
| 7508 | } | 8091 | } |
| 7509 | 8092 | ||
| 7510 | static int fan_read(char *p) | 8093 | static int fan_read(struct seq_file *m) |
| 7511 | { | 8094 | { |
| 7512 | int len = 0; | ||
| 7513 | int rc; | 8095 | int rc; |
| 7514 | u8 status; | 8096 | u8 status; |
| 7515 | unsigned int speed = 0; | 8097 | unsigned int speed = 0; |
| @@ -7521,7 +8103,7 @@ static int fan_read(char *p) | |||
| 7521 | if (rc < 0) | 8103 | if (rc < 0) |
| 7522 | return rc; | 8104 | return rc; |
| 7523 | 8105 | ||
| 7524 | len += sprintf(p + len, "status:\t\t%s\n" | 8106 | seq_printf(m, "status:\t\t%s\n" |
| 7525 | "level:\t\t%d\n", | 8107 | "level:\t\t%d\n", |
| 7526 | (status != 0) ? "enabled" : "disabled", status); | 8108 | (status != 0) ? "enabled" : "disabled", status); |
| 7527 | break; | 8109 | break; |
| @@ -7532,54 +8114,54 @@ static int fan_read(char *p) | |||
| 7532 | if (rc < 0) | 8114 | if (rc < 0) |
| 7533 | return rc; | 8115 | return rc; |
| 7534 | 8116 | ||
| 7535 | len += sprintf(p + len, "status:\t\t%s\n", | 8117 | seq_printf(m, "status:\t\t%s\n", |
| 7536 | (status != 0) ? "enabled" : "disabled"); | 8118 | (status != 0) ? "enabled" : "disabled"); |
| 7537 | 8119 | ||
| 7538 | rc = fan_get_speed(&speed); | 8120 | rc = fan_get_speed(&speed); |
| 7539 | if (rc < 0) | 8121 | if (rc < 0) |
| 7540 | return rc; | 8122 | return rc; |
| 7541 | 8123 | ||
| 7542 | len += sprintf(p + len, "speed:\t\t%d\n", speed); | 8124 | seq_printf(m, "speed:\t\t%d\n", speed); |
| 7543 | 8125 | ||
| 7544 | if (status & TP_EC_FAN_FULLSPEED) | 8126 | if (status & TP_EC_FAN_FULLSPEED) |
| 7545 | /* Disengaged mode takes precedence */ | 8127 | /* Disengaged mode takes precedence */ |
| 7546 | len += sprintf(p + len, "level:\t\tdisengaged\n"); | 8128 | seq_printf(m, "level:\t\tdisengaged\n"); |
| 7547 | else if (status & TP_EC_FAN_AUTO) | 8129 | else if (status & TP_EC_FAN_AUTO) |
| 7548 | len += sprintf(p + len, "level:\t\tauto\n"); | 8130 | seq_printf(m, "level:\t\tauto\n"); |
| 7549 | else | 8131 | else |
| 7550 | len += sprintf(p + len, "level:\t\t%d\n", status); | 8132 | seq_printf(m, "level:\t\t%d\n", status); |
| 7551 | break; | 8133 | break; |
| 7552 | 8134 | ||
| 7553 | case TPACPI_FAN_NONE: | 8135 | case TPACPI_FAN_NONE: |
| 7554 | default: | 8136 | default: |
| 7555 | len += sprintf(p + len, "status:\t\tnot supported\n"); | 8137 | seq_printf(m, "status:\t\tnot supported\n"); |
| 7556 | } | 8138 | } |
| 7557 | 8139 | ||
| 7558 | if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { | 8140 | if (fan_control_commands & TPACPI_FAN_CMD_LEVEL) { |
| 7559 | len += sprintf(p + len, "commands:\tlevel <level>"); | 8141 | seq_printf(m, "commands:\tlevel <level>"); |
| 7560 | 8142 | ||
| 7561 | switch (fan_control_access_mode) { | 8143 | switch (fan_control_access_mode) { |
| 7562 | case TPACPI_FAN_WR_ACPI_SFAN: | 8144 | case TPACPI_FAN_WR_ACPI_SFAN: |
| 7563 | len += sprintf(p + len, " (<level> is 0-7)\n"); | 8145 | seq_printf(m, " (<level> is 0-7)\n"); |
| 7564 | break; | 8146 | break; |
| 7565 | 8147 | ||
| 7566 | default: | 8148 | default: |
| 7567 | len += sprintf(p + len, " (<level> is 0-7, " | 8149 | seq_printf(m, " (<level> is 0-7, " |
| 7568 | "auto, disengaged, full-speed)\n"); | 8150 | "auto, disengaged, full-speed)\n"); |
| 7569 | break; | 8151 | break; |
| 7570 | } | 8152 | } |
| 7571 | } | 8153 | } |
| 7572 | 8154 | ||
| 7573 | if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) | 8155 | if (fan_control_commands & TPACPI_FAN_CMD_ENABLE) |
| 7574 | len += sprintf(p + len, "commands:\tenable, disable\n" | 8156 | seq_printf(m, "commands:\tenable, disable\n" |
| 7575 | "commands:\twatchdog <timeout> (<timeout> " | 8157 | "commands:\twatchdog <timeout> (<timeout> " |
| 7576 | "is 0 (off), 1-120 (seconds))\n"); | 8158 | "is 0 (off), 1-120 (seconds))\n"); |
| 7577 | 8159 | ||
| 7578 | if (fan_control_commands & TPACPI_FAN_CMD_SPEED) | 8160 | if (fan_control_commands & TPACPI_FAN_CMD_SPEED) |
| 7579 | len += sprintf(p + len, "commands:\tspeed <speed>" | 8161 | seq_printf(m, "commands:\tspeed <speed>" |
| 7580 | " (<speed> is 0-65535)\n"); | 8162 | " (<speed> is 0-65535)\n"); |
| 7581 | 8163 | ||
| 7582 | return len; | 8164 | return 0; |
| 7583 | } | 8165 | } |
| 7584 | 8166 | ||
| 7585 | static int fan_write_cmd_level(const char *cmd, int *rc) | 8167 | static int fan_write_cmd_level(const char *cmd, int *rc) |
| @@ -7721,10 +8303,23 @@ static struct ibm_struct fan_driver_data = { | |||
| 7721 | */ | 8303 | */ |
| 7722 | static void tpacpi_driver_event(const unsigned int hkey_event) | 8304 | static void tpacpi_driver_event(const unsigned int hkey_event) |
| 7723 | { | 8305 | { |
| 8306 | if (ibm_backlight_device) { | ||
| 8307 | switch (hkey_event) { | ||
| 8308 | case TP_HKEY_EV_BRGHT_UP: | ||
| 8309 | case TP_HKEY_EV_BRGHT_DOWN: | ||
| 8310 | tpacpi_brightness_notify_change(); | ||
| 8311 | } | ||
| 8312 | } | ||
| 8313 | if (alsa_card) { | ||
| 8314 | switch (hkey_event) { | ||
| 8315 | case TP_HKEY_EV_VOL_UP: | ||
| 8316 | case TP_HKEY_EV_VOL_DOWN: | ||
| 8317 | case TP_HKEY_EV_VOL_MUTE: | ||
| 8318 | volume_alsa_notify_change(); | ||
| 8319 | } | ||
| 8320 | } | ||
| 7724 | } | 8321 | } |
| 7725 | 8322 | ||
| 7726 | |||
| 7727 | |||
| 7728 | static void hotkey_driver_event(const unsigned int scancode) | 8323 | static void hotkey_driver_event(const unsigned int scancode) |
| 7729 | { | 8324 | { |
| 7730 | tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); | 8325 | tpacpi_driver_event(TP_HKEY_EV_HOTKEY_BASE + scancode); |
| @@ -7853,19 +8448,19 @@ static int __init ibm_init(struct ibm_init_struct *iibm) | |||
| 7853 | "%s installed\n", ibm->name); | 8448 | "%s installed\n", ibm->name); |
| 7854 | 8449 | ||
| 7855 | if (ibm->read) { | 8450 | if (ibm->read) { |
| 7856 | entry = create_proc_entry(ibm->name, | 8451 | mode_t mode; |
| 7857 | S_IFREG | S_IRUGO | S_IWUSR, | 8452 | |
| 7858 | proc_dir); | 8453 | mode = S_IRUGO; |
| 8454 | if (ibm->write) | ||
| 8455 | mode |= S_IWUSR; | ||
| 8456 | entry = proc_create_data(ibm->name, mode, proc_dir, | ||
| 8457 | &dispatch_proc_fops, ibm); | ||
| 7859 | if (!entry) { | 8458 | if (!entry) { |
| 7860 | printk(TPACPI_ERR "unable to create proc entry %s\n", | 8459 | printk(TPACPI_ERR "unable to create proc entry %s\n", |
| 7861 | ibm->name); | 8460 | ibm->name); |
| 7862 | ret = -ENODEV; | 8461 | ret = -ENODEV; |
| 7863 | goto err_out; | 8462 | goto err_out; |
| 7864 | } | 8463 | } |
| 7865 | entry->data = ibm; | ||
| 7866 | entry->read_proc = &dispatch_procfs_read; | ||
| 7867 | if (ibm->write) | ||
| 7868 | entry->write_proc = &dispatch_procfs_write; | ||
| 7869 | ibm->flags.proc_created = 1; | 8464 | ibm->flags.proc_created = 1; |
| 7870 | } | 8465 | } |
| 7871 | 8466 | ||
| @@ -8077,6 +8672,7 @@ static struct ibm_init_struct ibms_init[] __initdata = { | |||
| 8077 | .data = &brightness_driver_data, | 8672 | .data = &brightness_driver_data, |
| 8078 | }, | 8673 | }, |
| 8079 | { | 8674 | { |
| 8675 | .init = volume_init, | ||
| 8080 | .data = &volume_driver_data, | 8676 | .data = &volume_driver_data, |
| 8081 | }, | 8677 | }, |
| 8082 | { | 8678 | { |
| @@ -8112,36 +8708,59 @@ static int __init set_ibm_param(const char *val, struct kernel_param *kp) | |||
| 8112 | return -EINVAL; | 8708 | return -EINVAL; |
| 8113 | } | 8709 | } |
| 8114 | 8710 | ||
| 8115 | module_param(experimental, int, 0); | 8711 | module_param(experimental, int, 0444); |
| 8116 | MODULE_PARM_DESC(experimental, | 8712 | MODULE_PARM_DESC(experimental, |
| 8117 | "Enables experimental features when non-zero"); | 8713 | "Enables experimental features when non-zero"); |
| 8118 | 8714 | ||
| 8119 | module_param_named(debug, dbg_level, uint, 0); | 8715 | module_param_named(debug, dbg_level, uint, 0); |
| 8120 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); | 8716 | MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); |
| 8121 | 8717 | ||
| 8122 | module_param(force_load, bool, 0); | 8718 | module_param(force_load, bool, 0444); |
| 8123 | MODULE_PARM_DESC(force_load, | 8719 | MODULE_PARM_DESC(force_load, |
| 8124 | "Attempts to load the driver even on a " | 8720 | "Attempts to load the driver even on a " |
| 8125 | "mis-identified ThinkPad when true"); | 8721 | "mis-identified ThinkPad when true"); |
| 8126 | 8722 | ||
| 8127 | module_param_named(fan_control, fan_control_allowed, bool, 0); | 8723 | module_param_named(fan_control, fan_control_allowed, bool, 0444); |
| 8128 | MODULE_PARM_DESC(fan_control, | 8724 | MODULE_PARM_DESC(fan_control, |
| 8129 | "Enables setting fan parameters features when true"); | 8725 | "Enables setting fan parameters features when true"); |
| 8130 | 8726 | ||
| 8131 | module_param_named(brightness_mode, brightness_mode, uint, 0); | 8727 | module_param_named(brightness_mode, brightness_mode, uint, 0444); |
| 8132 | MODULE_PARM_DESC(brightness_mode, | 8728 | MODULE_PARM_DESC(brightness_mode, |
| 8133 | "Selects brightness control strategy: " | 8729 | "Selects brightness control strategy: " |
| 8134 | "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); | 8730 | "0=auto, 1=EC, 2=UCMS, 3=EC+NVRAM"); |
| 8135 | 8731 | ||
| 8136 | module_param(brightness_enable, uint, 0); | 8732 | module_param(brightness_enable, uint, 0444); |
| 8137 | MODULE_PARM_DESC(brightness_enable, | 8733 | MODULE_PARM_DESC(brightness_enable, |
| 8138 | "Enables backlight control when 1, disables when 0"); | 8734 | "Enables backlight control when 1, disables when 0"); |
| 8139 | 8735 | ||
| 8140 | module_param(hotkey_report_mode, uint, 0); | 8736 | module_param(hotkey_report_mode, uint, 0444); |
| 8141 | MODULE_PARM_DESC(hotkey_report_mode, | 8737 | MODULE_PARM_DESC(hotkey_report_mode, |
| 8142 | "used for backwards compatibility with userspace, " | 8738 | "used for backwards compatibility with userspace, " |
| 8143 | "see documentation"); | 8739 | "see documentation"); |
| 8144 | 8740 | ||
| 8741 | module_param_named(volume_mode, volume_mode, uint, 0444); | ||
| 8742 | MODULE_PARM_DESC(volume_mode, | ||
| 8743 | "Selects volume control strategy: " | ||
| 8744 | "0=auto, 1=EC, 2=N/A, 3=EC+NVRAM"); | ||
| 8745 | |||
| 8746 | module_param_named(volume_capabilities, volume_capabilities, uint, 0444); | ||
| 8747 | MODULE_PARM_DESC(volume_capabilities, | ||
| 8748 | "Selects the mixer capabilites: " | ||
| 8749 | "0=auto, 1=volume and mute, 2=mute only"); | ||
| 8750 | |||
| 8751 | module_param_named(volume_control, volume_control_allowed, bool, 0444); | ||
| 8752 | MODULE_PARM_DESC(volume_control, | ||
| 8753 | "Enables software override for the console audio " | ||
| 8754 | "control when true"); | ||
| 8755 | |||
| 8756 | /* ALSA module API parameters */ | ||
| 8757 | module_param_named(index, alsa_index, int, 0444); | ||
| 8758 | MODULE_PARM_DESC(index, "ALSA index for the ACPI EC Mixer"); | ||
| 8759 | module_param_named(id, alsa_id, charp, 0444); | ||
| 8760 | MODULE_PARM_DESC(id, "ALSA id for the ACPI EC Mixer"); | ||
| 8761 | module_param_named(enable, alsa_enable, bool, 0444); | ||
| 8762 | MODULE_PARM_DESC(enable, "Enable the ALSA interface for the ACPI EC Mixer"); | ||
| 8763 | |||
| 8145 | #define TPACPI_PARAM(feature) \ | 8764 | #define TPACPI_PARAM(feature) \ |
| 8146 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ | 8765 | module_param_call(feature, set_ibm_param, NULL, NULL, 0); \ |
| 8147 | MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ | 8766 | MODULE_PARM_DESC(feature, "Simulates thinkpad-acpi procfs command " \ |
| @@ -8160,25 +8779,25 @@ TPACPI_PARAM(volume); | |||
| 8160 | TPACPI_PARAM(fan); | 8779 | TPACPI_PARAM(fan); |
| 8161 | 8780 | ||
| 8162 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES | 8781 | #ifdef CONFIG_THINKPAD_ACPI_DEBUGFACILITIES |
| 8163 | module_param(dbg_wlswemul, uint, 0); | 8782 | module_param(dbg_wlswemul, uint, 0444); |
| 8164 | MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation"); | 8783 | MODULE_PARM_DESC(dbg_wlswemul, "Enables WLSW emulation"); |
| 8165 | module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0); | 8784 | module_param_named(wlsw_state, tpacpi_wlsw_emulstate, bool, 0); |
| 8166 | MODULE_PARM_DESC(wlsw_state, | 8785 | MODULE_PARM_DESC(wlsw_state, |
| 8167 | "Initial state of the emulated WLSW switch"); | 8786 | "Initial state of the emulated WLSW switch"); |
| 8168 | 8787 | ||
| 8169 | module_param(dbg_bluetoothemul, uint, 0); | 8788 | module_param(dbg_bluetoothemul, uint, 0444); |
| 8170 | MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation"); | 8789 | MODULE_PARM_DESC(dbg_bluetoothemul, "Enables bluetooth switch emulation"); |
| 8171 | module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0); | 8790 | module_param_named(bluetooth_state, tpacpi_bluetooth_emulstate, bool, 0); |
| 8172 | MODULE_PARM_DESC(bluetooth_state, | 8791 | MODULE_PARM_DESC(bluetooth_state, |
| 8173 | "Initial state of the emulated bluetooth switch"); | 8792 | "Initial state of the emulated bluetooth switch"); |
| 8174 | 8793 | ||
| 8175 | module_param(dbg_wwanemul, uint, 0); | 8794 | module_param(dbg_wwanemul, uint, 0444); |
| 8176 | MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation"); | 8795 | MODULE_PARM_DESC(dbg_wwanemul, "Enables WWAN switch emulation"); |
| 8177 | module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0); | 8796 | module_param_named(wwan_state, tpacpi_wwan_emulstate, bool, 0); |
| 8178 | MODULE_PARM_DESC(wwan_state, | 8797 | MODULE_PARM_DESC(wwan_state, |
| 8179 | "Initial state of the emulated WWAN switch"); | 8798 | "Initial state of the emulated WWAN switch"); |
| 8180 | 8799 | ||
| 8181 | module_param(dbg_uwbemul, uint, 0); | 8800 | module_param(dbg_uwbemul, uint, 0444); |
| 8182 | MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation"); | 8801 | MODULE_PARM_DESC(dbg_uwbemul, "Enables UWB switch emulation"); |
| 8183 | module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0); | 8802 | module_param_named(uwb_state, tpacpi_uwb_emulstate, bool, 0); |
| 8184 | MODULE_PARM_DESC(uwb_state, | 8803 | MODULE_PARM_DESC(uwb_state, |
| @@ -8371,6 +8990,7 @@ static int __init thinkpad_acpi_module_init(void) | |||
| 8371 | PCI_VENDOR_ID_IBM; | 8990 | PCI_VENDOR_ID_IBM; |
| 8372 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; | 8991 | tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT; |
| 8373 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; | 8992 | tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION; |
| 8993 | tpacpi_inputdev->dev.parent = &tpacpi_pdev->dev; | ||
| 8374 | } | 8994 | } |
| 8375 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { | 8995 | for (i = 0; i < ARRAY_SIZE(ibms_init); i++) { |
| 8376 | ret = ibm_init(&ibms_init[i]); | 8996 | ret = ibm_init(&ibms_init[i]); |
diff --git a/drivers/platform/x86/toshiba_bluetooth.c b/drivers/platform/x86/toshiba_bluetooth.c new file mode 100644 index 000000000000..a350418e87ea --- /dev/null +++ b/drivers/platform/x86/toshiba_bluetooth.c | |||
| @@ -0,0 +1,144 @@ | |||
| 1 | /* | ||
| 2 | * Toshiba Bluetooth Enable Driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2009 Jes Sorensen <Jes.Sorensen@gmail.com> | ||
| 5 | * | ||
| 6 | * Thanks to Matthew Garrett for background info on ACPI innards which | ||
| 7 | * normal people aren't meant to understand :-) | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * Note the Toshiba Bluetooth RFKill switch seems to be a strange | ||
| 14 | * fish. It only provides a BT event when the switch is flipped to | ||
| 15 | * the 'on' position. When flipping it to 'off', the USB device is | ||
| 16 | * simply pulled away underneath us, without any BT event being | ||
| 17 | * delivered. | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/kernel.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/init.h> | ||
| 23 | #include <linux/types.h> | ||
| 24 | #include <acpi/acpi_bus.h> | ||
| 25 | #include <acpi/acpi_drivers.h> | ||
| 26 | |||
| 27 | MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@gmail.com>"); | ||
| 28 | MODULE_DESCRIPTION("Toshiba Laptop ACPI Bluetooth Enable Driver"); | ||
| 29 | MODULE_LICENSE("GPL"); | ||
| 30 | |||
| 31 | |||
| 32 | static int toshiba_bt_rfkill_add(struct acpi_device *device); | ||
| 33 | static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type); | ||
| 34 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event); | ||
| 35 | static int toshiba_bt_resume(struct acpi_device *device); | ||
| 36 | |||
| 37 | static const struct acpi_device_id bt_device_ids[] = { | ||
| 38 | { "TOS6205", 0}, | ||
| 39 | { "", 0}, | ||
| 40 | }; | ||
| 41 | MODULE_DEVICE_TABLE(acpi, bt_device_ids); | ||
| 42 | |||
| 43 | static struct acpi_driver toshiba_bt_rfkill_driver = { | ||
| 44 | .name = "Toshiba BT", | ||
| 45 | .class = "Toshiba", | ||
| 46 | .ids = bt_device_ids, | ||
| 47 | .ops = { | ||
| 48 | .add = toshiba_bt_rfkill_add, | ||
| 49 | .remove = toshiba_bt_rfkill_remove, | ||
| 50 | .notify = toshiba_bt_rfkill_notify, | ||
| 51 | .resume = toshiba_bt_resume, | ||
| 52 | }, | ||
| 53 | .owner = THIS_MODULE, | ||
| 54 | }; | ||
| 55 | |||
| 56 | |||
| 57 | static int toshiba_bluetooth_enable(acpi_handle handle) | ||
| 58 | { | ||
| 59 | acpi_status res1, res2; | ||
| 60 | acpi_integer result; | ||
| 61 | |||
| 62 | /* | ||
| 63 | * Query ACPI to verify RFKill switch is set to 'on'. | ||
| 64 | * If not, we return silently, no need to report it as | ||
| 65 | * an error. | ||
| 66 | */ | ||
| 67 | res1 = acpi_evaluate_integer(handle, "BTST", NULL, &result); | ||
| 68 | if (ACPI_FAILURE(res1)) | ||
| 69 | return res1; | ||
| 70 | if (!(result & 0x01)) | ||
| 71 | return 0; | ||
| 72 | |||
| 73 | printk(KERN_INFO "toshiba_bluetooth: Re-enabling Toshiba Bluetooth\n"); | ||
| 74 | res1 = acpi_evaluate_object(handle, "AUSB", NULL, NULL); | ||
| 75 | res2 = acpi_evaluate_object(handle, "BTPO", NULL, NULL); | ||
| 76 | if (!ACPI_FAILURE(res1) || !ACPI_FAILURE(res2)) | ||
| 77 | return 0; | ||
| 78 | |||
| 79 | printk(KERN_WARNING "toshiba_bluetooth: Failed to re-enable " | ||
| 80 | "Toshiba Bluetooth\n"); | ||
| 81 | |||
| 82 | return -ENODEV; | ||
| 83 | } | ||
| 84 | |||
| 85 | static void toshiba_bt_rfkill_notify(struct acpi_device *device, u32 event) | ||
| 86 | { | ||
| 87 | toshiba_bluetooth_enable(device->handle); | ||
| 88 | } | ||
| 89 | |||
| 90 | static int toshiba_bt_resume(struct acpi_device *device) | ||
| 91 | { | ||
| 92 | return toshiba_bluetooth_enable(device->handle); | ||
| 93 | } | ||
| 94 | |||
| 95 | static int toshiba_bt_rfkill_add(struct acpi_device *device) | ||
| 96 | { | ||
| 97 | acpi_status status; | ||
| 98 | acpi_integer bt_present; | ||
| 99 | int result = -ENODEV; | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Some Toshiba laptops may have a fake TOS6205 device in | ||
| 103 | * their ACPI BIOS, so query the _STA method to see if there | ||
| 104 | * is really anything there, before trying to enable it. | ||
| 105 | */ | ||
| 106 | status = acpi_evaluate_integer(device->handle, "_STA", NULL, | ||
| 107 | &bt_present); | ||
| 108 | |||
| 109 | if (!ACPI_FAILURE(status) && bt_present) { | ||
| 110 | printk(KERN_INFO "Detected Toshiba ACPI Bluetooth device - " | ||
| 111 | "installing RFKill handler\n"); | ||
| 112 | result = toshiba_bluetooth_enable(device->handle); | ||
| 113 | } | ||
| 114 | |||
| 115 | return result; | ||
| 116 | } | ||
| 117 | |||
| 118 | static int __init toshiba_bt_rfkill_init(void) | ||
| 119 | { | ||
| 120 | int result; | ||
| 121 | |||
| 122 | result = acpi_bus_register_driver(&toshiba_bt_rfkill_driver); | ||
| 123 | if (result < 0) { | ||
| 124 | ACPI_DEBUG_PRINT((ACPI_DB_ERROR, | ||
| 125 | "Error registering driver\n")); | ||
| 126 | return result; | ||
| 127 | } | ||
| 128 | |||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | static int toshiba_bt_rfkill_remove(struct acpi_device *device, int type) | ||
| 133 | { | ||
| 134 | /* clean up */ | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | static void __exit toshiba_bt_rfkill_exit(void) | ||
| 139 | { | ||
| 140 | acpi_bus_unregister_driver(&toshiba_bt_rfkill_driver); | ||
| 141 | } | ||
| 142 | |||
| 143 | module_init(toshiba_bt_rfkill_init); | ||
| 144 | module_exit(toshiba_bt_rfkill_exit); | ||
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c index 177f8d767df4..e425a868cd3a 100644 --- a/drivers/platform/x86/wmi.c +++ b/drivers/platform/x86/wmi.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
| 31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
| 32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
| 33 | #include <linux/device.h> | ||
| 33 | #include <linux/list.h> | 34 | #include <linux/list.h> |
| 34 | #include <linux/acpi.h> | 35 | #include <linux/acpi.h> |
| 35 | #include <acpi/acpi_bus.h> | 36 | #include <acpi/acpi_bus.h> |
| @@ -65,6 +66,7 @@ struct wmi_block { | |||
| 65 | acpi_handle handle; | 66 | acpi_handle handle; |
| 66 | wmi_notify_handler handler; | 67 | wmi_notify_handler handler; |
| 67 | void *handler_data; | 68 | void *handler_data; |
| 69 | struct device *dev; | ||
| 68 | }; | 70 | }; |
| 69 | 71 | ||
| 70 | static struct wmi_block wmi_blocks; | 72 | static struct wmi_block wmi_blocks; |
| @@ -195,6 +197,34 @@ static bool wmi_parse_guid(const u8 *src, u8 *dest) | |||
| 195 | return true; | 197 | return true; |
| 196 | } | 198 | } |
| 197 | 199 | ||
| 200 | /* | ||
| 201 | * Convert a raw GUID to the ACII string representation | ||
| 202 | */ | ||
| 203 | static int wmi_gtoa(const char *in, char *out) | ||
| 204 | { | ||
| 205 | int i; | ||
| 206 | |||
| 207 | for (i = 3; i >= 0; i--) | ||
| 208 | out += sprintf(out, "%02X", in[i] & 0xFF); | ||
| 209 | |||
| 210 | out += sprintf(out, "-"); | ||
| 211 | out += sprintf(out, "%02X", in[5] & 0xFF); | ||
| 212 | out += sprintf(out, "%02X", in[4] & 0xFF); | ||
| 213 | out += sprintf(out, "-"); | ||
| 214 | out += sprintf(out, "%02X", in[7] & 0xFF); | ||
| 215 | out += sprintf(out, "%02X", in[6] & 0xFF); | ||
| 216 | out += sprintf(out, "-"); | ||
| 217 | out += sprintf(out, "%02X", in[8] & 0xFF); | ||
| 218 | out += sprintf(out, "%02X", in[9] & 0xFF); | ||
| 219 | out += sprintf(out, "-"); | ||
| 220 | |||
| 221 | for (i = 10; i <= 15; i++) | ||
| 222 | out += sprintf(out, "%02X", in[i] & 0xFF); | ||
| 223 | |||
| 224 | out = '\0'; | ||
| 225 | return 0; | ||
| 226 | } | ||
| 227 | |||
| 198 | static bool find_guid(const char *guid_string, struct wmi_block **out) | 228 | static bool find_guid(const char *guid_string, struct wmi_block **out) |
| 199 | { | 229 | { |
| 200 | char tmp[16], guid_input[16]; | 230 | char tmp[16], guid_input[16]; |
| @@ -555,6 +585,138 @@ bool wmi_has_guid(const char *guid_string) | |||
| 555 | EXPORT_SYMBOL_GPL(wmi_has_guid); | 585 | EXPORT_SYMBOL_GPL(wmi_has_guid); |
| 556 | 586 | ||
| 557 | /* | 587 | /* |
| 588 | * sysfs interface | ||
| 589 | */ | ||
| 590 | static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, | ||
| 591 | char *buf) | ||
| 592 | { | ||
| 593 | char guid_string[37]; | ||
| 594 | struct wmi_block *wblock; | ||
| 595 | |||
| 596 | wblock = dev_get_drvdata(dev); | ||
| 597 | if (!wblock) | ||
| 598 | return -ENOMEM; | ||
| 599 | |||
| 600 | wmi_gtoa(wblock->gblock.guid, guid_string); | ||
| 601 | |||
| 602 | return sprintf(buf, "wmi:%s\n", guid_string); | ||
| 603 | } | ||
| 604 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); | ||
| 605 | |||
| 606 | static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
| 607 | { | ||
| 608 | char guid_string[37]; | ||
| 609 | |||
| 610 | struct wmi_block *wblock; | ||
| 611 | |||
| 612 | if (add_uevent_var(env, "MODALIAS=")) | ||
| 613 | return -ENOMEM; | ||
| 614 | |||
| 615 | wblock = dev_get_drvdata(dev); | ||
| 616 | if (!wblock) | ||
| 617 | return -ENOMEM; | ||
| 618 | |||
| 619 | wmi_gtoa(wblock->gblock.guid, guid_string); | ||
| 620 | |||
| 621 | strcpy(&env->buf[env->buflen - 1], "wmi:"); | ||
| 622 | memcpy(&env->buf[env->buflen - 1 + 4], guid_string, 36); | ||
| 623 | env->buflen += 40; | ||
| 624 | |||
| 625 | return 0; | ||
| 626 | } | ||
| 627 | |||
| 628 | static void wmi_dev_free(struct device *dev) | ||
| 629 | { | ||
| 630 | kfree(dev); | ||
| 631 | } | ||
| 632 | |||
| 633 | static struct class wmi_class = { | ||
| 634 | .name = "wmi", | ||
| 635 | .dev_release = wmi_dev_free, | ||
| 636 | .dev_uevent = wmi_dev_uevent, | ||
| 637 | }; | ||
| 638 | |||
| 639 | static int wmi_create_devs(void) | ||
| 640 | { | ||
| 641 | int result; | ||
| 642 | char guid_string[37]; | ||
| 643 | struct guid_block *gblock; | ||
| 644 | struct wmi_block *wblock; | ||
| 645 | struct list_head *p; | ||
| 646 | struct device *guid_dev; | ||
| 647 | |||
| 648 | /* Create devices for all the GUIDs */ | ||
| 649 | list_for_each(p, &wmi_blocks.list) { | ||
| 650 | wblock = list_entry(p, struct wmi_block, list); | ||
| 651 | |||
| 652 | guid_dev = kzalloc(sizeof(struct device), GFP_KERNEL); | ||
| 653 | if (!guid_dev) | ||
| 654 | return -ENOMEM; | ||
| 655 | |||
| 656 | wblock->dev = guid_dev; | ||
| 657 | |||
| 658 | guid_dev->class = &wmi_class; | ||
| 659 | dev_set_drvdata(guid_dev, wblock); | ||
| 660 | |||
| 661 | gblock = &wblock->gblock; | ||
| 662 | |||
| 663 | wmi_gtoa(gblock->guid, guid_string); | ||
| 664 | dev_set_name(guid_dev, guid_string); | ||
| 665 | |||
| 666 | result = device_register(guid_dev); | ||
| 667 | if (result) | ||
| 668 | return result; | ||
| 669 | |||
| 670 | result = device_create_file(guid_dev, &dev_attr_modalias); | ||
| 671 | if (result) | ||
| 672 | return result; | ||
| 673 | } | ||
| 674 | |||
| 675 | return 0; | ||
| 676 | } | ||
| 677 | |||
| 678 | static void wmi_remove_devs(void) | ||
| 679 | { | ||
| 680 | struct guid_block *gblock; | ||
| 681 | struct wmi_block *wblock; | ||
| 682 | struct list_head *p; | ||
| 683 | struct device *guid_dev; | ||
| 684 | |||
| 685 | /* Delete devices for all the GUIDs */ | ||
| 686 | list_for_each(p, &wmi_blocks.list) { | ||
| 687 | wblock = list_entry(p, struct wmi_block, list); | ||
| 688 | |||
| 689 | guid_dev = wblock->dev; | ||
| 690 | gblock = &wblock->gblock; | ||
| 691 | |||
| 692 | device_remove_file(guid_dev, &dev_attr_modalias); | ||
| 693 | |||
| 694 | device_unregister(guid_dev); | ||
| 695 | } | ||
| 696 | } | ||
| 697 | |||
| 698 | static void wmi_class_exit(void) | ||
| 699 | { | ||
| 700 | wmi_remove_devs(); | ||
| 701 | class_unregister(&wmi_class); | ||
| 702 | } | ||
| 703 | |||
| 704 | static int wmi_class_init(void) | ||
| 705 | { | ||
| 706 | int ret; | ||
| 707 | |||
| 708 | ret = class_register(&wmi_class); | ||
| 709 | if (ret) | ||
| 710 | return ret; | ||
| 711 | |||
| 712 | ret = wmi_create_devs(); | ||
| 713 | if (ret) | ||
| 714 | wmi_class_exit(); | ||
| 715 | |||
| 716 | return ret; | ||
| 717 | } | ||
| 718 | |||
| 719 | /* | ||
| 558 | * Parse the _WDG method for the GUID data blocks | 720 | * Parse the _WDG method for the GUID data blocks |
| 559 | */ | 721 | */ |
| 560 | static __init acpi_status parse_wdg(acpi_handle handle) | 722 | static __init acpi_status parse_wdg(acpi_handle handle) |
| @@ -709,10 +871,17 @@ static int __init acpi_wmi_init(void) | |||
| 709 | 871 | ||
| 710 | if (result < 0) { | 872 | if (result < 0) { |
| 711 | printk(KERN_INFO PREFIX "Error loading mapper\n"); | 873 | printk(KERN_INFO PREFIX "Error loading mapper\n"); |
| 712 | } else { | 874 | return -ENODEV; |
| 713 | printk(KERN_INFO PREFIX "Mapper loaded\n"); | 875 | } |
| 876 | |||
| 877 | result = wmi_class_init(); | ||
| 878 | if (result) { | ||
| 879 | acpi_bus_unregister_driver(&acpi_wmi_driver); | ||
| 880 | return result; | ||
| 714 | } | 881 | } |
| 715 | 882 | ||
| 883 | printk(KERN_INFO PREFIX "Mapper loaded\n"); | ||
| 884 | |||
| 716 | return result; | 885 | return result; |
| 717 | } | 886 | } |
| 718 | 887 | ||
| @@ -721,6 +890,8 @@ static void __exit acpi_wmi_exit(void) | |||
| 721 | struct list_head *p, *tmp; | 890 | struct list_head *p, *tmp; |
| 722 | struct wmi_block *wblock; | 891 | struct wmi_block *wblock; |
| 723 | 892 | ||
| 893 | wmi_class_exit(); | ||
| 894 | |||
| 724 | acpi_bus_unregister_driver(&acpi_wmi_driver); | 895 | acpi_bus_unregister_driver(&acpi_wmi_driver); |
| 725 | 896 | ||
| 726 | list_for_each_safe(p, tmp, &wmi_blocks.list) { | 897 | list_for_each_safe(p, tmp, &wmi_blocks.list) { |
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index 83b8b5ac49c9..5314bf630bc4 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c | |||
| @@ -80,7 +80,8 @@ static int pnpacpi_get_resources(struct pnp_dev *dev) | |||
| 80 | 80 | ||
| 81 | static int pnpacpi_set_resources(struct pnp_dev *dev) | 81 | static int pnpacpi_set_resources(struct pnp_dev *dev) |
| 82 | { | 82 | { |
| 83 | acpi_handle handle = dev->data; | 83 | struct acpi_device *acpi_dev = dev->data; |
| 84 | acpi_handle handle = acpi_dev->handle; | ||
| 84 | struct acpi_buffer buffer; | 85 | struct acpi_buffer buffer; |
| 85 | int ret; | 86 | int ret; |
| 86 | 87 | ||
| @@ -103,7 +104,8 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) | |||
| 103 | 104 | ||
| 104 | static int pnpacpi_disable_resources(struct pnp_dev *dev) | 105 | static int pnpacpi_disable_resources(struct pnp_dev *dev) |
| 105 | { | 106 | { |
| 106 | acpi_handle handle = dev->data; | 107 | struct acpi_device *acpi_dev = dev->data; |
| 108 | acpi_handle handle = acpi_dev->handle; | ||
| 107 | int ret; | 109 | int ret; |
| 108 | 110 | ||
| 109 | dev_dbg(&dev->dev, "disable resources\n"); | 111 | dev_dbg(&dev->dev, "disable resources\n"); |
| @@ -121,6 +123,8 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) | |||
| 121 | #ifdef CONFIG_ACPI_SLEEP | 123 | #ifdef CONFIG_ACPI_SLEEP |
| 122 | static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) | 124 | static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) |
| 123 | { | 125 | { |
| 126 | struct acpi_device *acpi_dev = dev->data; | ||
| 127 | acpi_handle handle = acpi_dev->handle; | ||
| 124 | int power_state; | 128 | int power_state; |
| 125 | 129 | ||
| 126 | power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); | 130 | 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) | |||
| 128 | power_state = (state.event == PM_EVENT_ON) ? | 132 | power_state = (state.event == PM_EVENT_ON) ? |
| 129 | ACPI_STATE_D0 : ACPI_STATE_D3; | 133 | ACPI_STATE_D0 : ACPI_STATE_D3; |
| 130 | 134 | ||
| 131 | return acpi_bus_set_power((acpi_handle) dev->data, power_state); | 135 | return acpi_bus_set_power(handle, power_state); |
| 132 | } | 136 | } |
| 133 | 137 | ||
| 134 | static int pnpacpi_resume(struct pnp_dev *dev) | 138 | static int pnpacpi_resume(struct pnp_dev *dev) |
| 135 | { | 139 | { |
| 136 | return acpi_bus_set_power((acpi_handle) dev->data, ACPI_STATE_D0); | 140 | struct acpi_device *acpi_dev = dev->data; |
| 141 | acpi_handle handle = acpi_dev->handle; | ||
| 142 | |||
| 143 | return acpi_bus_set_power(handle, ACPI_STATE_D0); | ||
| 137 | } | 144 | } |
| 138 | #endif | 145 | #endif |
| 139 | 146 | ||
| 140 | static struct pnp_protocol pnpacpi_protocol = { | 147 | struct pnp_protocol pnpacpi_protocol = { |
| 141 | .name = "Plug and Play ACPI", | 148 | .name = "Plug and Play ACPI", |
| 142 | .get = pnpacpi_get_resources, | 149 | .get = pnpacpi_get_resources, |
| 143 | .set = pnpacpi_set_resources, | 150 | .set = pnpacpi_set_resources, |
| @@ -147,6 +154,7 @@ static struct pnp_protocol pnpacpi_protocol = { | |||
| 147 | .resume = pnpacpi_resume, | 154 | .resume = pnpacpi_resume, |
| 148 | #endif | 155 | #endif |
| 149 | }; | 156 | }; |
| 157 | EXPORT_SYMBOL(pnpacpi_protocol); | ||
| 150 | 158 | ||
| 151 | static int __init pnpacpi_add_device(struct acpi_device *device) | 159 | static int __init pnpacpi_add_device(struct acpi_device *device) |
| 152 | { | 160 | { |
| @@ -168,7 +176,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) | |||
| 168 | if (!dev) | 176 | if (!dev) |
| 169 | return -ENOMEM; | 177 | return -ENOMEM; |
| 170 | 178 | ||
| 171 | dev->data = device->handle; | 179 | dev->data = device; |
| 172 | /* .enabled means the device can decode the resources */ | 180 | /* .enabled means the device can decode the resources */ |
| 173 | dev->active = device->status.enabled; | 181 | dev->active = device->status.enabled; |
| 174 | status = acpi_get_handle(device->handle, "_SRS", &temp); | 182 | status = acpi_get_handle(device->handle, "_SRS", &temp); |
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c index ef3a2cd3a7a0..5702b2c8691f 100644 --- a/drivers/pnp/pnpacpi/rsparser.c +++ b/drivers/pnp/pnpacpi/rsparser.c | |||
| @@ -465,7 +465,8 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res, | |||
| 465 | 465 | ||
| 466 | int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) | 466 | int pnpacpi_parse_allocated_resource(struct pnp_dev *dev) |
| 467 | { | 467 | { |
| 468 | acpi_handle handle = dev->data; | 468 | struct acpi_device *acpi_dev = dev->data; |
| 469 | acpi_handle handle = acpi_dev->handle; | ||
| 469 | acpi_status status; | 470 | acpi_status status; |
| 470 | 471 | ||
| 471 | pnp_dbg(&dev->dev, "parse allocated resources\n"); | 472 | pnp_dbg(&dev->dev, "parse allocated resources\n"); |
| @@ -773,7 +774,8 @@ static __init acpi_status pnpacpi_option_resource(struct acpi_resource *res, | |||
| 773 | 774 | ||
| 774 | int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) | 775 | int __init pnpacpi_parse_resource_option_data(struct pnp_dev *dev) |
| 775 | { | 776 | { |
| 776 | acpi_handle handle = dev->data; | 777 | struct acpi_device *acpi_dev = dev->data; |
| 778 | acpi_handle handle = acpi_dev->handle; | ||
| 777 | acpi_status status; | 779 | acpi_status status; |
| 778 | struct acpipnp_parse_option_s parse_data; | 780 | struct acpipnp_parse_option_s parse_data; |
| 779 | 781 | ||
| @@ -845,7 +847,8 @@ static acpi_status pnpacpi_type_resources(struct acpi_resource *res, void *data) | |||
| 845 | int pnpacpi_build_resource_template(struct pnp_dev *dev, | 847 | int pnpacpi_build_resource_template(struct pnp_dev *dev, |
| 846 | struct acpi_buffer *buffer) | 848 | struct acpi_buffer *buffer) |
| 847 | { | 849 | { |
| 848 | acpi_handle handle = dev->data; | 850 | struct acpi_device *acpi_dev = dev->data; |
| 851 | acpi_handle handle = acpi_dev->handle; | ||
| 849 | struct acpi_resource *resource; | 852 | struct acpi_resource *resource; |
| 850 | int res_cnt = 0; | 853 | int res_cnt = 0; |
| 851 | acpi_status status; | 854 | acpi_status status; |
diff --git a/drivers/thermal/thermal_sys.c b/drivers/thermal/thermal_sys.c index 6f8d8f971212..5066de5cfc0c 100644 --- a/drivers/thermal/thermal_sys.c +++ b/drivers/thermal/thermal_sys.c | |||
| @@ -225,6 +225,12 @@ passive_store(struct device *dev, struct device_attribute *attr, | |||
| 225 | if (!sscanf(buf, "%d\n", &state)) | 225 | if (!sscanf(buf, "%d\n", &state)) |
| 226 | return -EINVAL; | 226 | return -EINVAL; |
| 227 | 227 | ||
| 228 | /* sanity check: values below 1000 millicelcius don't make sense | ||
| 229 | * and can cause the system to go into a thermal heart attack | ||
| 230 | */ | ||
| 231 | if (state && state < 1000) | ||
| 232 | return -EINVAL; | ||
| 233 | |||
| 228 | if (state && !tz->forced_passive) { | 234 | if (state && !tz->forced_passive) { |
| 229 | mutex_lock(&thermal_list_lock); | 235 | mutex_lock(&thermal_list_lock); |
| 230 | list_for_each_entry(cdev, &thermal_cdev_list, node) { | 236 | list_for_each_entry(cdev, &thermal_cdev_list, node) { |
| @@ -235,6 +241,8 @@ passive_store(struct device *dev, struct device_attribute *attr, | |||
| 235 | cdev); | 241 | cdev); |
| 236 | } | 242 | } |
| 237 | mutex_unlock(&thermal_list_lock); | 243 | mutex_unlock(&thermal_list_lock); |
| 244 | if (!tz->passive_delay) | ||
| 245 | tz->passive_delay = 1000; | ||
| 238 | } else if (!state && tz->forced_passive) { | 246 | } else if (!state && tz->forced_passive) { |
| 239 | mutex_lock(&thermal_list_lock); | 247 | mutex_lock(&thermal_list_lock); |
| 240 | list_for_each_entry(cdev, &thermal_cdev_list, node) { | 248 | list_for_each_entry(cdev, &thermal_cdev_list, node) { |
| @@ -245,17 +253,12 @@ passive_store(struct device *dev, struct device_attribute *attr, | |||
| 245 | cdev); | 253 | cdev); |
| 246 | } | 254 | } |
| 247 | mutex_unlock(&thermal_list_lock); | 255 | mutex_unlock(&thermal_list_lock); |
| 256 | tz->passive_delay = 0; | ||
| 248 | } | 257 | } |
| 249 | 258 | ||
| 250 | tz->tc1 = 1; | 259 | tz->tc1 = 1; |
| 251 | tz->tc2 = 1; | 260 | tz->tc2 = 1; |
| 252 | 261 | ||
| 253 | if (!tz->passive_delay) | ||
| 254 | tz->passive_delay = 1000; | ||
| 255 | |||
| 256 | if (!tz->polling_delay) | ||
| 257 | tz->polling_delay = 10000; | ||
| 258 | |||
| 259 | tz->forced_passive = state; | 262 | tz->forced_passive = state; |
| 260 | 263 | ||
| 261 | thermal_zone_device_update(tz); | 264 | thermal_zone_device_update(tz); |
| @@ -374,7 +377,7 @@ thermal_cooling_device_cur_state_store(struct device *dev, | |||
| 374 | if (!sscanf(buf, "%ld\n", &state)) | 377 | if (!sscanf(buf, "%ld\n", &state)) |
| 375 | return -EINVAL; | 378 | return -EINVAL; |
| 376 | 379 | ||
| 377 | if (state < 0) | 380 | if ((long)state < 0) |
| 378 | return -EINVAL; | 381 | return -EINVAL; |
| 379 | 382 | ||
| 380 | result = cdev->ops->set_cur_state(cdev, state); | 383 | result = cdev->ops->set_cur_state(cdev, state); |
| @@ -1016,6 +1019,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz) | |||
| 1016 | thermal_zone_device_set_polling(tz, tz->passive_delay); | 1019 | thermal_zone_device_set_polling(tz, tz->passive_delay); |
| 1017 | else if (tz->polling_delay) | 1020 | else if (tz->polling_delay) |
| 1018 | thermal_zone_device_set_polling(tz, tz->polling_delay); | 1021 | thermal_zone_device_set_polling(tz, tz->polling_delay); |
| 1022 | else | ||
| 1023 | thermal_zone_device_set_polling(tz, 0); | ||
| 1019 | mutex_unlock(&tz->lock); | 1024 | mutex_unlock(&tz->lock); |
| 1020 | } | 1025 | } |
| 1021 | EXPORT_SYMBOL(thermal_zone_device_update); | 1026 | EXPORT_SYMBOL(thermal_zone_device_update); |
diff --git a/include/acpi/acoutput.h b/include/acpi/acoutput.h index 5c823d5ab783..d814da4b5365 100644 --- a/include/acpi/acoutput.h +++ b/include/acpi/acoutput.h | |||
| @@ -85,7 +85,8 @@ | |||
| 85 | #define ACPI_LV_INIT 0x00000001 | 85 | #define ACPI_LV_INIT 0x00000001 |
| 86 | #define ACPI_LV_DEBUG_OBJECT 0x00000002 | 86 | #define ACPI_LV_DEBUG_OBJECT 0x00000002 |
| 87 | #define ACPI_LV_INFO 0x00000004 | 87 | #define ACPI_LV_INFO 0x00000004 |
| 88 | #define ACPI_LV_ALL_EXCEPTIONS 0x00000007 | 88 | #define ACPI_LV_REPAIR 0x00000008 |
| 89 | #define ACPI_LV_ALL_EXCEPTIONS 0x0000000F | ||
| 89 | 90 | ||
| 90 | /* Trace verbosity level 1 [Standard Trace Level] */ | 91 | /* Trace verbosity level 1 [Standard Trace Level] */ |
| 91 | 92 | ||
| @@ -143,6 +144,7 @@ | |||
| 143 | #define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT) | 144 | #define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT) |
| 144 | #define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) | 145 | #define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) |
| 145 | #define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO) | 146 | #define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO) |
| 147 | #define ACPI_DB_REPAIR ACPI_DEBUG_LEVEL (ACPI_LV_REPAIR) | ||
| 146 | #define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS) | 148 | #define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS) |
| 147 | 149 | ||
| 148 | /* Trace level -- also used in the global "DebugLevel" */ | 150 | /* Trace level -- also used in the global "DebugLevel" */ |
| @@ -174,8 +176,8 @@ | |||
| 174 | 176 | ||
| 175 | /* Defaults for debug_level, debug and normal */ | 177 | /* Defaults for debug_level, debug and normal */ |
| 176 | 178 | ||
| 177 | #define ACPI_DEBUG_DEFAULT (ACPI_LV_INFO) | 179 | #define ACPI_DEBUG_DEFAULT (ACPI_LV_INFO | ACPI_LV_REPAIR) |
| 178 | #define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT) | 180 | #define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) |
| 179 | #define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) | 181 | #define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) |
| 180 | 182 | ||
| 181 | #if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) | 183 | #if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) |
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 5e1ad3cd1bbd..86e9735a96bd 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h | |||
| @@ -47,7 +47,7 @@ | |||
| 47 | 47 | ||
| 48 | /* Current ACPICA subsystem version in YYYYMMDD format */ | 48 | /* Current ACPICA subsystem version in YYYYMMDD format */ |
| 49 | 49 | ||
| 50 | #define ACPI_CA_VERSION 0x20091112 | 50 | #define ACPI_CA_VERSION 0x20091214 |
| 51 | 51 | ||
| 52 | #include "actypes.h" | 52 | #include "actypes.h" |
| 53 | #include "actbl.h" | 53 | #include "actbl.h" |
diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 8b668ead6d6e..29245c6b5c0e 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h | |||
| @@ -294,7 +294,7 @@ static inline void acpi_processor_ffh_cstate_enter(struct acpi_processor_cx | |||
| 294 | #ifdef CONFIG_CPU_FREQ | 294 | #ifdef CONFIG_CPU_FREQ |
| 295 | void acpi_processor_ppc_init(void); | 295 | void acpi_processor_ppc_init(void); |
| 296 | void acpi_processor_ppc_exit(void); | 296 | void acpi_processor_ppc_exit(void); |
| 297 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr); | 297 | int acpi_processor_ppc_has_changed(struct acpi_processor *pr, int event_flag); |
| 298 | extern int acpi_processor_get_bios_limit(int cpu, unsigned int *limit); | 298 | extern int acpi_processor_get_bios_limit(int cpu, unsigned int *limit); |
| 299 | #else | 299 | #else |
| 300 | static inline void acpi_processor_ppc_init(void) | 300 | static inline void acpi_processor_ppc_init(void) |
| @@ -305,7 +305,8 @@ static inline void acpi_processor_ppc_exit(void) | |||
| 305 | { | 305 | { |
| 306 | return; | 306 | return; |
| 307 | } | 307 | } |
| 308 | static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr) | 308 | static inline int acpi_processor_ppc_has_changed(struct acpi_processor *pr, |
| 309 | int event_flag) | ||
| 309 | { | 310 | { |
| 310 | static unsigned int printout = 1; | 311 | static unsigned int printout = 1; |
| 311 | if (printout) { | 312 | if (printout) { |
diff --git a/include/linux/acpi.h b/include/linux/acpi.h index dfcd920c3e54..ce945d4845fc 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h | |||
| @@ -240,7 +240,7 @@ extern int pnpacpi_disabled; | |||
| 240 | #define PXM_INVAL (-1) | 240 | #define PXM_INVAL (-1) |
| 241 | #define NID_INVAL (-1) | 241 | #define NID_INVAL (-1) |
| 242 | 242 | ||
| 243 | int acpi_check_resource_conflict(struct resource *res); | 243 | int acpi_check_resource_conflict(const struct resource *res); |
| 244 | 244 | ||
| 245 | int acpi_check_region(resource_size_t start, resource_size_t n, | 245 | int acpi_check_region(resource_size_t start, resource_size_t n, |
| 246 | const char *name); | 246 | const char *name); |
| @@ -253,10 +253,16 @@ void __init acpi_old_suspend_ordering(void); | |||
| 253 | void __init acpi_s4_no_nvs(void); | 253 | void __init acpi_s4_no_nvs(void); |
| 254 | #endif /* CONFIG_PM_SLEEP */ | 254 | #endif /* CONFIG_PM_SLEEP */ |
| 255 | 255 | ||
| 256 | struct acpi_osc_context { | ||
| 257 | char *uuid_str; /* uuid string */ | ||
| 258 | int rev; | ||
| 259 | struct acpi_buffer cap; /* arg2/arg3 */ | ||
| 260 | struct acpi_buffer ret; /* free by caller if success */ | ||
| 261 | }; | ||
| 262 | |||
| 256 | #define OSC_QUERY_TYPE 0 | 263 | #define OSC_QUERY_TYPE 0 |
| 257 | #define OSC_SUPPORT_TYPE 1 | 264 | #define OSC_SUPPORT_TYPE 1 |
| 258 | #define OSC_CONTROL_TYPE 2 | 265 | #define OSC_CONTROL_TYPE 2 |
| 259 | #define OSC_SUPPORT_MASKS 0x1f | ||
| 260 | 266 | ||
| 261 | /* _OSC DW0 Definition */ | 267 | /* _OSC DW0 Definition */ |
| 262 | #define OSC_QUERY_ENABLE 1 | 268 | #define OSC_QUERY_ENABLE 1 |
| @@ -265,12 +271,23 @@ void __init acpi_s4_no_nvs(void); | |||
| 265 | #define OSC_INVALID_REVISION_ERROR 8 | 271 | #define OSC_INVALID_REVISION_ERROR 8 |
| 266 | #define OSC_CAPABILITIES_MASK_ERROR 16 | 272 | #define OSC_CAPABILITIES_MASK_ERROR 16 |
| 267 | 273 | ||
| 274 | acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); | ||
| 275 | |||
| 276 | /* platform-wide _OSC bits */ | ||
| 277 | #define OSC_SB_PAD_SUPPORT 1 | ||
| 278 | #define OSC_SB_PPC_OST_SUPPORT 2 | ||
| 279 | #define OSC_SB_PR3_SUPPORT 4 | ||
| 280 | #define OSC_SB_CPUHP_OST_SUPPORT 8 | ||
| 281 | #define OSC_SB_APEI_SUPPORT 16 | ||
| 282 | |||
| 283 | /* PCI defined _OSC bits */ | ||
| 268 | /* _OSC DW1 Definition (OS Support Fields) */ | 284 | /* _OSC DW1 Definition (OS Support Fields) */ |
| 269 | #define OSC_EXT_PCI_CONFIG_SUPPORT 1 | 285 | #define OSC_EXT_PCI_CONFIG_SUPPORT 1 |
| 270 | #define OSC_ACTIVE_STATE_PWR_SUPPORT 2 | 286 | #define OSC_ACTIVE_STATE_PWR_SUPPORT 2 |
| 271 | #define OSC_CLOCK_PWR_CAPABILITY_SUPPORT 4 | 287 | #define OSC_CLOCK_PWR_CAPABILITY_SUPPORT 4 |
| 272 | #define OSC_PCI_SEGMENT_GROUPS_SUPPORT 8 | 288 | #define OSC_PCI_SEGMENT_GROUPS_SUPPORT 8 |
| 273 | #define OSC_MSI_SUPPORT 16 | 289 | #define OSC_MSI_SUPPORT 16 |
| 290 | #define OSC_PCI_SUPPORT_MASKS 0x1f | ||
| 274 | 291 | ||
| 275 | /* _OSC DW1 Definition (OS Control Fields) */ | 292 | /* _OSC DW1 Definition (OS Control Fields) */ |
| 276 | #define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 1 | 293 | #define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 1 |
| @@ -279,7 +296,7 @@ void __init acpi_s4_no_nvs(void); | |||
| 279 | #define OSC_PCI_EXPRESS_AER_CONTROL 8 | 296 | #define OSC_PCI_EXPRESS_AER_CONTROL 8 |
| 280 | #define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL 16 | 297 | #define OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL 16 |
| 281 | 298 | ||
| 282 | #define OSC_CONTROL_MASKS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \ | 299 | #define OSC_PCI_CONTROL_MASKS (OSC_PCI_EXPRESS_NATIVE_HP_CONTROL | \ |
| 283 | OSC_SHPC_NATIVE_HP_CONTROL | \ | 300 | OSC_SHPC_NATIVE_HP_CONTROL | \ |
| 284 | OSC_PCI_EXPRESS_PME_CONTROL | \ | 301 | OSC_PCI_EXPRESS_PME_CONTROL | \ |
| 285 | OSC_PCI_EXPRESS_AER_CONTROL | \ | 302 | OSC_PCI_EXPRESS_AER_CONTROL | \ |
diff --git a/include/linux/pnp.h b/include/linux/pnp.h index fddfafaed024..7c4193eb0072 100644 --- a/include/linux/pnp.h +++ b/include/linux/pnp.h | |||
| @@ -334,6 +334,19 @@ extern struct pnp_protocol pnpbios_protocol; | |||
| 334 | #define pnp_device_is_pnpbios(dev) 0 | 334 | #define pnp_device_is_pnpbios(dev) 0 |
| 335 | #endif | 335 | #endif |
| 336 | 336 | ||
| 337 | #ifdef CONFIG_PNPACPI | ||
| 338 | extern struct pnp_protocol pnpacpi_protocol; | ||
| 339 | |||
| 340 | static inline struct acpi_device *pnp_acpi_device(struct pnp_dev *dev) | ||
| 341 | { | ||
| 342 | if (dev->protocol == &pnpacpi_protocol) | ||
| 343 | return dev->data; | ||
| 344 | return NULL; | ||
| 345 | } | ||
| 346 | #else | ||
| 347 | #define pnp_acpi_device(dev) 0 | ||
| 348 | #endif | ||
| 349 | |||
| 337 | /* status */ | 350 | /* status */ |
| 338 | #define PNP_READY 0x0000 | 351 | #define PNP_READY 0x0000 |
| 339 | #define PNP_ATTACHED 0x0001 | 352 | #define PNP_ATTACHED 0x0001 |
