diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-23 20:20:59 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-03-23 20:20:59 -0400 |
commit | 5a010c73cdb760c9bdf37b28824b6566789cc005 (patch) | |
tree | a12508a6d3b20807eaa822bedd95973df47d6307 /drivers/platform | |
parent | b615d3d406ead1157c6b846c417b71a3b6600776 (diff) | |
parent | fffcad87d4e7c5f6f6f6e5fc9d337bd6f197f80f (diff) |
Merge tag 'platform-drivers-x86-v4.6-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86
Pull x86 platform driver updates from Darren Hart:
"Significant refactoring of Dell laptop drivers, modularizing the
smbios code. Multiple new platforms added for ideapad, asus, dell,
and alienware using existing quirks. A few fixes and cleanups.
hp-wmi:
- Remove GPS rfkill support via pre-2009 interface
- fix unregister order in hp_wmi_rfkill_setup() once again
ideapad-laptop:
- Add ideapad Y700 (15) to the no_hw_rfkill DMI list
fujitsu-laptop:
- Support radio toggle button
intel-hid:
- allocate correct amount of memory for private struct
platform/x86:
- Make intel_scu_ipc explicitly non-modular
intel_pmc_ipc:
- Avoid pending IPC1 command during legacy suspend
- Fix GCR register base address and length
asus-nb-wmi:
- add wapf=4 quirk for ASUS X75VD
intel_telemetry_pltdrv:
- Change verbosity control bits
dell-rbtn:
- Add a comment about the XPS 13 9350
dell-wmi, dell-laptop:
- depends DMI
dell-wmi:
- support Dell Inspiron M5110
- properly process Dell Instant Launch hotkey
- enable receiving WMI events on Dell Vostro V131
- Support new hotkeys on the XPS 13 9350 (Skylake)
- Clean up hotkey table size check
- Stop storing pointers to DMI tables
dell-laptop:
- move dell_smi_error() to dell-smbios
- use dell_smbios_find_token() instead of find_token_location()
- use dell_smbios_find_token() instead of find_token_id()
- extract SMBIOS-related code to a separate module
dell-smbios:
- rename dell_smi_error() to dell_smbios_error()
- make da_tokens static
- remove find_token_{id,location}()
- implement new function for finding DMI table 0xDA tokens
- make the SMBIOS buffer static
- return the SMBIOS buffer from dell_smbios_get_buffer()
- don't return an SMBIOS buffer from dell_smbios_send_request()
- don't pass an SMBIOS buffer to dell_smbios_send_request()
- rename dell_send_request() to dell_smbios_send_request()
- rename release_buffer() to dell_smbios_release_buffer()
- rename clear_buffer() to dell_smbios_clear_buffer()
- rename get_buffer() to dell_smbios_get_buffer()
dell-led:
- use dell_smbios_send_request() for performing SMBIOS calls
- use dell_smbios_find_token() for finding mic DMI tokens
toshiba_acpi:
- Add a module parameter to disable hotkeys registration
- Add sysfs entries for the Cooling Method feature
- Add support for cooling method feature
Documentation/ABI:
- Update sysfs-driver-toshiba_acpi file
thinkpad_acpi:
- Remove ambiguous logging for "Unsupported brightness interface"
alienware-wmi:
- whitespace improvements
- Add support for two new systems: ASM200 and ASM201.
- Add support for deep sleep control.
- Add initial support for alienware graphics amplifier.
- Add support for new platform: X51-R3
- Clean up whitespace for ASM100 platform"
* tag 'platform-drivers-x86-v4.6-1' of git://git.infradead.org/users/dvhart/linux-platform-drivers-x86: (47 commits)
hp-wmi: Remove GPS rfkill support via pre-2009 interface
hp-wmi: fix unregister order in hp_wmi_rfkill_setup() once again
dell-wmi: support Dell Inspiron M5110
dell-wmi: properly process Dell Instant Launch hotkey
dell-wmi: enable receiving WMI events on Dell Vostro V131
dell-smbios: rename dell_smi_error() to dell_smbios_error()
dell-laptop: move dell_smi_error() to dell-smbios
ideapad-laptop: Add ideapad Y700 (15) to the no_hw_rfkill DMI list
fujitsu-laptop: Support radio toggle button
intel-hid: allocate correct amount of memory for private struct
platform/x86: Make intel_scu_ipc explicitly non-modular
intel_pmc_ipc: Avoid pending IPC1 command during legacy suspend
intel_pmc_ipc: Fix GCR register base address and length
asus-nb-wmi: add wapf=4 quirk for ASUS X75VD
intel_telemetry_pltdrv: Change verbosity control bits
dell-rbtn: Add a comment about the XPS 13 9350
dell-wmi: Support new hotkeys on the XPS 13 9350 (Skylake)
dell-wmi: Clean up hotkey table size check
dell-wmi, dell-laptop: depends DMI
dell-wmi: Stop storing pointers to DMI tables
...
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/x86/Kconfig | 15 | ||||
-rw-r--r-- | drivers/platform/x86/Makefile | 1 | ||||
-rw-r--r-- | drivers/platform/x86/alienware-wmi.c | 286 | ||||
-rw-r--r-- | drivers/platform/x86/asus-nb-wmi.c | 9 | ||||
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 370 | ||||
-rw-r--r-- | drivers/platform/x86/dell-rbtn.c | 15 | ||||
-rw-r--r-- | drivers/platform/x86/dell-smbios.c | 193 | ||||
-rw-r--r-- | drivers/platform/x86/dell-smbios.h | 46 | ||||
-rw-r--r-- | drivers/platform/x86/dell-wmi.c | 238 | ||||
-rw-r--r-- | drivers/platform/x86/fujitsu-laptop.c | 8 | ||||
-rw-r--r-- | drivers/platform/x86/hp-wmi.c | 46 | ||||
-rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 14 | ||||
-rw-r--r-- | drivers/platform/x86/intel-hid.c | 3 | ||||
-rw-r--r-- | drivers/platform/x86/intel_pmc_ipc.c | 8 | ||||
-rw-r--r-- | drivers/platform/x86/intel_scu_ipc.c | 35 | ||||
-rw-r--r-- | drivers/platform/x86/intel_telemetry_pltdrv.c | 13 | ||||
-rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 4 | ||||
-rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 115 |
18 files changed, 995 insertions, 424 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 69f93a576e45..ed2004be13cf 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig | |||
@@ -91,10 +91,21 @@ config ASUS_LAPTOP | |||
91 | 91 | ||
92 | If you have an ACPI-compatible ASUS laptop, say Y or M here. | 92 | If you have an ACPI-compatible ASUS laptop, say Y or M here. |
93 | 93 | ||
94 | config DELL_SMBIOS | ||
95 | tristate "Dell SMBIOS Support" | ||
96 | depends on DCDBAS | ||
97 | default n | ||
98 | ---help--- | ||
99 | This module provides common functions for kernel modules using | ||
100 | Dell SMBIOS. | ||
101 | |||
102 | If you have a Dell laptop, say Y or M here. | ||
103 | |||
94 | config DELL_LAPTOP | 104 | config DELL_LAPTOP |
95 | tristate "Dell Laptop Extras" | 105 | tristate "Dell Laptop Extras" |
96 | depends on X86 | 106 | depends on X86 |
97 | depends on DCDBAS | 107 | depends on DELL_SMBIOS |
108 | depends on DMI | ||
98 | depends on BACKLIGHT_CLASS_DEVICE | 109 | depends on BACKLIGHT_CLASS_DEVICE |
99 | depends on ACPI_VIDEO || ACPI_VIDEO = n | 110 | depends on ACPI_VIDEO || ACPI_VIDEO = n |
100 | depends on RFKILL || RFKILL = n | 111 | depends on RFKILL || RFKILL = n |
@@ -110,8 +121,10 @@ config DELL_LAPTOP | |||
110 | config DELL_WMI | 121 | config DELL_WMI |
111 | tristate "Dell WMI extras" | 122 | tristate "Dell WMI extras" |
112 | depends on ACPI_WMI | 123 | depends on ACPI_WMI |
124 | depends on DMI | ||
113 | depends on INPUT | 125 | depends on INPUT |
114 | depends on ACPI_VIDEO || ACPI_VIDEO = n | 126 | depends on ACPI_VIDEO || ACPI_VIDEO = n |
127 | depends on DELL_SMBIOS | ||
115 | select INPUT_SPARSEKMAP | 128 | select INPUT_SPARSEKMAP |
116 | ---help--- | 129 | ---help--- |
117 | Say Y here if you want to support WMI-based hotkeys on Dell laptops. | 130 | Say Y here if you want to support WMI-based hotkeys on Dell laptops. |
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 40574e7390f3..448443c3baba 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile | |||
@@ -11,6 +11,7 @@ obj-$(CONFIG_EEEPC_WMI) += eeepc-wmi.o | |||
11 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o | 11 | obj-$(CONFIG_MSI_LAPTOP) += msi-laptop.o |
12 | obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o | 12 | obj-$(CONFIG_ACPI_CMPC) += classmate-laptop.o |
13 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o | 13 | obj-$(CONFIG_COMPAL_LAPTOP) += compal-laptop.o |
14 | obj-$(CONFIG_DELL_SMBIOS) += dell-smbios.o | ||
14 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o | 15 | obj-$(CONFIG_DELL_LAPTOP) += dell-laptop.o |
15 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o | 16 | obj-$(CONFIG_DELL_WMI) += dell-wmi.o |
16 | obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o | 17 | obj-$(CONFIG_DELL_WMI_AIO) += dell-wmi-aio.o |
diff --git a/drivers/platform/x86/alienware-wmi.c b/drivers/platform/x86/alienware-wmi.c index 1e1e59423889..005629447b0c 100644 --- a/drivers/platform/x86/alienware-wmi.c +++ b/drivers/platform/x86/alienware-wmi.c | |||
@@ -33,6 +33,9 @@ | |||
33 | #define WMAX_METHOD_BRIGHTNESS 0x3 | 33 | #define WMAX_METHOD_BRIGHTNESS 0x3 |
34 | #define WMAX_METHOD_ZONE_CONTROL 0x4 | 34 | #define WMAX_METHOD_ZONE_CONTROL 0x4 |
35 | #define WMAX_METHOD_HDMI_CABLE 0x5 | 35 | #define WMAX_METHOD_HDMI_CABLE 0x5 |
36 | #define WMAX_METHOD_AMPLIFIER_CABLE 0x6 | ||
37 | #define WMAX_METHOD_DEEP_SLEEP_CONTROL 0x0B | ||
38 | #define WMAX_METHOD_DEEP_SLEEP_STATUS 0x0C | ||
36 | 39 | ||
37 | MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); | 40 | MODULE_AUTHOR("Mario Limonciello <mario_limonciello@dell.com>"); |
38 | MODULE_DESCRIPTION("Alienware special feature control"); | 41 | MODULE_DESCRIPTION("Alienware special feature control"); |
@@ -60,6 +63,8 @@ enum WMAX_CONTROL_STATES { | |||
60 | struct quirk_entry { | 63 | struct quirk_entry { |
61 | u8 num_zones; | 64 | u8 num_zones; |
62 | u8 hdmi_mux; | 65 | u8 hdmi_mux; |
66 | u8 amplifier; | ||
67 | u8 deepslp; | ||
63 | }; | 68 | }; |
64 | 69 | ||
65 | static struct quirk_entry *quirks; | 70 | static struct quirk_entry *quirks; |
@@ -67,16 +72,43 @@ static struct quirk_entry *quirks; | |||
67 | static struct quirk_entry quirk_unknown = { | 72 | static struct quirk_entry quirk_unknown = { |
68 | .num_zones = 2, | 73 | .num_zones = 2, |
69 | .hdmi_mux = 0, | 74 | .hdmi_mux = 0, |
75 | .amplifier = 0, | ||
76 | .deepslp = 0, | ||
70 | }; | 77 | }; |
71 | 78 | ||
72 | static struct quirk_entry quirk_x51_family = { | 79 | static struct quirk_entry quirk_x51_r1_r2 = { |
73 | .num_zones = 3, | 80 | .num_zones = 3, |
74 | .hdmi_mux = 0. | 81 | .hdmi_mux = 0, |
82 | .amplifier = 0, | ||
83 | .deepslp = 0, | ||
84 | }; | ||
85 | |||
86 | static struct quirk_entry quirk_x51_r3 = { | ||
87 | .num_zones = 4, | ||
88 | .hdmi_mux = 0, | ||
89 | .amplifier = 1, | ||
90 | .deepslp = 0, | ||
75 | }; | 91 | }; |
76 | 92 | ||
77 | static struct quirk_entry quirk_asm100 = { | 93 | static struct quirk_entry quirk_asm100 = { |
78 | .num_zones = 2, | 94 | .num_zones = 2, |
79 | .hdmi_mux = 1, | 95 | .hdmi_mux = 1, |
96 | .amplifier = 0, | ||
97 | .deepslp = 0, | ||
98 | }; | ||
99 | |||
100 | static struct quirk_entry quirk_asm200 = { | ||
101 | .num_zones = 2, | ||
102 | .hdmi_mux = 1, | ||
103 | .amplifier = 0, | ||
104 | .deepslp = 1, | ||
105 | }; | ||
106 | |||
107 | static struct quirk_entry quirk_asm201 = { | ||
108 | .num_zones = 2, | ||
109 | .hdmi_mux = 1, | ||
110 | .amplifier = 1, | ||
111 | .deepslp = 1, | ||
80 | }; | 112 | }; |
81 | 113 | ||
82 | static int __init dmi_matched(const struct dmi_system_id *dmi) | 114 | static int __init dmi_matched(const struct dmi_system_id *dmi) |
@@ -88,12 +120,12 @@ static int __init dmi_matched(const struct dmi_system_id *dmi) | |||
88 | static const struct dmi_system_id alienware_quirks[] __initconst = { | 120 | static const struct dmi_system_id alienware_quirks[] __initconst = { |
89 | { | 121 | { |
90 | .callback = dmi_matched, | 122 | .callback = dmi_matched, |
91 | .ident = "Alienware X51 R1", | 123 | .ident = "Alienware X51 R3", |
92 | .matches = { | 124 | .matches = { |
93 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | 125 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), |
94 | DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"), | 126 | DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R3"), |
95 | }, | 127 | }, |
96 | .driver_data = &quirk_x51_family, | 128 | .driver_data = &quirk_x51_r3, |
97 | }, | 129 | }, |
98 | { | 130 | { |
99 | .callback = dmi_matched, | 131 | .callback = dmi_matched, |
@@ -102,17 +134,44 @@ static const struct dmi_system_id alienware_quirks[] __initconst = { | |||
102 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | 134 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), |
103 | DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"), | 135 | DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51 R2"), |
104 | }, | 136 | }, |
105 | .driver_data = &quirk_x51_family, | 137 | .driver_data = &quirk_x51_r1_r2, |
138 | }, | ||
139 | { | ||
140 | .callback = dmi_matched, | ||
141 | .ident = "Alienware X51 R1", | ||
142 | .matches = { | ||
143 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | ||
144 | DMI_MATCH(DMI_PRODUCT_NAME, "Alienware X51"), | ||
145 | }, | ||
146 | .driver_data = &quirk_x51_r1_r2, | ||
147 | }, | ||
148 | { | ||
149 | .callback = dmi_matched, | ||
150 | .ident = "Alienware ASM100", | ||
151 | .matches = { | ||
152 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | ||
153 | DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), | ||
154 | }, | ||
155 | .driver_data = &quirk_asm100, | ||
156 | }, | ||
157 | { | ||
158 | .callback = dmi_matched, | ||
159 | .ident = "Alienware ASM200", | ||
160 | .matches = { | ||
161 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | ||
162 | DMI_MATCH(DMI_PRODUCT_NAME, "ASM200"), | ||
163 | }, | ||
164 | .driver_data = &quirk_asm200, | ||
106 | }, | 165 | }, |
107 | { | 166 | { |
108 | .callback = dmi_matched, | 167 | .callback = dmi_matched, |
109 | .ident = "Alienware ASM100", | 168 | .ident = "Alienware ASM201", |
110 | .matches = { | 169 | .matches = { |
111 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), | 170 | DMI_MATCH(DMI_SYS_VENDOR, "Alienware"), |
112 | DMI_MATCH(DMI_PRODUCT_NAME, "ASM100"), | 171 | DMI_MATCH(DMI_PRODUCT_NAME, "ASM201"), |
113 | }, | 172 | }, |
114 | .driver_data = &quirk_asm100, | 173 | .driver_data = &quirk_asm201, |
115 | }, | 174 | }, |
116 | {} | 175 | {} |
117 | }; | 176 | }; |
118 | 177 | ||
@@ -133,7 +192,7 @@ struct wmax_brightness_args { | |||
133 | u32 percentage; | 192 | u32 percentage; |
134 | }; | 193 | }; |
135 | 194 | ||
136 | struct hdmi_args { | 195 | struct wmax_basic_args { |
137 | u8 arg; | 196 | u8 arg; |
138 | }; | 197 | }; |
139 | 198 | ||
@@ -170,7 +229,7 @@ static u8 global_brightness; | |||
170 | 229 | ||
171 | /* | 230 | /* |
172 | * Helpers used for zone control | 231 | * Helpers used for zone control |
173 | */ | 232 | */ |
174 | static int parse_rgb(const char *buf, struct platform_zone *zone) | 233 | static int parse_rgb(const char *buf, struct platform_zone *zone) |
175 | { | 234 | { |
176 | long unsigned int rgb; | 235 | long unsigned int rgb; |
@@ -210,7 +269,7 @@ static struct platform_zone *match_zone(struct device_attribute *attr) | |||
210 | 269 | ||
211 | /* | 270 | /* |
212 | * Individual RGB zone control | 271 | * Individual RGB zone control |
213 | */ | 272 | */ |
214 | static int alienware_update_led(struct platform_zone *zone) | 273 | static int alienware_update_led(struct platform_zone *zone) |
215 | { | 274 | { |
216 | int method_id; | 275 | int method_id; |
@@ -218,16 +277,16 @@ static int alienware_update_led(struct platform_zone *zone) | |||
218 | char *guid; | 277 | char *guid; |
219 | struct acpi_buffer input; | 278 | struct acpi_buffer input; |
220 | struct legacy_led_args legacy_args; | 279 | struct legacy_led_args legacy_args; |
221 | struct wmax_led_args wmax_args; | 280 | struct wmax_led_args wmax_basic_args; |
222 | if (interface == WMAX) { | 281 | if (interface == WMAX) { |
223 | wmax_args.led_mask = 1 << zone->location; | 282 | wmax_basic_args.led_mask = 1 << zone->location; |
224 | wmax_args.colors = zone->colors; | 283 | wmax_basic_args.colors = zone->colors; |
225 | wmax_args.state = lighting_control_state; | 284 | wmax_basic_args.state = lighting_control_state; |
226 | guid = WMAX_CONTROL_GUID; | 285 | guid = WMAX_CONTROL_GUID; |
227 | method_id = WMAX_METHOD_ZONE_CONTROL; | 286 | method_id = WMAX_METHOD_ZONE_CONTROL; |
228 | 287 | ||
229 | input.length = (acpi_size) sizeof(wmax_args); | 288 | input.length = (acpi_size) sizeof(wmax_basic_args); |
230 | input.pointer = &wmax_args; | 289 | input.pointer = &wmax_basic_args; |
231 | } else { | 290 | } else { |
232 | legacy_args.colors = zone->colors; | 291 | legacy_args.colors = zone->colors; |
233 | legacy_args.brightness = global_brightness; | 292 | legacy_args.brightness = global_brightness; |
@@ -283,7 +342,7 @@ static ssize_t zone_set(struct device *dev, struct device_attribute *attr, | |||
283 | 342 | ||
284 | /* | 343 | /* |
285 | * LED Brightness (Global) | 344 | * LED Brightness (Global) |
286 | */ | 345 | */ |
287 | static int wmax_brightness(int brightness) | 346 | static int wmax_brightness(int brightness) |
288 | { | 347 | { |
289 | acpi_status status; | 348 | acpi_status status; |
@@ -327,7 +386,7 @@ static struct led_classdev global_led = { | |||
327 | 386 | ||
328 | /* | 387 | /* |
329 | * Lighting control state device attribute (Global) | 388 | * Lighting control state device attribute (Global) |
330 | */ | 389 | */ |
331 | static ssize_t show_control_state(struct device *dev, | 390 | static ssize_t show_control_state(struct device *dev, |
332 | struct device_attribute *attr, char *buf) | 391 | struct device_attribute *attr, char *buf) |
333 | { | 392 | { |
@@ -435,11 +494,7 @@ static void alienware_zone_exit(struct platform_device *dev) | |||
435 | kfree(zone_attrs); | 494 | kfree(zone_attrs); |
436 | } | 495 | } |
437 | 496 | ||
438 | /* | 497 | static acpi_status alienware_wmax_command(struct wmax_basic_args *in_args, |
439 | The HDMI mux sysfs node indicates the status of the HDMI input mux. | ||
440 | It can toggle between standard system GPU output and HDMI input. | ||
441 | */ | ||
442 | static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, | ||
443 | u32 command, int *out_data) | 498 | u32 command, int *out_data) |
444 | { | 499 | { |
445 | acpi_status status; | 500 | acpi_status status; |
@@ -467,16 +522,20 @@ static acpi_status alienware_hdmi_command(struct hdmi_args *in_args, | |||
467 | 522 | ||
468 | } | 523 | } |
469 | 524 | ||
525 | /* | ||
526 | * The HDMI mux sysfs node indicates the status of the HDMI input mux. | ||
527 | * It can toggle between standard system GPU output and HDMI input. | ||
528 | */ | ||
470 | static ssize_t show_hdmi_cable(struct device *dev, | 529 | static ssize_t show_hdmi_cable(struct device *dev, |
471 | struct device_attribute *attr, char *buf) | 530 | struct device_attribute *attr, char *buf) |
472 | { | 531 | { |
473 | acpi_status status; | 532 | acpi_status status; |
474 | u32 out_data; | 533 | u32 out_data; |
475 | struct hdmi_args in_args = { | 534 | struct wmax_basic_args in_args = { |
476 | .arg = 0, | 535 | .arg = 0, |
477 | }; | 536 | }; |
478 | status = | 537 | status = |
479 | alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_CABLE, | 538 | alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_CABLE, |
480 | (u32 *) &out_data); | 539 | (u32 *) &out_data); |
481 | if (ACPI_SUCCESS(status)) { | 540 | if (ACPI_SUCCESS(status)) { |
482 | if (out_data == 0) | 541 | if (out_data == 0) |
@@ -495,11 +554,11 @@ static ssize_t show_hdmi_source(struct device *dev, | |||
495 | { | 554 | { |
496 | acpi_status status; | 555 | acpi_status status; |
497 | u32 out_data; | 556 | u32 out_data; |
498 | struct hdmi_args in_args = { | 557 | struct wmax_basic_args in_args = { |
499 | .arg = 0, | 558 | .arg = 0, |
500 | }; | 559 | }; |
501 | status = | 560 | status = |
502 | alienware_hdmi_command(&in_args, WMAX_METHOD_HDMI_STATUS, | 561 | alienware_wmax_command(&in_args, WMAX_METHOD_HDMI_STATUS, |
503 | (u32 *) &out_data); | 562 | (u32 *) &out_data); |
504 | 563 | ||
505 | if (ACPI_SUCCESS(status)) { | 564 | if (ACPI_SUCCESS(status)) { |
@@ -519,7 +578,7 @@ static ssize_t toggle_hdmi_source(struct device *dev, | |||
519 | const char *buf, size_t count) | 578 | const char *buf, size_t count) |
520 | { | 579 | { |
521 | acpi_status status; | 580 | acpi_status status; |
522 | struct hdmi_args args; | 581 | struct wmax_basic_args args; |
523 | if (strcmp(buf, "gpu\n") == 0) | 582 | if (strcmp(buf, "gpu\n") == 0) |
524 | args.arg = 1; | 583 | args.arg = 1; |
525 | else if (strcmp(buf, "input\n") == 0) | 584 | else if (strcmp(buf, "input\n") == 0) |
@@ -528,7 +587,7 @@ static ssize_t toggle_hdmi_source(struct device *dev, | |||
528 | args.arg = 3; | 587 | args.arg = 3; |
529 | pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); | 588 | pr_debug("alienware-wmi: setting hdmi to %d : %s", args.arg, buf); |
530 | 589 | ||
531 | status = alienware_hdmi_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); | 590 | status = alienware_wmax_command(&args, WMAX_METHOD_HDMI_SOURCE, NULL); |
532 | 591 | ||
533 | if (ACPI_FAILURE(status)) | 592 | if (ACPI_FAILURE(status)) |
534 | pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", | 593 | pr_err("alienware-wmi: HDMI toggle failed: results: %u\n", |
@@ -563,11 +622,144 @@ static int create_hdmi(struct platform_device *dev) | |||
563 | 622 | ||
564 | ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); | 623 | ret = sysfs_create_group(&dev->dev.kobj, &hdmi_attribute_group); |
565 | if (ret) | 624 | if (ret) |
566 | goto error_create_hdmi; | 625 | remove_hdmi(dev); |
567 | return 0; | 626 | return ret; |
627 | } | ||
568 | 628 | ||
569 | error_create_hdmi: | 629 | /* |
570 | remove_hdmi(dev); | 630 | * Alienware GFX amplifier support |
631 | * - Currently supports reading cable status | ||
632 | * - Leaving expansion room to possibly support dock/undock events later | ||
633 | */ | ||
634 | static ssize_t show_amplifier_status(struct device *dev, | ||
635 | struct device_attribute *attr, char *buf) | ||
636 | { | ||
637 | acpi_status status; | ||
638 | u32 out_data; | ||
639 | struct wmax_basic_args in_args = { | ||
640 | .arg = 0, | ||
641 | }; | ||
642 | status = | ||
643 | alienware_wmax_command(&in_args, WMAX_METHOD_AMPLIFIER_CABLE, | ||
644 | (u32 *) &out_data); | ||
645 | if (ACPI_SUCCESS(status)) { | ||
646 | if (out_data == 0) | ||
647 | return scnprintf(buf, PAGE_SIZE, | ||
648 | "[unconnected] connected unknown\n"); | ||
649 | else if (out_data == 1) | ||
650 | return scnprintf(buf, PAGE_SIZE, | ||
651 | "unconnected [connected] unknown\n"); | ||
652 | } | ||
653 | pr_err("alienware-wmi: unknown amplifier cable status: %d\n", status); | ||
654 | return scnprintf(buf, PAGE_SIZE, "unconnected connected [unknown]\n"); | ||
655 | } | ||
656 | |||
657 | static DEVICE_ATTR(status, S_IRUGO, show_amplifier_status, NULL); | ||
658 | |||
659 | static struct attribute *amplifier_attrs[] = { | ||
660 | &dev_attr_status.attr, | ||
661 | NULL, | ||
662 | }; | ||
663 | |||
664 | static struct attribute_group amplifier_attribute_group = { | ||
665 | .name = "amplifier", | ||
666 | .attrs = amplifier_attrs, | ||
667 | }; | ||
668 | |||
669 | static void remove_amplifier(struct platform_device *dev) | ||
670 | { | ||
671 | if (quirks->amplifier > 0) | ||
672 | sysfs_remove_group(&dev->dev.kobj, &lifier_attribute_group); | ||
673 | } | ||
674 | |||
675 | static int create_amplifier(struct platform_device *dev) | ||
676 | { | ||
677 | int ret; | ||
678 | |||
679 | ret = sysfs_create_group(&dev->dev.kobj, &lifier_attribute_group); | ||
680 | if (ret) | ||
681 | remove_amplifier(dev); | ||
682 | return ret; | ||
683 | } | ||
684 | |||
685 | /* | ||
686 | * Deep Sleep Control support | ||
687 | * - Modifies BIOS setting for deep sleep control allowing extra wakeup events | ||
688 | */ | ||
689 | static ssize_t show_deepsleep_status(struct device *dev, | ||
690 | struct device_attribute *attr, char *buf) | ||
691 | { | ||
692 | acpi_status status; | ||
693 | u32 out_data; | ||
694 | struct wmax_basic_args in_args = { | ||
695 | .arg = 0, | ||
696 | }; | ||
697 | status = alienware_wmax_command(&in_args, WMAX_METHOD_DEEP_SLEEP_STATUS, | ||
698 | (u32 *) &out_data); | ||
699 | if (ACPI_SUCCESS(status)) { | ||
700 | if (out_data == 0) | ||
701 | return scnprintf(buf, PAGE_SIZE, | ||
702 | "[disabled] s5 s5_s4\n"); | ||
703 | else if (out_data == 1) | ||
704 | return scnprintf(buf, PAGE_SIZE, | ||
705 | "disabled [s5] s5_s4\n"); | ||
706 | else if (out_data == 2) | ||
707 | return scnprintf(buf, PAGE_SIZE, | ||
708 | "disabled s5 [s5_s4]\n"); | ||
709 | } | ||
710 | pr_err("alienware-wmi: unknown deep sleep status: %d\n", status); | ||
711 | return scnprintf(buf, PAGE_SIZE, "disabled s5 s5_s4 [unknown]\n"); | ||
712 | } | ||
713 | |||
714 | static ssize_t toggle_deepsleep(struct device *dev, | ||
715 | struct device_attribute *attr, | ||
716 | const char *buf, size_t count) | ||
717 | { | ||
718 | acpi_status status; | ||
719 | struct wmax_basic_args args; | ||
720 | |||
721 | if (strcmp(buf, "disabled\n") == 0) | ||
722 | args.arg = 0; | ||
723 | else if (strcmp(buf, "s5\n") == 0) | ||
724 | args.arg = 1; | ||
725 | else | ||
726 | args.arg = 2; | ||
727 | pr_debug("alienware-wmi: setting deep sleep to %d : %s", args.arg, buf); | ||
728 | |||
729 | status = alienware_wmax_command(&args, WMAX_METHOD_DEEP_SLEEP_CONTROL, | ||
730 | NULL); | ||
731 | |||
732 | if (ACPI_FAILURE(status)) | ||
733 | pr_err("alienware-wmi: deep sleep control failed: results: %u\n", | ||
734 | status); | ||
735 | return count; | ||
736 | } | ||
737 | |||
738 | static DEVICE_ATTR(deepsleep, S_IRUGO | S_IWUSR, show_deepsleep_status, toggle_deepsleep); | ||
739 | |||
740 | static struct attribute *deepsleep_attrs[] = { | ||
741 | &dev_attr_deepsleep.attr, | ||
742 | NULL, | ||
743 | }; | ||
744 | |||
745 | static struct attribute_group deepsleep_attribute_group = { | ||
746 | .name = "deepsleep", | ||
747 | .attrs = deepsleep_attrs, | ||
748 | }; | ||
749 | |||
750 | static void remove_deepsleep(struct platform_device *dev) | ||
751 | { | ||
752 | if (quirks->deepslp > 0) | ||
753 | sysfs_remove_group(&dev->dev.kobj, &deepsleep_attribute_group); | ||
754 | } | ||
755 | |||
756 | static int create_deepsleep(struct platform_device *dev) | ||
757 | { | ||
758 | int ret; | ||
759 | |||
760 | ret = sysfs_create_group(&dev->dev.kobj, &deepsleep_attribute_group); | ||
761 | if (ret) | ||
762 | remove_deepsleep(dev); | ||
571 | return ret; | 763 | return ret; |
572 | } | 764 | } |
573 | 765 | ||
@@ -606,6 +798,18 @@ static int __init alienware_wmi_init(void) | |||
606 | goto fail_prep_hdmi; | 798 | goto fail_prep_hdmi; |
607 | } | 799 | } |
608 | 800 | ||
801 | if (quirks->amplifier > 0) { | ||
802 | ret = create_amplifier(platform_device); | ||
803 | if (ret) | ||
804 | goto fail_prep_amplifier; | ||
805 | } | ||
806 | |||
807 | if (quirks->deepslp > 0) { | ||
808 | ret = create_deepsleep(platform_device); | ||
809 | if (ret) | ||
810 | goto fail_prep_deepsleep; | ||
811 | } | ||
812 | |||
609 | ret = alienware_zone_init(platform_device); | 813 | ret = alienware_zone_init(platform_device); |
610 | if (ret) | 814 | if (ret) |
611 | goto fail_prep_zones; | 815 | goto fail_prep_zones; |
@@ -614,6 +818,8 @@ static int __init alienware_wmi_init(void) | |||
614 | 818 | ||
615 | fail_prep_zones: | 819 | fail_prep_zones: |
616 | alienware_zone_exit(platform_device); | 820 | alienware_zone_exit(platform_device); |
821 | fail_prep_deepsleep: | ||
822 | fail_prep_amplifier: | ||
617 | fail_prep_hdmi: | 823 | fail_prep_hdmi: |
618 | platform_device_del(platform_device); | 824 | platform_device_del(platform_device); |
619 | fail_platform_device2: | 825 | fail_platform_device2: |
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 131fee2b093e..091ca7ada8fc 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c | |||
@@ -272,6 +272,15 @@ static const struct dmi_system_id asus_quirks[] = { | |||
272 | }, | 272 | }, |
273 | { | 273 | { |
274 | .callback = dmi_matched, | 274 | .callback = dmi_matched, |
275 | .ident = "ASUSTeK COMPUTER INC. X75VD", | ||
276 | .matches = { | ||
277 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | ||
278 | DMI_MATCH(DMI_PRODUCT_NAME, "X75VD"), | ||
279 | }, | ||
280 | .driver_data = &quirk_asus_wapf4, | ||
281 | }, | ||
282 | { | ||
283 | .callback = dmi_matched, | ||
275 | .ident = "ASUSTeK COMPUTER INC. 1015E", | 284 | .ident = "ASUSTeK COMPUTER INC. 1015E", |
276 | .matches = { | 285 | .matches = { |
277 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), | 286 | DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), |
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index aaeeae81e3a9..2c2f02b2e08a 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -28,12 +28,11 @@ | |||
28 | #include <linux/acpi.h> | 28 | #include <linux/acpi.h> |
29 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
30 | #include <linux/i8042.h> | 30 | #include <linux/i8042.h> |
31 | #include <linux/slab.h> | ||
32 | #include <linux/debugfs.h> | 31 | #include <linux/debugfs.h> |
33 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
34 | #include <acpi/video.h> | 33 | #include <acpi/video.h> |
35 | #include "../../firmware/dcdbas.h" | ||
36 | #include "dell-rbtn.h" | 34 | #include "dell-rbtn.h" |
35 | #include "dell-smbios.h" | ||
37 | 36 | ||
38 | #define BRIGHTNESS_TOKEN 0x7d | 37 | #define BRIGHTNESS_TOKEN 0x7d |
39 | #define KBD_LED_OFF_TOKEN 0x01E1 | 38 | #define KBD_LED_OFF_TOKEN 0x01E1 |
@@ -44,33 +43,6 @@ | |||
44 | #define KBD_LED_AUTO_75_TOKEN 0x02EC | 43 | #define KBD_LED_AUTO_75_TOKEN 0x02EC |
45 | #define KBD_LED_AUTO_100_TOKEN 0x02F6 | 44 | #define KBD_LED_AUTO_100_TOKEN 0x02F6 |
46 | 45 | ||
47 | /* This structure will be modified by the firmware when we enter | ||
48 | * system management mode, hence the volatiles */ | ||
49 | |||
50 | struct calling_interface_buffer { | ||
51 | u16 class; | ||
52 | u16 select; | ||
53 | volatile u32 input[4]; | ||
54 | volatile u32 output[4]; | ||
55 | } __packed; | ||
56 | |||
57 | struct calling_interface_token { | ||
58 | u16 tokenID; | ||
59 | u16 location; | ||
60 | union { | ||
61 | u16 value; | ||
62 | u16 stringlength; | ||
63 | }; | ||
64 | }; | ||
65 | |||
66 | struct calling_interface_structure { | ||
67 | struct dmi_header header; | ||
68 | u16 cmdIOAddress; | ||
69 | u8 cmdIOCode; | ||
70 | u32 supportedCmds; | ||
71 | struct calling_interface_token tokens[]; | ||
72 | } __packed; | ||
73 | |||
74 | struct quirk_entry { | 46 | struct quirk_entry { |
75 | u8 touchpad_led; | 47 | u8 touchpad_led; |
76 | 48 | ||
@@ -103,11 +75,6 @@ static struct quirk_entry quirk_dell_xps13_9333 = { | |||
103 | .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, | 75 | .kbd_timeouts = { 0, 5, 15, 60, 5 * 60, 15 * 60, -1 }, |
104 | }; | 76 | }; |
105 | 77 | ||
106 | static int da_command_address; | ||
107 | static int da_command_code; | ||
108 | static int da_num_tokens; | ||
109 | static struct calling_interface_token *da_tokens; | ||
110 | |||
111 | static struct platform_driver platform_driver = { | 78 | static struct platform_driver platform_driver = { |
112 | .driver = { | 79 | .driver = { |
113 | .name = "dell-laptop", | 80 | .name = "dell-laptop", |
@@ -306,126 +273,6 @@ static const struct dmi_system_id dell_quirks[] __initconst = { | |||
306 | { } | 273 | { } |
307 | }; | 274 | }; |
308 | 275 | ||
309 | static struct calling_interface_buffer *buffer; | ||
310 | static DEFINE_MUTEX(buffer_mutex); | ||
311 | |||
312 | static void clear_buffer(void) | ||
313 | { | ||
314 | memset(buffer, 0, sizeof(struct calling_interface_buffer)); | ||
315 | } | ||
316 | |||
317 | static void get_buffer(void) | ||
318 | { | ||
319 | mutex_lock(&buffer_mutex); | ||
320 | clear_buffer(); | ||
321 | } | ||
322 | |||
323 | static void release_buffer(void) | ||
324 | { | ||
325 | mutex_unlock(&buffer_mutex); | ||
326 | } | ||
327 | |||
328 | static void __init parse_da_table(const struct dmi_header *dm) | ||
329 | { | ||
330 | /* Final token is a terminator, so we don't want to copy it */ | ||
331 | int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; | ||
332 | struct calling_interface_token *new_da_tokens; | ||
333 | struct calling_interface_structure *table = | ||
334 | container_of(dm, struct calling_interface_structure, header); | ||
335 | |||
336 | /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least | ||
337 | 6 bytes of entry */ | ||
338 | |||
339 | if (dm->length < 17) | ||
340 | return; | ||
341 | |||
342 | da_command_address = table->cmdIOAddress; | ||
343 | da_command_code = table->cmdIOCode; | ||
344 | |||
345 | new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * | ||
346 | sizeof(struct calling_interface_token), | ||
347 | GFP_KERNEL); | ||
348 | |||
349 | if (!new_da_tokens) | ||
350 | return; | ||
351 | da_tokens = new_da_tokens; | ||
352 | |||
353 | memcpy(da_tokens+da_num_tokens, table->tokens, | ||
354 | sizeof(struct calling_interface_token) * tokens); | ||
355 | |||
356 | da_num_tokens += tokens; | ||
357 | } | ||
358 | |||
359 | static void __init find_tokens(const struct dmi_header *dm, void *dummy) | ||
360 | { | ||
361 | switch (dm->type) { | ||
362 | case 0xd4: /* Indexed IO */ | ||
363 | case 0xd5: /* Protected Area Type 1 */ | ||
364 | case 0xd6: /* Protected Area Type 2 */ | ||
365 | break; | ||
366 | case 0xda: /* Calling interface */ | ||
367 | parse_da_table(dm); | ||
368 | break; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | static int find_token_id(int tokenid) | ||
373 | { | ||
374 | int i; | ||
375 | |||
376 | for (i = 0; i < da_num_tokens; i++) { | ||
377 | if (da_tokens[i].tokenID == tokenid) | ||
378 | return i; | ||
379 | } | ||
380 | |||
381 | return -1; | ||
382 | } | ||
383 | |||
384 | static int find_token_location(int tokenid) | ||
385 | { | ||
386 | int id; | ||
387 | |||
388 | id = find_token_id(tokenid); | ||
389 | if (id == -1) | ||
390 | return -1; | ||
391 | |||
392 | return da_tokens[id].location; | ||
393 | } | ||
394 | |||
395 | static struct calling_interface_buffer * | ||
396 | dell_send_request(struct calling_interface_buffer *buffer, int class, | ||
397 | int select) | ||
398 | { | ||
399 | struct smi_cmd command; | ||
400 | |||
401 | command.magic = SMI_CMD_MAGIC; | ||
402 | command.command_address = da_command_address; | ||
403 | command.command_code = da_command_code; | ||
404 | command.ebx = virt_to_phys(buffer); | ||
405 | command.ecx = 0x42534931; | ||
406 | |||
407 | buffer->class = class; | ||
408 | buffer->select = select; | ||
409 | |||
410 | dcdbas_smi_request(&command); | ||
411 | |||
412 | return buffer; | ||
413 | } | ||
414 | |||
415 | static inline int dell_smi_error(int value) | ||
416 | { | ||
417 | switch (value) { | ||
418 | case 0: /* Completed successfully */ | ||
419 | return 0; | ||
420 | case -1: /* Completed with error */ | ||
421 | return -EIO; | ||
422 | case -2: /* Function not supported */ | ||
423 | return -ENXIO; | ||
424 | default: /* Unknown error */ | ||
425 | return -EINVAL; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | /* | 276 | /* |
430 | * Derived from information in smbios-wireless-ctl: | 277 | * Derived from information in smbios-wireless-ctl: |
431 | * | 278 | * |
@@ -548,6 +395,7 @@ static inline int dell_smi_error(int value) | |||
548 | 395 | ||
549 | static int dell_rfkill_set(void *data, bool blocked) | 396 | static int dell_rfkill_set(void *data, bool blocked) |
550 | { | 397 | { |
398 | struct calling_interface_buffer *buffer; | ||
551 | int disable = blocked ? 1 : 0; | 399 | int disable = blocked ? 1 : 0; |
552 | unsigned long radio = (unsigned long)data; | 400 | unsigned long radio = (unsigned long)data; |
553 | int hwswitch_bit = (unsigned long)data - 1; | 401 | int hwswitch_bit = (unsigned long)data - 1; |
@@ -555,19 +403,19 @@ static int dell_rfkill_set(void *data, bool blocked) | |||
555 | int status; | 403 | int status; |
556 | int ret; | 404 | int ret; |
557 | 405 | ||
558 | get_buffer(); | 406 | buffer = dell_smbios_get_buffer(); |
559 | 407 | ||
560 | dell_send_request(buffer, 17, 11); | 408 | dell_smbios_send_request(17, 11); |
561 | ret = buffer->output[0]; | 409 | ret = buffer->output[0]; |
562 | status = buffer->output[1]; | 410 | status = buffer->output[1]; |
563 | 411 | ||
564 | if (ret != 0) | 412 | if (ret != 0) |
565 | goto out; | 413 | goto out; |
566 | 414 | ||
567 | clear_buffer(); | 415 | dell_smbios_clear_buffer(); |
568 | 416 | ||
569 | buffer->input[0] = 0x2; | 417 | buffer->input[0] = 0x2; |
570 | dell_send_request(buffer, 17, 11); | 418 | dell_smbios_send_request(17, 11); |
571 | ret = buffer->output[0]; | 419 | ret = buffer->output[0]; |
572 | hwswitch = buffer->output[1]; | 420 | hwswitch = buffer->output[1]; |
573 | 421 | ||
@@ -577,27 +425,28 @@ static int dell_rfkill_set(void *data, bool blocked) | |||
577 | (status & BIT(0)) && !(status & BIT(16))) | 425 | (status & BIT(0)) && !(status & BIT(16))) |
578 | disable = 1; | 426 | disable = 1; |
579 | 427 | ||
580 | clear_buffer(); | 428 | dell_smbios_clear_buffer(); |
581 | 429 | ||
582 | buffer->input[0] = (1 | (radio<<8) | (disable << 16)); | 430 | buffer->input[0] = (1 | (radio<<8) | (disable << 16)); |
583 | dell_send_request(buffer, 17, 11); | 431 | dell_smbios_send_request(17, 11); |
584 | ret = buffer->output[0]; | 432 | ret = buffer->output[0]; |
585 | 433 | ||
586 | out: | 434 | out: |
587 | release_buffer(); | 435 | dell_smbios_release_buffer(); |
588 | return dell_smi_error(ret); | 436 | return dell_smbios_error(ret); |
589 | } | 437 | } |
590 | 438 | ||
591 | /* Must be called with the buffer held */ | 439 | /* Must be called with the buffer held */ |
592 | static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, | 440 | static void dell_rfkill_update_sw_state(struct rfkill *rfkill, int radio, |
593 | int status) | 441 | int status, |
442 | struct calling_interface_buffer *buffer) | ||
594 | { | 443 | { |
595 | if (status & BIT(0)) { | 444 | if (status & BIT(0)) { |
596 | /* Has hw-switch, sync sw_state to BIOS */ | 445 | /* Has hw-switch, sync sw_state to BIOS */ |
597 | int block = rfkill_blocked(rfkill); | 446 | int block = rfkill_blocked(rfkill); |
598 | clear_buffer(); | 447 | dell_smbios_clear_buffer(); |
599 | buffer->input[0] = (1 | (radio << 8) | (block << 16)); | 448 | buffer->input[0] = (1 | (radio << 8) | (block << 16)); |
600 | dell_send_request(buffer, 17, 11); | 449 | dell_smbios_send_request(17, 11); |
601 | } else { | 450 | } else { |
602 | /* No hw-switch, sync BIOS state to sw_state */ | 451 | /* No hw-switch, sync BIOS state to sw_state */ |
603 | rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); | 452 | rfkill_set_sw_state(rfkill, !!(status & BIT(radio + 16))); |
@@ -613,30 +462,31 @@ static void dell_rfkill_update_hw_state(struct rfkill *rfkill, int radio, | |||
613 | 462 | ||
614 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) | 463 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) |
615 | { | 464 | { |
465 | struct calling_interface_buffer *buffer; | ||
616 | int radio = ((unsigned long)data & 0xF); | 466 | int radio = ((unsigned long)data & 0xF); |
617 | int hwswitch; | 467 | int hwswitch; |
618 | int status; | 468 | int status; |
619 | int ret; | 469 | int ret; |
620 | 470 | ||
621 | get_buffer(); | 471 | buffer = dell_smbios_get_buffer(); |
622 | 472 | ||
623 | dell_send_request(buffer, 17, 11); | 473 | dell_smbios_send_request(17, 11); |
624 | ret = buffer->output[0]; | 474 | ret = buffer->output[0]; |
625 | status = buffer->output[1]; | 475 | status = buffer->output[1]; |
626 | 476 | ||
627 | if (ret != 0 || !(status & BIT(0))) { | 477 | if (ret != 0 || !(status & BIT(0))) { |
628 | release_buffer(); | 478 | dell_smbios_release_buffer(); |
629 | return; | 479 | return; |
630 | } | 480 | } |
631 | 481 | ||
632 | clear_buffer(); | 482 | dell_smbios_clear_buffer(); |
633 | 483 | ||
634 | buffer->input[0] = 0x2; | 484 | buffer->input[0] = 0x2; |
635 | dell_send_request(buffer, 17, 11); | 485 | dell_smbios_send_request(17, 11); |
636 | ret = buffer->output[0]; | 486 | ret = buffer->output[0]; |
637 | hwswitch = buffer->output[1]; | 487 | hwswitch = buffer->output[1]; |
638 | 488 | ||
639 | release_buffer(); | 489 | dell_smbios_release_buffer(); |
640 | 490 | ||
641 | if (ret != 0) | 491 | if (ret != 0) |
642 | return; | 492 | return; |
@@ -653,25 +503,26 @@ static struct dentry *dell_laptop_dir; | |||
653 | 503 | ||
654 | static int dell_debugfs_show(struct seq_file *s, void *data) | 504 | static int dell_debugfs_show(struct seq_file *s, void *data) |
655 | { | 505 | { |
506 | struct calling_interface_buffer *buffer; | ||
656 | int hwswitch_state; | 507 | int hwswitch_state; |
657 | int hwswitch_ret; | 508 | int hwswitch_ret; |
658 | int status; | 509 | int status; |
659 | int ret; | 510 | int ret; |
660 | 511 | ||
661 | get_buffer(); | 512 | buffer = dell_smbios_get_buffer(); |
662 | 513 | ||
663 | dell_send_request(buffer, 17, 11); | 514 | dell_smbios_send_request(17, 11); |
664 | ret = buffer->output[0]; | 515 | ret = buffer->output[0]; |
665 | status = buffer->output[1]; | 516 | status = buffer->output[1]; |
666 | 517 | ||
667 | clear_buffer(); | 518 | dell_smbios_clear_buffer(); |
668 | 519 | ||
669 | buffer->input[0] = 0x2; | 520 | buffer->input[0] = 0x2; |
670 | dell_send_request(buffer, 17, 11); | 521 | dell_smbios_send_request(17, 11); |
671 | hwswitch_ret = buffer->output[0]; | 522 | hwswitch_ret = buffer->output[0]; |
672 | hwswitch_state = buffer->output[1]; | 523 | hwswitch_state = buffer->output[1]; |
673 | 524 | ||
674 | release_buffer(); | 525 | dell_smbios_release_buffer(); |
675 | 526 | ||
676 | seq_printf(s, "return:\t%d\n", ret); | 527 | seq_printf(s, "return:\t%d\n", ret); |
677 | seq_printf(s, "status:\t0x%X\n", status); | 528 | seq_printf(s, "status:\t0x%X\n", status); |
@@ -752,23 +603,24 @@ static const struct file_operations dell_debugfs_fops = { | |||
752 | 603 | ||
753 | static void dell_update_rfkill(struct work_struct *ignored) | 604 | static void dell_update_rfkill(struct work_struct *ignored) |
754 | { | 605 | { |
606 | struct calling_interface_buffer *buffer; | ||
755 | int hwswitch = 0; | 607 | int hwswitch = 0; |
756 | int status; | 608 | int status; |
757 | int ret; | 609 | int ret; |
758 | 610 | ||
759 | get_buffer(); | 611 | buffer = dell_smbios_get_buffer(); |
760 | 612 | ||
761 | dell_send_request(buffer, 17, 11); | 613 | dell_smbios_send_request(17, 11); |
762 | ret = buffer->output[0]; | 614 | ret = buffer->output[0]; |
763 | status = buffer->output[1]; | 615 | status = buffer->output[1]; |
764 | 616 | ||
765 | if (ret != 0) | 617 | if (ret != 0) |
766 | goto out; | 618 | goto out; |
767 | 619 | ||
768 | clear_buffer(); | 620 | dell_smbios_clear_buffer(); |
769 | 621 | ||
770 | buffer->input[0] = 0x2; | 622 | buffer->input[0] = 0x2; |
771 | dell_send_request(buffer, 17, 11); | 623 | dell_smbios_send_request(17, 11); |
772 | ret = buffer->output[0]; | 624 | ret = buffer->output[0]; |
773 | 625 | ||
774 | if (ret == 0 && (status & BIT(0))) | 626 | if (ret == 0 && (status & BIT(0))) |
@@ -776,20 +628,21 @@ static void dell_update_rfkill(struct work_struct *ignored) | |||
776 | 628 | ||
777 | if (wifi_rfkill) { | 629 | if (wifi_rfkill) { |
778 | dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch); | 630 | dell_rfkill_update_hw_state(wifi_rfkill, 1, status, hwswitch); |
779 | dell_rfkill_update_sw_state(wifi_rfkill, 1, status); | 631 | dell_rfkill_update_sw_state(wifi_rfkill, 1, status, buffer); |
780 | } | 632 | } |
781 | if (bluetooth_rfkill) { | 633 | if (bluetooth_rfkill) { |
782 | dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status, | 634 | dell_rfkill_update_hw_state(bluetooth_rfkill, 2, status, |
783 | hwswitch); | 635 | hwswitch); |
784 | dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status); | 636 | dell_rfkill_update_sw_state(bluetooth_rfkill, 2, status, |
637 | buffer); | ||
785 | } | 638 | } |
786 | if (wwan_rfkill) { | 639 | if (wwan_rfkill) { |
787 | dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch); | 640 | dell_rfkill_update_hw_state(wwan_rfkill, 3, status, hwswitch); |
788 | dell_rfkill_update_sw_state(wwan_rfkill, 3, status); | 641 | dell_rfkill_update_sw_state(wwan_rfkill, 3, status, buffer); |
789 | } | 642 | } |
790 | 643 | ||
791 | out: | 644 | out: |
792 | release_buffer(); | 645 | dell_smbios_release_buffer(); |
793 | } | 646 | } |
794 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | 647 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); |
795 | 648 | ||
@@ -833,6 +686,7 @@ static struct notifier_block dell_laptop_rbtn_notifier = { | |||
833 | 686 | ||
834 | static int __init dell_setup_rfkill(void) | 687 | static int __init dell_setup_rfkill(void) |
835 | { | 688 | { |
689 | struct calling_interface_buffer *buffer; | ||
836 | int status, ret, whitelisted; | 690 | int status, ret, whitelisted; |
837 | const char *product; | 691 | const char *product; |
838 | 692 | ||
@@ -848,11 +702,11 @@ static int __init dell_setup_rfkill(void) | |||
848 | if (!force_rfkill && !whitelisted) | 702 | if (!force_rfkill && !whitelisted) |
849 | return 0; | 703 | return 0; |
850 | 704 | ||
851 | get_buffer(); | 705 | buffer = dell_smbios_get_buffer(); |
852 | dell_send_request(buffer, 17, 11); | 706 | dell_smbios_send_request(17, 11); |
853 | ret = buffer->output[0]; | 707 | ret = buffer->output[0]; |
854 | status = buffer->output[1]; | 708 | status = buffer->output[1]; |
855 | release_buffer(); | 709 | dell_smbios_release_buffer(); |
856 | 710 | ||
857 | /* dell wireless info smbios call is not supported */ | 711 | /* dell wireless info smbios call is not supported */ |
858 | if (ret != 0) | 712 | if (ret != 0) |
@@ -1005,51 +859,53 @@ static void dell_cleanup_rfkill(void) | |||
1005 | 859 | ||
1006 | static int dell_send_intensity(struct backlight_device *bd) | 860 | static int dell_send_intensity(struct backlight_device *bd) |
1007 | { | 861 | { |
1008 | int token; | 862 | struct calling_interface_buffer *buffer; |
863 | struct calling_interface_token *token; | ||
1009 | int ret; | 864 | int ret; |
1010 | 865 | ||
1011 | token = find_token_location(BRIGHTNESS_TOKEN); | 866 | token = dell_smbios_find_token(BRIGHTNESS_TOKEN); |
1012 | if (token == -1) | 867 | if (!token) |
1013 | return -ENODEV; | 868 | return -ENODEV; |
1014 | 869 | ||
1015 | get_buffer(); | 870 | buffer = dell_smbios_get_buffer(); |
1016 | buffer->input[0] = token; | 871 | buffer->input[0] = token->location; |
1017 | buffer->input[1] = bd->props.brightness; | 872 | buffer->input[1] = bd->props.brightness; |
1018 | 873 | ||
1019 | if (power_supply_is_system_supplied() > 0) | 874 | if (power_supply_is_system_supplied() > 0) |
1020 | dell_send_request(buffer, 1, 2); | 875 | dell_smbios_send_request(1, 2); |
1021 | else | 876 | else |
1022 | dell_send_request(buffer, 1, 1); | 877 | dell_smbios_send_request(1, 1); |
1023 | 878 | ||
1024 | ret = dell_smi_error(buffer->output[0]); | 879 | ret = dell_smbios_error(buffer->output[0]); |
1025 | 880 | ||
1026 | release_buffer(); | 881 | dell_smbios_release_buffer(); |
1027 | return ret; | 882 | return ret; |
1028 | } | 883 | } |
1029 | 884 | ||
1030 | static int dell_get_intensity(struct backlight_device *bd) | 885 | static int dell_get_intensity(struct backlight_device *bd) |
1031 | { | 886 | { |
1032 | int token; | 887 | struct calling_interface_buffer *buffer; |
888 | struct calling_interface_token *token; | ||
1033 | int ret; | 889 | int ret; |
1034 | 890 | ||
1035 | token = find_token_location(BRIGHTNESS_TOKEN); | 891 | token = dell_smbios_find_token(BRIGHTNESS_TOKEN); |
1036 | if (token == -1) | 892 | if (!token) |
1037 | return -ENODEV; | 893 | return -ENODEV; |
1038 | 894 | ||
1039 | get_buffer(); | 895 | buffer = dell_smbios_get_buffer(); |
1040 | buffer->input[0] = token; | 896 | buffer->input[0] = token->location; |
1041 | 897 | ||
1042 | if (power_supply_is_system_supplied() > 0) | 898 | if (power_supply_is_system_supplied() > 0) |
1043 | dell_send_request(buffer, 0, 2); | 899 | dell_smbios_send_request(0, 2); |
1044 | else | 900 | else |
1045 | dell_send_request(buffer, 0, 1); | 901 | dell_smbios_send_request(0, 1); |
1046 | 902 | ||
1047 | if (buffer->output[0]) | 903 | if (buffer->output[0]) |
1048 | ret = dell_smi_error(buffer->output[0]); | 904 | ret = dell_smbios_error(buffer->output[0]); |
1049 | else | 905 | else |
1050 | ret = buffer->output[1]; | 906 | ret = buffer->output[1]; |
1051 | 907 | ||
1052 | release_buffer(); | 908 | dell_smbios_release_buffer(); |
1053 | return ret; | 909 | return ret; |
1054 | } | 910 | } |
1055 | 911 | ||
@@ -1293,17 +1149,18 @@ static bool kbd_led_present; | |||
1293 | 1149 | ||
1294 | static int kbd_get_info(struct kbd_info *info) | 1150 | static int kbd_get_info(struct kbd_info *info) |
1295 | { | 1151 | { |
1152 | struct calling_interface_buffer *buffer; | ||
1296 | u8 units; | 1153 | u8 units; |
1297 | int ret; | 1154 | int ret; |
1298 | 1155 | ||
1299 | get_buffer(); | 1156 | buffer = dell_smbios_get_buffer(); |
1300 | 1157 | ||
1301 | buffer->input[0] = 0x0; | 1158 | buffer->input[0] = 0x0; |
1302 | dell_send_request(buffer, 4, 11); | 1159 | dell_smbios_send_request(4, 11); |
1303 | ret = buffer->output[0]; | 1160 | ret = buffer->output[0]; |
1304 | 1161 | ||
1305 | if (ret) { | 1162 | if (ret) { |
1306 | ret = dell_smi_error(ret); | 1163 | ret = dell_smbios_error(ret); |
1307 | goto out; | 1164 | goto out; |
1308 | } | 1165 | } |
1309 | 1166 | ||
@@ -1323,7 +1180,7 @@ static int kbd_get_info(struct kbd_info *info) | |||
1323 | info->days = (buffer->output[3] >> 24) & 0xFF; | 1180 | info->days = (buffer->output[3] >> 24) & 0xFF; |
1324 | 1181 | ||
1325 | out: | 1182 | out: |
1326 | release_buffer(); | 1183 | dell_smbios_release_buffer(); |
1327 | return ret; | 1184 | return ret; |
1328 | } | 1185 | } |
1329 | 1186 | ||
@@ -1382,16 +1239,17 @@ static int kbd_set_level(struct kbd_state *state, u8 level) | |||
1382 | 1239 | ||
1383 | static int kbd_get_state(struct kbd_state *state) | 1240 | static int kbd_get_state(struct kbd_state *state) |
1384 | { | 1241 | { |
1242 | struct calling_interface_buffer *buffer; | ||
1385 | int ret; | 1243 | int ret; |
1386 | 1244 | ||
1387 | get_buffer(); | 1245 | buffer = dell_smbios_get_buffer(); |
1388 | 1246 | ||
1389 | buffer->input[0] = 0x1; | 1247 | buffer->input[0] = 0x1; |
1390 | dell_send_request(buffer, 4, 11); | 1248 | dell_smbios_send_request(4, 11); |
1391 | ret = buffer->output[0]; | 1249 | ret = buffer->output[0]; |
1392 | 1250 | ||
1393 | if (ret) { | 1251 | if (ret) { |
1394 | ret = dell_smi_error(ret); | 1252 | ret = dell_smbios_error(ret); |
1395 | goto out; | 1253 | goto out; |
1396 | } | 1254 | } |
1397 | 1255 | ||
@@ -1407,15 +1265,16 @@ static int kbd_get_state(struct kbd_state *state) | |||
1407 | state->level = (buffer->output[2] >> 16) & 0xFF; | 1265 | state->level = (buffer->output[2] >> 16) & 0xFF; |
1408 | 1266 | ||
1409 | out: | 1267 | out: |
1410 | release_buffer(); | 1268 | dell_smbios_release_buffer(); |
1411 | return ret; | 1269 | return ret; |
1412 | } | 1270 | } |
1413 | 1271 | ||
1414 | static int kbd_set_state(struct kbd_state *state) | 1272 | static int kbd_set_state(struct kbd_state *state) |
1415 | { | 1273 | { |
1274 | struct calling_interface_buffer *buffer; | ||
1416 | int ret; | 1275 | int ret; |
1417 | 1276 | ||
1418 | get_buffer(); | 1277 | buffer = dell_smbios_get_buffer(); |
1419 | buffer->input[0] = 0x2; | 1278 | buffer->input[0] = 0x2; |
1420 | buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; | 1279 | buffer->input[1] = BIT(state->mode_bit) & 0xFFFF; |
1421 | buffer->input[1] |= (state->triggers & 0xFF) << 16; | 1280 | buffer->input[1] |= (state->triggers & 0xFF) << 16; |
@@ -1423,11 +1282,11 @@ static int kbd_set_state(struct kbd_state *state) | |||
1423 | buffer->input[1] |= (state->timeout_unit & 0x3) << 30; | 1282 | buffer->input[1] |= (state->timeout_unit & 0x3) << 30; |
1424 | buffer->input[2] = state->als_setting & 0xFF; | 1283 | buffer->input[2] = state->als_setting & 0xFF; |
1425 | buffer->input[2] |= (state->level & 0xFF) << 16; | 1284 | buffer->input[2] |= (state->level & 0xFF) << 16; |
1426 | dell_send_request(buffer, 4, 11); | 1285 | dell_smbios_send_request(4, 11); |
1427 | ret = buffer->output[0]; | 1286 | ret = buffer->output[0]; |
1428 | release_buffer(); | 1287 | dell_smbios_release_buffer(); |
1429 | 1288 | ||
1430 | return dell_smi_error(ret); | 1289 | return dell_smbios_error(ret); |
1431 | } | 1290 | } |
1432 | 1291 | ||
1433 | static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) | 1292 | static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) |
@@ -1452,50 +1311,52 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old) | |||
1452 | 1311 | ||
1453 | static int kbd_set_token_bit(u8 bit) | 1312 | static int kbd_set_token_bit(u8 bit) |
1454 | { | 1313 | { |
1455 | int id; | 1314 | struct calling_interface_buffer *buffer; |
1315 | struct calling_interface_token *token; | ||
1456 | int ret; | 1316 | int ret; |
1457 | 1317 | ||
1458 | if (bit >= ARRAY_SIZE(kbd_tokens)) | 1318 | if (bit >= ARRAY_SIZE(kbd_tokens)) |
1459 | return -EINVAL; | 1319 | return -EINVAL; |
1460 | 1320 | ||
1461 | id = find_token_id(kbd_tokens[bit]); | 1321 | token = dell_smbios_find_token(kbd_tokens[bit]); |
1462 | if (id == -1) | 1322 | if (!token) |
1463 | return -EINVAL; | 1323 | return -EINVAL; |
1464 | 1324 | ||
1465 | get_buffer(); | 1325 | buffer = dell_smbios_get_buffer(); |
1466 | buffer->input[0] = da_tokens[id].location; | 1326 | buffer->input[0] = token->location; |
1467 | buffer->input[1] = da_tokens[id].value; | 1327 | buffer->input[1] = token->value; |
1468 | dell_send_request(buffer, 1, 0); | 1328 | dell_smbios_send_request(1, 0); |
1469 | ret = buffer->output[0]; | 1329 | ret = buffer->output[0]; |
1470 | release_buffer(); | 1330 | dell_smbios_release_buffer(); |
1471 | 1331 | ||
1472 | return dell_smi_error(ret); | 1332 | return dell_smbios_error(ret); |
1473 | } | 1333 | } |
1474 | 1334 | ||
1475 | static int kbd_get_token_bit(u8 bit) | 1335 | static int kbd_get_token_bit(u8 bit) |
1476 | { | 1336 | { |
1477 | int id; | 1337 | struct calling_interface_buffer *buffer; |
1338 | struct calling_interface_token *token; | ||
1478 | int ret; | 1339 | int ret; |
1479 | int val; | 1340 | int val; |
1480 | 1341 | ||
1481 | if (bit >= ARRAY_SIZE(kbd_tokens)) | 1342 | if (bit >= ARRAY_SIZE(kbd_tokens)) |
1482 | return -EINVAL; | 1343 | return -EINVAL; |
1483 | 1344 | ||
1484 | id = find_token_id(kbd_tokens[bit]); | 1345 | token = dell_smbios_find_token(kbd_tokens[bit]); |
1485 | if (id == -1) | 1346 | if (!token) |
1486 | return -EINVAL; | 1347 | return -EINVAL; |
1487 | 1348 | ||
1488 | get_buffer(); | 1349 | buffer = dell_smbios_get_buffer(); |
1489 | buffer->input[0] = da_tokens[id].location; | 1350 | buffer->input[0] = token->location; |
1490 | dell_send_request(buffer, 0, 0); | 1351 | dell_smbios_send_request(0, 0); |
1491 | ret = buffer->output[0]; | 1352 | ret = buffer->output[0]; |
1492 | val = buffer->output[1]; | 1353 | val = buffer->output[1]; |
1493 | release_buffer(); | 1354 | dell_smbios_release_buffer(); |
1494 | 1355 | ||
1495 | if (ret) | 1356 | if (ret) |
1496 | return dell_smi_error(ret); | 1357 | return dell_smbios_error(ret); |
1497 | 1358 | ||
1498 | return (val == da_tokens[id].value); | 1359 | return (val == token->value); |
1499 | } | 1360 | } |
1500 | 1361 | ||
1501 | static int kbd_get_first_active_token_bit(void) | 1362 | static int kbd_get_first_active_token_bit(void) |
@@ -1597,7 +1458,7 @@ static inline void kbd_init_tokens(void) | |||
1597 | int i; | 1458 | int i; |
1598 | 1459 | ||
1599 | for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) | 1460 | for (i = 0; i < ARRAY_SIZE(kbd_tokens); ++i) |
1600 | if (find_token_id(kbd_tokens[i]) != -1) | 1461 | if (dell_smbios_find_token(kbd_tokens[i])) |
1601 | kbd_token_bits |= BIT(i); | 1462 | kbd_token_bits |= BIT(i); |
1602 | } | 1463 | } |
1603 | 1464 | ||
@@ -2111,8 +1972,9 @@ static void kbd_led_exit(void) | |||
2111 | 1972 | ||
2112 | static int __init dell_init(void) | 1973 | static int __init dell_init(void) |
2113 | { | 1974 | { |
1975 | struct calling_interface_buffer *buffer; | ||
1976 | struct calling_interface_token *token; | ||
2114 | int max_intensity = 0; | 1977 | int max_intensity = 0; |
2115 | int token; | ||
2116 | int ret; | 1978 | int ret; |
2117 | 1979 | ||
2118 | if (!dmi_check_system(dell_device_table)) | 1980 | if (!dmi_check_system(dell_device_table)) |
@@ -2122,13 +1984,6 @@ static int __init dell_init(void) | |||
2122 | /* find if this machine support other functions */ | 1984 | /* find if this machine support other functions */ |
2123 | dmi_check_system(dell_quirks); | 1985 | dmi_check_system(dell_quirks); |
2124 | 1986 | ||
2125 | dmi_walk(find_tokens, NULL); | ||
2126 | |||
2127 | if (!da_tokens) { | ||
2128 | pr_info("Unable to find dmi tokens\n"); | ||
2129 | return -ENODEV; | ||
2130 | } | ||
2131 | |||
2132 | ret = platform_driver_register(&platform_driver); | 1987 | ret = platform_driver_register(&platform_driver); |
2133 | if (ret) | 1988 | if (ret) |
2134 | goto fail_platform_driver; | 1989 | goto fail_platform_driver; |
@@ -2141,16 +1996,6 @@ static int __init dell_init(void) | |||
2141 | if (ret) | 1996 | if (ret) |
2142 | goto fail_platform_device2; | 1997 | goto fail_platform_device2; |
2143 | 1998 | ||
2144 | /* | ||
2145 | * Allocate buffer below 4GB for SMI data--only 32-bit physical addr | ||
2146 | * is passed to SMI handler. | ||
2147 | */ | ||
2148 | buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); | ||
2149 | if (!buffer) { | ||
2150 | ret = -ENOMEM; | ||
2151 | goto fail_buffer; | ||
2152 | } | ||
2153 | |||
2154 | ret = dell_setup_rfkill(); | 1999 | ret = dell_setup_rfkill(); |
2155 | 2000 | ||
2156 | if (ret) { | 2001 | if (ret) { |
@@ -2171,14 +2016,14 @@ static int __init dell_init(void) | |||
2171 | if (acpi_video_get_backlight_type() != acpi_backlight_vendor) | 2016 | if (acpi_video_get_backlight_type() != acpi_backlight_vendor) |
2172 | return 0; | 2017 | return 0; |
2173 | 2018 | ||
2174 | token = find_token_location(BRIGHTNESS_TOKEN); | 2019 | token = dell_smbios_find_token(BRIGHTNESS_TOKEN); |
2175 | if (token != -1) { | 2020 | if (token) { |
2176 | get_buffer(); | 2021 | buffer = dell_smbios_get_buffer(); |
2177 | buffer->input[0] = token; | 2022 | buffer->input[0] = token->location; |
2178 | dell_send_request(buffer, 0, 2); | 2023 | dell_smbios_send_request(0, 2); |
2179 | if (buffer->output[0] == 0) | 2024 | if (buffer->output[0] == 0) |
2180 | max_intensity = buffer->output[3]; | 2025 | max_intensity = buffer->output[3]; |
2181 | release_buffer(); | 2026 | dell_smbios_release_buffer(); |
2182 | } | 2027 | } |
2183 | 2028 | ||
2184 | if (max_intensity) { | 2029 | if (max_intensity) { |
@@ -2208,15 +2053,12 @@ static int __init dell_init(void) | |||
2208 | fail_backlight: | 2053 | fail_backlight: |
2209 | dell_cleanup_rfkill(); | 2054 | dell_cleanup_rfkill(); |
2210 | fail_rfkill: | 2055 | fail_rfkill: |
2211 | free_page((unsigned long)buffer); | ||
2212 | fail_buffer: | ||
2213 | platform_device_del(platform_device); | 2056 | platform_device_del(platform_device); |
2214 | fail_platform_device2: | 2057 | fail_platform_device2: |
2215 | platform_device_put(platform_device); | 2058 | platform_device_put(platform_device); |
2216 | fail_platform_device1: | 2059 | fail_platform_device1: |
2217 | platform_driver_unregister(&platform_driver); | 2060 | platform_driver_unregister(&platform_driver); |
2218 | fail_platform_driver: | 2061 | fail_platform_driver: |
2219 | kfree(da_tokens); | ||
2220 | return ret; | 2062 | return ret; |
2221 | } | 2063 | } |
2222 | 2064 | ||
@@ -2232,8 +2074,6 @@ static void __exit dell_exit(void) | |||
2232 | platform_device_unregister(platform_device); | 2074 | platform_device_unregister(platform_device); |
2233 | platform_driver_unregister(&platform_driver); | 2075 | platform_driver_unregister(&platform_driver); |
2234 | } | 2076 | } |
2235 | kfree(da_tokens); | ||
2236 | free_page((unsigned long)buffer); | ||
2237 | } | 2077 | } |
2238 | 2078 | ||
2239 | /* dell-rbtn.c driver export functions which will not work correctly (and could | 2079 | /* dell-rbtn.c driver export functions which will not work correctly (and could |
diff --git a/drivers/platform/x86/dell-rbtn.c b/drivers/platform/x86/dell-rbtn.c index cd410e392550..b51a2008d782 100644 --- a/drivers/platform/x86/dell-rbtn.c +++ b/drivers/platform/x86/dell-rbtn.c | |||
@@ -217,6 +217,21 @@ static void rbtn_notify(struct acpi_device *device, u32 event); | |||
217 | static const struct acpi_device_id rbtn_ids[] = { | 217 | static const struct acpi_device_id rbtn_ids[] = { |
218 | { "DELRBTN", 0 }, | 218 | { "DELRBTN", 0 }, |
219 | { "DELLABCE", 0 }, | 219 | { "DELLABCE", 0 }, |
220 | |||
221 | /* | ||
222 | * This driver can also handle the "DELLABC6" device that | ||
223 | * appears on the XPS 13 9350, but that device is disabled | ||
224 | * by the DSDT unless booted with acpi_osi="!Windows 2012" | ||
225 | * acpi_osi="!Windows 2013". Even if we boot that and bind | ||
226 | * the driver, we seem to have inconsistent behavior in | ||
227 | * which NetworkManager can get out of sync with the rfkill | ||
228 | * state. | ||
229 | * | ||
230 | * On the XPS 13 9350 and similar laptops, we're not supposed to | ||
231 | * use DELLABC6 at all. Instead, we handle the rfkill button | ||
232 | * via the intel-hid driver. | ||
233 | */ | ||
234 | |||
220 | { "", 0 }, | 235 | { "", 0 }, |
221 | }; | 236 | }; |
222 | 237 | ||
diff --git a/drivers/platform/x86/dell-smbios.c b/drivers/platform/x86/dell-smbios.c new file mode 100644 index 000000000000..d2412ab097da --- /dev/null +++ b/drivers/platform/x86/dell-smbios.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * Common functions for kernel modules using Dell SMBIOS | ||
3 | * | ||
4 | * Copyright (c) Red Hat <mjg@redhat.com> | ||
5 | * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com> | ||
6 | * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com> | ||
7 | * | ||
8 | * Based on documentation in the libsmbios package: | ||
9 | * Copyright (C) 2005-2014 Dell Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/kernel.h> | ||
17 | #include <linux/module.h> | ||
18 | #include <linux/dmi.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/gfp.h> | ||
21 | #include <linux/mutex.h> | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/io.h> | ||
24 | #include "../../firmware/dcdbas.h" | ||
25 | #include "dell-smbios.h" | ||
26 | |||
27 | struct calling_interface_structure { | ||
28 | struct dmi_header header; | ||
29 | u16 cmdIOAddress; | ||
30 | u8 cmdIOCode; | ||
31 | u32 supportedCmds; | ||
32 | struct calling_interface_token tokens[]; | ||
33 | } __packed; | ||
34 | |||
35 | static struct calling_interface_buffer *buffer; | ||
36 | static DEFINE_MUTEX(buffer_mutex); | ||
37 | |||
38 | static int da_command_address; | ||
39 | static int da_command_code; | ||
40 | static int da_num_tokens; | ||
41 | static struct calling_interface_token *da_tokens; | ||
42 | |||
43 | int dell_smbios_error(int value) | ||
44 | { | ||
45 | switch (value) { | ||
46 | case 0: /* Completed successfully */ | ||
47 | return 0; | ||
48 | case -1: /* Completed with error */ | ||
49 | return -EIO; | ||
50 | case -2: /* Function not supported */ | ||
51 | return -ENXIO; | ||
52 | default: /* Unknown error */ | ||
53 | return -EINVAL; | ||
54 | } | ||
55 | } | ||
56 | EXPORT_SYMBOL_GPL(dell_smbios_error); | ||
57 | |||
58 | struct calling_interface_buffer *dell_smbios_get_buffer(void) | ||
59 | { | ||
60 | mutex_lock(&buffer_mutex); | ||
61 | dell_smbios_clear_buffer(); | ||
62 | return buffer; | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(dell_smbios_get_buffer); | ||
65 | |||
66 | void dell_smbios_clear_buffer(void) | ||
67 | { | ||
68 | memset(buffer, 0, sizeof(struct calling_interface_buffer)); | ||
69 | } | ||
70 | EXPORT_SYMBOL_GPL(dell_smbios_clear_buffer); | ||
71 | |||
72 | void dell_smbios_release_buffer(void) | ||
73 | { | ||
74 | mutex_unlock(&buffer_mutex); | ||
75 | } | ||
76 | EXPORT_SYMBOL_GPL(dell_smbios_release_buffer); | ||
77 | |||
78 | void dell_smbios_send_request(int class, int select) | ||
79 | { | ||
80 | struct smi_cmd command; | ||
81 | |||
82 | command.magic = SMI_CMD_MAGIC; | ||
83 | command.command_address = da_command_address; | ||
84 | command.command_code = da_command_code; | ||
85 | command.ebx = virt_to_phys(buffer); | ||
86 | command.ecx = 0x42534931; | ||
87 | |||
88 | buffer->class = class; | ||
89 | buffer->select = select; | ||
90 | |||
91 | dcdbas_smi_request(&command); | ||
92 | } | ||
93 | EXPORT_SYMBOL_GPL(dell_smbios_send_request); | ||
94 | |||
95 | struct calling_interface_token *dell_smbios_find_token(int tokenid) | ||
96 | { | ||
97 | int i; | ||
98 | |||
99 | for (i = 0; i < da_num_tokens; i++) { | ||
100 | if (da_tokens[i].tokenID == tokenid) | ||
101 | return &da_tokens[i]; | ||
102 | } | ||
103 | |||
104 | return NULL; | ||
105 | } | ||
106 | EXPORT_SYMBOL_GPL(dell_smbios_find_token); | ||
107 | |||
108 | static void __init parse_da_table(const struct dmi_header *dm) | ||
109 | { | ||
110 | /* Final token is a terminator, so we don't want to copy it */ | ||
111 | int tokens = (dm->length-11)/sizeof(struct calling_interface_token)-1; | ||
112 | struct calling_interface_token *new_da_tokens; | ||
113 | struct calling_interface_structure *table = | ||
114 | container_of(dm, struct calling_interface_structure, header); | ||
115 | |||
116 | /* 4 bytes of table header, plus 7 bytes of Dell header, plus at least | ||
117 | 6 bytes of entry */ | ||
118 | |||
119 | if (dm->length < 17) | ||
120 | return; | ||
121 | |||
122 | da_command_address = table->cmdIOAddress; | ||
123 | da_command_code = table->cmdIOCode; | ||
124 | |||
125 | new_da_tokens = krealloc(da_tokens, (da_num_tokens + tokens) * | ||
126 | sizeof(struct calling_interface_token), | ||
127 | GFP_KERNEL); | ||
128 | |||
129 | if (!new_da_tokens) | ||
130 | return; | ||
131 | da_tokens = new_da_tokens; | ||
132 | |||
133 | memcpy(da_tokens+da_num_tokens, table->tokens, | ||
134 | sizeof(struct calling_interface_token) * tokens); | ||
135 | |||
136 | da_num_tokens += tokens; | ||
137 | } | ||
138 | |||
139 | static void __init find_tokens(const struct dmi_header *dm, void *dummy) | ||
140 | { | ||
141 | switch (dm->type) { | ||
142 | case 0xd4: /* Indexed IO */ | ||
143 | case 0xd5: /* Protected Area Type 1 */ | ||
144 | case 0xd6: /* Protected Area Type 2 */ | ||
145 | break; | ||
146 | case 0xda: /* Calling interface */ | ||
147 | parse_da_table(dm); | ||
148 | break; | ||
149 | } | ||
150 | } | ||
151 | |||
152 | static int __init dell_smbios_init(void) | ||
153 | { | ||
154 | int ret; | ||
155 | |||
156 | dmi_walk(find_tokens, NULL); | ||
157 | |||
158 | if (!da_tokens) { | ||
159 | pr_info("Unable to find dmi tokens\n"); | ||
160 | return -ENODEV; | ||
161 | } | ||
162 | |||
163 | /* | ||
164 | * Allocate buffer below 4GB for SMI data--only 32-bit physical addr | ||
165 | * is passed to SMI handler. | ||
166 | */ | ||
167 | buffer = (void *)__get_free_page(GFP_KERNEL | GFP_DMA32); | ||
168 | if (!buffer) { | ||
169 | ret = -ENOMEM; | ||
170 | goto fail_buffer; | ||
171 | } | ||
172 | |||
173 | return 0; | ||
174 | |||
175 | fail_buffer: | ||
176 | kfree(da_tokens); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | static void __exit dell_smbios_exit(void) | ||
181 | { | ||
182 | kfree(da_tokens); | ||
183 | free_page((unsigned long)buffer); | ||
184 | } | ||
185 | |||
186 | subsys_initcall(dell_smbios_init); | ||
187 | module_exit(dell_smbios_exit); | ||
188 | |||
189 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); | ||
190 | MODULE_AUTHOR("Gabriele Mazzotta <gabriele.mzt@gmail.com>"); | ||
191 | MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); | ||
192 | MODULE_DESCRIPTION("Common functions for kernel modules using Dell SMBIOS"); | ||
193 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/platform/x86/dell-smbios.h b/drivers/platform/x86/dell-smbios.h new file mode 100644 index 000000000000..ec7d40ae5e6e --- /dev/null +++ b/drivers/platform/x86/dell-smbios.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Common functions for kernel modules using Dell SMBIOS | ||
3 | * | ||
4 | * Copyright (c) Red Hat <mjg@redhat.com> | ||
5 | * Copyright (c) 2014 Gabriele Mazzotta <gabriele.mzt@gmail.com> | ||
6 | * Copyright (c) 2014 Pali Rohár <pali.rohar@gmail.com> | ||
7 | * | ||
8 | * Based on documentation in the libsmbios package: | ||
9 | * Copyright (C) 2005-2014 Dell Inc. | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #ifndef _DELL_SMBIOS_H_ | ||
17 | #define _DELL_SMBIOS_H_ | ||
18 | |||
19 | /* This structure will be modified by the firmware when we enter | ||
20 | * system management mode, hence the volatiles */ | ||
21 | |||
22 | struct calling_interface_buffer { | ||
23 | u16 class; | ||
24 | u16 select; | ||
25 | volatile u32 input[4]; | ||
26 | volatile u32 output[4]; | ||
27 | } __packed; | ||
28 | |||
29 | struct calling_interface_token { | ||
30 | u16 tokenID; | ||
31 | u16 location; | ||
32 | union { | ||
33 | u16 value; | ||
34 | u16 stringlength; | ||
35 | }; | ||
36 | }; | ||
37 | |||
38 | int dell_smbios_error(int value); | ||
39 | |||
40 | struct calling_interface_buffer *dell_smbios_get_buffer(void); | ||
41 | void dell_smbios_clear_buffer(void); | ||
42 | void dell_smbios_release_buffer(void); | ||
43 | void dell_smbios_send_request(int class, int select); | ||
44 | |||
45 | struct calling_interface_token *dell_smbios_find_token(int tokenid); | ||
46 | #endif | ||
diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 368e193c2741..15c6f1191aec 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/string.h> | 37 | #include <linux/string.h> |
38 | #include <linux/dmi.h> | 38 | #include <linux/dmi.h> |
39 | #include <acpi/video.h> | 39 | #include <acpi/video.h> |
40 | #include "dell-smbios.h" | ||
40 | 41 | ||
41 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); | 42 | MODULE_AUTHOR("Matthew Garrett <mjg@redhat.com>"); |
42 | MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); | 43 | MODULE_AUTHOR("Pali Rohár <pali.rohar@gmail.com>"); |
@@ -47,10 +48,37 @@ MODULE_LICENSE("GPL"); | |||
47 | #define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492" | 48 | #define DELL_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492" |
48 | 49 | ||
49 | static u32 dell_wmi_interface_version; | 50 | static u32 dell_wmi_interface_version; |
51 | static bool wmi_requires_smbios_request; | ||
50 | 52 | ||
51 | MODULE_ALIAS("wmi:"DELL_EVENT_GUID); | 53 | MODULE_ALIAS("wmi:"DELL_EVENT_GUID); |
52 | MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID); | 54 | MODULE_ALIAS("wmi:"DELL_DESCRIPTOR_GUID); |
53 | 55 | ||
56 | static int __init dmi_matched(const struct dmi_system_id *dmi) | ||
57 | { | ||
58 | wmi_requires_smbios_request = 1; | ||
59 | return 1; | ||
60 | } | ||
61 | |||
62 | static const struct dmi_system_id dell_wmi_smbios_list[] __initconst = { | ||
63 | { | ||
64 | .callback = dmi_matched, | ||
65 | .ident = "Dell Inspiron M5110", | ||
66 | .matches = { | ||
67 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
68 | DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), | ||
69 | }, | ||
70 | }, | ||
71 | { | ||
72 | .callback = dmi_matched, | ||
73 | .ident = "Dell Vostro V131", | ||
74 | .matches = { | ||
75 | DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), | ||
76 | DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), | ||
77 | }, | ||
78 | }, | ||
79 | { } | ||
80 | }; | ||
81 | |||
54 | /* | 82 | /* |
55 | * Certain keys are flagged as KE_IGNORE. All of these are either | 83 | * Certain keys are flagged as KE_IGNORE. All of these are either |
56 | * notifications (rather than requests for change) or are also sent | 84 | * notifications (rather than requests for change) or are also sent |
@@ -90,8 +118,11 @@ static const struct key_entry dell_wmi_legacy_keymap[] __initconst = { | |||
90 | 118 | ||
91 | { KE_IGNORE, 0xe020, { KEY_MUTE } }, | 119 | { KE_IGNORE, 0xe020, { KEY_MUTE } }, |
92 | 120 | ||
93 | /* Shortcut and audio panel keys */ | 121 | /* Dell Instant Launch key */ |
94 | { KE_IGNORE, 0xe025, { KEY_RESERVED } }, | 122 | { KE_KEY, 0xe025, { KEY_PROG4 } }, |
123 | { KE_KEY, 0xe029, { KEY_PROG4 } }, | ||
124 | |||
125 | /* Audio panel key */ | ||
95 | { KE_IGNORE, 0xe026, { KEY_RESERVED } }, | 126 | { KE_IGNORE, 0xe026, { KEY_RESERVED } }, |
96 | 127 | ||
97 | { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, | 128 | { KE_IGNORE, 0xe02e, { KEY_VOLUMEDOWN } }, |
@@ -120,7 +151,10 @@ struct dell_bios_hotkey_table { | |||
120 | 151 | ||
121 | }; | 152 | }; |
122 | 153 | ||
123 | static const struct dell_bios_hotkey_table *dell_bios_hotkey_table; | 154 | struct dell_dmi_results { |
155 | int err; | ||
156 | struct key_entry *keymap; | ||
157 | }; | ||
124 | 158 | ||
125 | /* Uninitialized entries here are KEY_RESERVED == 0. */ | 159 | /* Uninitialized entries here are KEY_RESERVED == 0. */ |
126 | static const u16 bios_to_linux_keycode[256] __initconst = { | 160 | static const u16 bios_to_linux_keycode[256] __initconst = { |
@@ -166,6 +200,30 @@ static const u16 bios_to_linux_keycode[256] __initconst = { | |||
166 | [255] = KEY_PROG3, | 200 | [255] = KEY_PROG3, |
167 | }; | 201 | }; |
168 | 202 | ||
203 | /* | ||
204 | * These are applied if the 0xB2 DMI hotkey table is present and doesn't | ||
205 | * override them. | ||
206 | */ | ||
207 | static const struct key_entry dell_wmi_extra_keymap[] __initconst = { | ||
208 | /* Fn-lock */ | ||
209 | { KE_IGNORE, 0x151, { KEY_RESERVED } }, | ||
210 | |||
211 | /* Change keyboard illumination */ | ||
212 | { KE_IGNORE, 0x152, { KEY_KBDILLUMTOGGLE } }, | ||
213 | |||
214 | /* | ||
215 | * Radio disable (notify only -- there is no model for which the | ||
216 | * WMI event is supposed to trigger an action). | ||
217 | */ | ||
218 | { KE_IGNORE, 0x153, { KEY_RFKILL } }, | ||
219 | |||
220 | /* RGB keyboard backlight control */ | ||
221 | { KE_IGNORE, 0x154, { KEY_RESERVED } }, | ||
222 | |||
223 | /* Stealth mode toggle */ | ||
224 | { KE_IGNORE, 0x155, { KEY_RESERVED } }, | ||
225 | }; | ||
226 | |||
169 | static struct input_dev *dell_wmi_input_dev; | 227 | static struct input_dev *dell_wmi_input_dev; |
170 | 228 | ||
171 | static void dell_wmi_process_key(int reported_key) | 229 | static void dell_wmi_process_key(int reported_key) |
@@ -188,6 +246,9 @@ static void dell_wmi_process_key(int reported_key) | |||
188 | acpi_video_handles_brightness_key_presses()) | 246 | acpi_video_handles_brightness_key_presses()) |
189 | return; | 247 | return; |
190 | 248 | ||
249 | if (reported_key == 0xe025 && !wmi_requires_smbios_request) | ||
250 | return; | ||
251 | |||
191 | sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); | 252 | sparse_keymap_report_entry(dell_wmi_input_dev, key, 1, true); |
192 | } | 253 | } |
193 | 254 | ||
@@ -337,20 +398,60 @@ static void dell_wmi_notify(u32 value, void *context) | |||
337 | kfree(obj); | 398 | kfree(obj); |
338 | } | 399 | } |
339 | 400 | ||
340 | static const struct key_entry * __init dell_wmi_prepare_new_keymap(void) | 401 | static bool have_scancode(u32 scancode, const struct key_entry *keymap, int len) |
341 | { | 402 | { |
342 | int hotkey_num = (dell_bios_hotkey_table->header.length - 4) / | ||
343 | sizeof(struct dell_bios_keymap_entry); | ||
344 | struct key_entry *keymap; | ||
345 | int i; | 403 | int i; |
346 | 404 | ||
347 | keymap = kcalloc(hotkey_num + 1, sizeof(struct key_entry), GFP_KERNEL); | 405 | for (i = 0; i < len; i++) |
348 | if (!keymap) | 406 | if (keymap[i].code == scancode) |
349 | return NULL; | 407 | return true; |
408 | |||
409 | return false; | ||
410 | } | ||
411 | |||
412 | static void __init handle_dmi_entry(const struct dmi_header *dm, | ||
413 | |||
414 | void *opaque) | ||
415 | |||
416 | { | ||
417 | struct dell_dmi_results *results = opaque; | ||
418 | struct dell_bios_hotkey_table *table; | ||
419 | int hotkey_num, i, pos = 0; | ||
420 | struct key_entry *keymap; | ||
421 | int num_bios_keys; | ||
422 | |||
423 | if (results->err || results->keymap) | ||
424 | return; /* We already found the hotkey table. */ | ||
425 | |||
426 | if (dm->type != 0xb2) | ||
427 | return; | ||
428 | |||
429 | table = container_of(dm, struct dell_bios_hotkey_table, header); | ||
430 | |||
431 | hotkey_num = (table->header.length - | ||
432 | sizeof(struct dell_bios_hotkey_table)) / | ||
433 | sizeof(struct dell_bios_keymap_entry); | ||
434 | if (hotkey_num < 1) { | ||
435 | /* | ||
436 | * Historically, dell-wmi would ignore a DMI entry of | ||
437 | * fewer than 7 bytes. Sizes between 4 and 8 bytes are | ||
438 | * nonsensical (both the header and all entries are 4 | ||
439 | * bytes), so we approximate the old behavior by | ||
440 | * ignoring tables with fewer than one entry. | ||
441 | */ | ||
442 | return; | ||
443 | } | ||
444 | |||
445 | keymap = kcalloc(hotkey_num + ARRAY_SIZE(dell_wmi_extra_keymap) + 1, | ||
446 | sizeof(struct key_entry), GFP_KERNEL); | ||
447 | if (!keymap) { | ||
448 | results->err = -ENOMEM; | ||
449 | return; | ||
450 | } | ||
350 | 451 | ||
351 | for (i = 0; i < hotkey_num; i++) { | 452 | for (i = 0; i < hotkey_num; i++) { |
352 | const struct dell_bios_keymap_entry *bios_entry = | 453 | const struct dell_bios_keymap_entry *bios_entry = |
353 | &dell_bios_hotkey_table->keymap[i]; | 454 | &table->keymap[i]; |
354 | 455 | ||
355 | /* Uninitialized entries are 0 aka KEY_RESERVED. */ | 456 | /* Uninitialized entries are 0 aka KEY_RESERVED. */ |
356 | u16 keycode = (bios_entry->keycode < | 457 | u16 keycode = (bios_entry->keycode < |
@@ -370,20 +471,39 @@ static const struct key_entry * __init dell_wmi_prepare_new_keymap(void) | |||
370 | } | 471 | } |
371 | 472 | ||
372 | if (keycode == KEY_KBDILLUMTOGGLE) | 473 | if (keycode == KEY_KBDILLUMTOGGLE) |
373 | keymap[i].type = KE_IGNORE; | 474 | keymap[pos].type = KE_IGNORE; |
374 | else | 475 | else |
375 | keymap[i].type = KE_KEY; | 476 | keymap[pos].type = KE_KEY; |
376 | keymap[i].code = bios_entry->scancode; | 477 | keymap[pos].code = bios_entry->scancode; |
377 | keymap[i].keycode = keycode; | 478 | keymap[pos].keycode = keycode; |
479 | |||
480 | pos++; | ||
481 | } | ||
482 | |||
483 | num_bios_keys = pos; | ||
484 | |||
485 | for (i = 0; i < ARRAY_SIZE(dell_wmi_extra_keymap); i++) { | ||
486 | const struct key_entry *entry = &dell_wmi_extra_keymap[i]; | ||
487 | |||
488 | /* | ||
489 | * Check if we've already found this scancode. This takes | ||
490 | * quadratic time, but it doesn't matter unless the list | ||
491 | * of extra keys gets very long. | ||
492 | */ | ||
493 | if (!have_scancode(entry->code, keymap, num_bios_keys)) { | ||
494 | keymap[pos] = *entry; | ||
495 | pos++; | ||
496 | } | ||
378 | } | 497 | } |
379 | 498 | ||
380 | keymap[hotkey_num].type = KE_END; | 499 | keymap[pos].type = KE_END; |
381 | 500 | ||
382 | return keymap; | 501 | results->keymap = keymap; |
383 | } | 502 | } |
384 | 503 | ||
385 | static int __init dell_wmi_input_setup(void) | 504 | static int __init dell_wmi_input_setup(void) |
386 | { | 505 | { |
506 | struct dell_dmi_results dmi_results = {}; | ||
387 | int err; | 507 | int err; |
388 | 508 | ||
389 | dell_wmi_input_dev = input_allocate_device(); | 509 | dell_wmi_input_dev = input_allocate_device(); |
@@ -394,20 +514,31 @@ static int __init dell_wmi_input_setup(void) | |||
394 | dell_wmi_input_dev->phys = "wmi/input0"; | 514 | dell_wmi_input_dev->phys = "wmi/input0"; |
395 | dell_wmi_input_dev->id.bustype = BUS_HOST; | 515 | dell_wmi_input_dev->id.bustype = BUS_HOST; |
396 | 516 | ||
397 | if (dell_new_hk_type) { | 517 | if (dmi_walk(handle_dmi_entry, &dmi_results)) { |
398 | const struct key_entry *keymap = dell_wmi_prepare_new_keymap(); | 518 | /* |
399 | if (!keymap) { | 519 | * Historically, dell-wmi ignored dmi_walk errors. A failure |
400 | err = -ENOMEM; | 520 | * is certainly surprising, but it probably just indicates |
401 | goto err_free_dev; | 521 | * a very old laptop. |
402 | } | 522 | */ |
523 | pr_warn("no DMI; using the old-style hotkey interface\n"); | ||
524 | } | ||
403 | 525 | ||
404 | err = sparse_keymap_setup(dell_wmi_input_dev, keymap, NULL); | 526 | if (dmi_results.err) { |
527 | err = dmi_results.err; | ||
528 | goto err_free_dev; | ||
529 | } | ||
530 | |||
531 | if (dmi_results.keymap) { | ||
532 | dell_new_hk_type = true; | ||
533 | |||
534 | err = sparse_keymap_setup(dell_wmi_input_dev, | ||
535 | dmi_results.keymap, NULL); | ||
405 | 536 | ||
406 | /* | 537 | /* |
407 | * Sparse keymap library makes a copy of keymap so we | 538 | * Sparse keymap library makes a copy of keymap so we |
408 | * don't need the original one that was allocated. | 539 | * don't need the original one that was allocated. |
409 | */ | 540 | */ |
410 | kfree(keymap); | 541 | kfree(dmi_results.keymap); |
411 | } else { | 542 | } else { |
412 | err = sparse_keymap_setup(dell_wmi_input_dev, | 543 | err = sparse_keymap_setup(dell_wmi_input_dev, |
413 | dell_wmi_legacy_keymap, NULL); | 544 | dell_wmi_legacy_keymap, NULL); |
@@ -434,15 +565,6 @@ static void dell_wmi_input_destroy(void) | |||
434 | input_unregister_device(dell_wmi_input_dev); | 565 | input_unregister_device(dell_wmi_input_dev); |
435 | } | 566 | } |
436 | 567 | ||
437 | static void __init find_hk_type(const struct dmi_header *dm, void *dummy) | ||
438 | { | ||
439 | if (dm->type == 0xb2 && dm->length > 6) { | ||
440 | dell_new_hk_type = true; | ||
441 | dell_bios_hotkey_table = | ||
442 | container_of(dm, struct dell_bios_hotkey_table, header); | ||
443 | } | ||
444 | } | ||
445 | |||
446 | /* | 568 | /* |
447 | * Descriptor buffer is 128 byte long and contains: | 569 | * Descriptor buffer is 128 byte long and contains: |
448 | * | 570 | * |
@@ -509,6 +631,38 @@ static int __init dell_wmi_check_descriptor_buffer(void) | |||
509 | return 0; | 631 | return 0; |
510 | } | 632 | } |
511 | 633 | ||
634 | /* | ||
635 | * According to Dell SMBIOS documentation: | ||
636 | * | ||
637 | * 17 3 Application Program Registration | ||
638 | * | ||
639 | * cbArg1 Application ID 1 = 0x00010000 | ||
640 | * cbArg2 Application ID 2 | ||
641 | * QUICKSET/DCP = 0x51534554 "QSET" | ||
642 | * ALS Driver = 0x416c7353 "AlsS" | ||
643 | * Latitude ON = 0x4c6f6e52 "LonR" | ||
644 | * cbArg3 Application version or revision number | ||
645 | * cbArg4 0 = Unregister application | ||
646 | * 1 = Register application | ||
647 | * cbRes1 Standard return codes (0, -1, -2) | ||
648 | */ | ||
649 | |||
650 | static int dell_wmi_events_set_enabled(bool enable) | ||
651 | { | ||
652 | struct calling_interface_buffer *buffer; | ||
653 | int ret; | ||
654 | |||
655 | buffer = dell_smbios_get_buffer(); | ||
656 | buffer->input[0] = 0x10000; | ||
657 | buffer->input[1] = 0x51534554; | ||
658 | buffer->input[3] = enable; | ||
659 | dell_smbios_send_request(17, 3); | ||
660 | ret = buffer->output[0]; | ||
661 | dell_smbios_release_buffer(); | ||
662 | |||
663 | return dell_smbios_error(ret); | ||
664 | } | ||
665 | |||
512 | static int __init dell_wmi_init(void) | 666 | static int __init dell_wmi_init(void) |
513 | { | 667 | { |
514 | int err; | 668 | int err; |
@@ -524,8 +678,6 @@ static int __init dell_wmi_init(void) | |||
524 | if (err) | 678 | if (err) |
525 | return err; | 679 | return err; |
526 | 680 | ||
527 | dmi_walk(find_hk_type, NULL); | ||
528 | |||
529 | err = dell_wmi_input_setup(); | 681 | err = dell_wmi_input_setup(); |
530 | if (err) | 682 | if (err) |
531 | return err; | 683 | return err; |
@@ -538,12 +690,26 @@ static int __init dell_wmi_init(void) | |||
538 | return -ENODEV; | 690 | return -ENODEV; |
539 | } | 691 | } |
540 | 692 | ||
693 | dmi_check_system(dell_wmi_smbios_list); | ||
694 | |||
695 | if (wmi_requires_smbios_request) { | ||
696 | err = dell_wmi_events_set_enabled(true); | ||
697 | if (err) { | ||
698 | pr_err("Failed to enable WMI events\n"); | ||
699 | wmi_remove_notify_handler(DELL_EVENT_GUID); | ||
700 | dell_wmi_input_destroy(); | ||
701 | return err; | ||
702 | } | ||
703 | } | ||
704 | |||
541 | return 0; | 705 | return 0; |
542 | } | 706 | } |
543 | module_init(dell_wmi_init); | 707 | module_init(dell_wmi_init); |
544 | 708 | ||
545 | static void __exit dell_wmi_exit(void) | 709 | static void __exit dell_wmi_exit(void) |
546 | { | 710 | { |
711 | if (wmi_requires_smbios_request) | ||
712 | dell_wmi_events_set_enabled(false); | ||
547 | wmi_remove_notify_handler(DELL_EVENT_GUID); | 713 | wmi_remove_notify_handler(DELL_EVENT_GUID); |
548 | dell_wmi_input_destroy(); | 714 | dell_wmi_input_destroy(); |
549 | } | 715 | } |
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 1c62caff93fd..ffc84cc7b1c7 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c | |||
@@ -114,6 +114,7 @@ | |||
114 | #define KEY2_CODE 0x411 | 114 | #define KEY2_CODE 0x411 |
115 | #define KEY3_CODE 0x412 | 115 | #define KEY3_CODE 0x412 |
116 | #define KEY4_CODE 0x413 | 116 | #define KEY4_CODE 0x413 |
117 | #define KEY5_CODE 0x420 | ||
117 | 118 | ||
118 | #define MAX_HOTKEY_RINGBUFFER_SIZE 100 | 119 | #define MAX_HOTKEY_RINGBUFFER_SIZE 100 |
119 | #define RINGBUFFERSIZE 40 | 120 | #define RINGBUFFERSIZE 40 |
@@ -149,7 +150,7 @@ struct fujitsu_t { | |||
149 | char phys[32]; | 150 | char phys[32]; |
150 | struct backlight_device *bl_device; | 151 | struct backlight_device *bl_device; |
151 | struct platform_device *pf_device; | 152 | struct platform_device *pf_device; |
152 | int keycode1, keycode2, keycode3, keycode4; | 153 | int keycode1, keycode2, keycode3, keycode4, keycode5; |
153 | 154 | ||
154 | unsigned int max_brightness; | 155 | unsigned int max_brightness; |
155 | unsigned int brightness_changed; | 156 | unsigned int brightness_changed; |
@@ -823,6 +824,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | |||
823 | set_bit(fujitsu->keycode2, input->keybit); | 824 | set_bit(fujitsu->keycode2, input->keybit); |
824 | set_bit(fujitsu->keycode3, input->keybit); | 825 | set_bit(fujitsu->keycode3, input->keybit); |
825 | set_bit(fujitsu->keycode4, input->keybit); | 826 | set_bit(fujitsu->keycode4, input->keybit); |
827 | set_bit(fujitsu->keycode5, input->keybit); | ||
826 | set_bit(KEY_UNKNOWN, input->keybit); | 828 | set_bit(KEY_UNKNOWN, input->keybit); |
827 | 829 | ||
828 | error = input_register_device(input); | 830 | error = input_register_device(input); |
@@ -962,6 +964,9 @@ static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) | |||
962 | case KEY4_CODE: | 964 | case KEY4_CODE: |
963 | keycode = fujitsu->keycode4; | 965 | keycode = fujitsu->keycode4; |
964 | break; | 966 | break; |
967 | case KEY5_CODE: | ||
968 | keycode = fujitsu->keycode5; | ||
969 | break; | ||
965 | case 0: | 970 | case 0: |
966 | keycode = 0; | 971 | keycode = 0; |
967 | break; | 972 | break; |
@@ -1072,6 +1077,7 @@ static int __init fujitsu_init(void) | |||
1072 | fujitsu->keycode2 = KEY_PROG2; | 1077 | fujitsu->keycode2 = KEY_PROG2; |
1073 | fujitsu->keycode3 = KEY_PROG3; | 1078 | fujitsu->keycode3 = KEY_PROG3; |
1074 | fujitsu->keycode4 = KEY_PROG4; | 1079 | fujitsu->keycode4 = KEY_PROG4; |
1080 | fujitsu->keycode5 = KEY_RFKILL; | ||
1075 | dmi_check_system(fujitsu_dmi_table); | 1081 | dmi_check_system(fujitsu_dmi_table); |
1076 | 1082 | ||
1077 | result = acpi_bus_register_driver(&acpi_fujitsu_driver); | 1083 | result = acpi_bus_register_driver(&acpi_fujitsu_driver); |
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c index fb4dd7b3ee71..6f145f2d004d 100644 --- a/drivers/platform/x86/hp-wmi.c +++ b/drivers/platform/x86/hp-wmi.c | |||
@@ -157,7 +157,6 @@ static struct platform_device *hp_wmi_platform_dev; | |||
157 | static struct rfkill *wifi_rfkill; | 157 | static struct rfkill *wifi_rfkill; |
158 | static struct rfkill *bluetooth_rfkill; | 158 | static struct rfkill *bluetooth_rfkill; |
159 | static struct rfkill *wwan_rfkill; | 159 | static struct rfkill *wwan_rfkill; |
160 | static struct rfkill *gps_rfkill; | ||
161 | 160 | ||
162 | struct rfkill2_device { | 161 | struct rfkill2_device { |
163 | u8 id; | 162 | u8 id; |
@@ -613,10 +612,6 @@ static void hp_wmi_notify(u32 value, void *context) | |||
613 | rfkill_set_states(wwan_rfkill, | 612 | rfkill_set_states(wwan_rfkill, |
614 | hp_wmi_get_sw_state(HPWMI_WWAN), | 613 | hp_wmi_get_sw_state(HPWMI_WWAN), |
615 | hp_wmi_get_hw_state(HPWMI_WWAN)); | 614 | hp_wmi_get_hw_state(HPWMI_WWAN)); |
616 | if (gps_rfkill) | ||
617 | rfkill_set_states(gps_rfkill, | ||
618 | hp_wmi_get_sw_state(HPWMI_GPS), | ||
619 | hp_wmi_get_hw_state(HPWMI_GPS)); | ||
620 | break; | 615 | break; |
621 | case HPWMI_CPU_BATTERY_THROTTLE: | 616 | case HPWMI_CPU_BATTERY_THROTTLE: |
622 | pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); | 617 | pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n"); |
@@ -746,7 +741,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) | |||
746 | (void *) HPWMI_BLUETOOTH); | 741 | (void *) HPWMI_BLUETOOTH); |
747 | if (!bluetooth_rfkill) { | 742 | if (!bluetooth_rfkill) { |
748 | err = -ENOMEM; | 743 | err = -ENOMEM; |
749 | goto register_wifi_error; | 744 | goto register_bluetooth_error; |
750 | } | 745 | } |
751 | rfkill_init_sw_state(bluetooth_rfkill, | 746 | rfkill_init_sw_state(bluetooth_rfkill, |
752 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); | 747 | hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); |
@@ -764,7 +759,7 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) | |||
764 | (void *) HPWMI_WWAN); | 759 | (void *) HPWMI_WWAN); |
765 | if (!wwan_rfkill) { | 760 | if (!wwan_rfkill) { |
766 | err = -ENOMEM; | 761 | err = -ENOMEM; |
767 | goto register_bluetooth_error; | 762 | goto register_wwan_error; |
768 | } | 763 | } |
769 | rfkill_init_sw_state(wwan_rfkill, | 764 | rfkill_init_sw_state(wwan_rfkill, |
770 | hp_wmi_get_sw_state(HPWMI_WWAN)); | 765 | hp_wmi_get_sw_state(HPWMI_WWAN)); |
@@ -775,35 +770,13 @@ static int __init hp_wmi_rfkill_setup(struct platform_device *device) | |||
775 | goto register_wwan_error; | 770 | goto register_wwan_error; |
776 | } | 771 | } |
777 | 772 | ||
778 | if (wireless & 0x8) { | ||
779 | gps_rfkill = rfkill_alloc("hp-gps", &device->dev, | ||
780 | RFKILL_TYPE_GPS, | ||
781 | &hp_wmi_rfkill_ops, | ||
782 | (void *) HPWMI_GPS); | ||
783 | if (!gps_rfkill) { | ||
784 | err = -ENOMEM; | ||
785 | goto register_wwan_error; | ||
786 | } | ||
787 | rfkill_init_sw_state(gps_rfkill, | ||
788 | hp_wmi_get_sw_state(HPWMI_GPS)); | ||
789 | rfkill_set_hw_state(gps_rfkill, | ||
790 | hp_wmi_get_hw_state(HPWMI_GPS)); | ||
791 | err = rfkill_register(gps_rfkill); | ||
792 | if (err) | ||
793 | goto register_gps_error; | ||
794 | } | ||
795 | |||
796 | return 0; | 773 | return 0; |
797 | register_gps_error: | 774 | |
798 | rfkill_destroy(gps_rfkill); | ||
799 | gps_rfkill = NULL; | ||
800 | if (bluetooth_rfkill) | ||
801 | rfkill_unregister(bluetooth_rfkill); | ||
802 | register_wwan_error: | 775 | register_wwan_error: |
803 | rfkill_destroy(wwan_rfkill); | 776 | rfkill_destroy(wwan_rfkill); |
804 | wwan_rfkill = NULL; | 777 | wwan_rfkill = NULL; |
805 | if (gps_rfkill) | 778 | if (bluetooth_rfkill) |
806 | rfkill_unregister(gps_rfkill); | 779 | rfkill_unregister(bluetooth_rfkill); |
807 | register_bluetooth_error: | 780 | register_bluetooth_error: |
808 | rfkill_destroy(bluetooth_rfkill); | 781 | rfkill_destroy(bluetooth_rfkill); |
809 | bluetooth_rfkill = NULL; | 782 | bluetooth_rfkill = NULL; |
@@ -907,7 +880,6 @@ static int __init hp_wmi_bios_setup(struct platform_device *device) | |||
907 | wifi_rfkill = NULL; | 880 | wifi_rfkill = NULL; |
908 | bluetooth_rfkill = NULL; | 881 | bluetooth_rfkill = NULL; |
909 | wwan_rfkill = NULL; | 882 | wwan_rfkill = NULL; |
910 | gps_rfkill = NULL; | ||
911 | rfkill2_count = 0; | 883 | rfkill2_count = 0; |
912 | 884 | ||
913 | if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) | 885 | if (hp_wmi_bios_2009_later() || hp_wmi_rfkill_setup(device)) |
@@ -960,10 +932,6 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device) | |||
960 | rfkill_unregister(wwan_rfkill); | 932 | rfkill_unregister(wwan_rfkill); |
961 | rfkill_destroy(wwan_rfkill); | 933 | rfkill_destroy(wwan_rfkill); |
962 | } | 934 | } |
963 | if (gps_rfkill) { | ||
964 | rfkill_unregister(gps_rfkill); | ||
965 | rfkill_destroy(gps_rfkill); | ||
966 | } | ||
967 | 935 | ||
968 | return 0; | 936 | return 0; |
969 | } | 937 | } |
@@ -999,10 +967,6 @@ static int hp_wmi_resume_handler(struct device *device) | |||
999 | rfkill_set_states(wwan_rfkill, | 967 | rfkill_set_states(wwan_rfkill, |
1000 | hp_wmi_get_sw_state(HPWMI_WWAN), | 968 | hp_wmi_get_sw_state(HPWMI_WWAN), |
1001 | hp_wmi_get_hw_state(HPWMI_WWAN)); | 969 | hp_wmi_get_hw_state(HPWMI_WWAN)); |
1002 | if (gps_rfkill) | ||
1003 | rfkill_set_states(gps_rfkill, | ||
1004 | hp_wmi_get_sw_state(HPWMI_GPS), | ||
1005 | hp_wmi_get_hw_state(HPWMI_GPS)); | ||
1006 | 970 | ||
1007 | return 0; | 971 | return 0; |
1008 | } | 972 | } |
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index d78ee151c9e4..be3bc2f4edd4 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c | |||
@@ -865,6 +865,20 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { | |||
865 | }, | 865 | }, |
866 | }, | 866 | }, |
867 | { | 867 | { |
868 | .ident = "Lenovo ideapad Y700-15ISK", | ||
869 | .matches = { | ||
870 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), | ||
871 | DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ISK"), | ||
872 | }, | ||
873 | }, | ||
874 | { | ||
875 | .ident = "Lenovo ideapad Y700 Touch-15ISK", | ||
876 | .matches = { | ||
877 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), | ||
878 | DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700 Touch-15ISK"), | ||
879 | }, | ||
880 | }, | ||
881 | { | ||
868 | .ident = "Lenovo ideapad Y700-17ISK", | 882 | .ident = "Lenovo ideapad Y700-17ISK", |
869 | .matches = { | 883 | .matches = { |
870 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), | 884 | DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), |
diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index e20f23e04c24..f93abc8c1424 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c | |||
@@ -180,8 +180,7 @@ static int intel_hid_probe(struct platform_device *device) | |||
180 | return -ENODEV; | 180 | return -ENODEV; |
181 | } | 181 | } |
182 | 182 | ||
183 | priv = devm_kzalloc(&device->dev, | 183 | priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); |
184 | sizeof(struct intel_hid_priv *), GFP_KERNEL); | ||
185 | if (!priv) | 184 | if (!priv) |
186 | return -ENOMEM; | 185 | return -ENOMEM; |
187 | dev_set_drvdata(&device->dev, priv); | 186 | dev_set_drvdata(&device->dev, priv); |
diff --git a/drivers/platform/x86/intel_pmc_ipc.c b/drivers/platform/x86/intel_pmc_ipc.c index 092519e37de6..3fb1d85c70a8 100644 --- a/drivers/platform/x86/intel_pmc_ipc.c +++ b/drivers/platform/x86/intel_pmc_ipc.c | |||
@@ -67,7 +67,8 @@ | |||
67 | /* exported resources from IFWI */ | 67 | /* exported resources from IFWI */ |
68 | #define PLAT_RESOURCE_IPC_INDEX 0 | 68 | #define PLAT_RESOURCE_IPC_INDEX 0 |
69 | #define PLAT_RESOURCE_IPC_SIZE 0x1000 | 69 | #define PLAT_RESOURCE_IPC_SIZE 0x1000 |
70 | #define PLAT_RESOURCE_GCR_SIZE 0x1000 | 70 | #define PLAT_RESOURCE_GCR_OFFSET 0x1008 |
71 | #define PLAT_RESOURCE_GCR_SIZE 0x4 | ||
71 | #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 | 72 | #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 |
72 | #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 | 73 | #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 |
73 | #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 | 74 | #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 |
@@ -766,7 +767,7 @@ static int ipc_plat_get_res(struct platform_device *pdev) | |||
766 | } | 767 | } |
767 | ipcdev.ipc_base = addr; | 768 | ipcdev.ipc_base = addr; |
768 | 769 | ||
769 | ipcdev.gcr_base = res->start + size; | 770 | ipcdev.gcr_base = res->start + PLAT_RESOURCE_GCR_OFFSET; |
770 | ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; | 771 | ipcdev.gcr_size = PLAT_RESOURCE_GCR_SIZE; |
771 | dev_info(&pdev->dev, "ipc res: %pR\n", res); | 772 | dev_info(&pdev->dev, "ipc res: %pR\n", res); |
772 | 773 | ||
@@ -824,7 +825,8 @@ static int ipc_plat_probe(struct platform_device *pdev) | |||
824 | goto err_device; | 825 | goto err_device; |
825 | } | 826 | } |
826 | 827 | ||
827 | if (request_irq(ipcdev.irq, ioc, 0, "intel_pmc_ipc", &ipcdev)) { | 828 | if (request_irq(ipcdev.irq, ioc, IRQF_NO_SUSPEND, |
829 | "intel_pmc_ipc", &ipcdev)) { | ||
828 | dev_err(&pdev->dev, "Failed to request irq\n"); | 830 | dev_err(&pdev->dev, "Failed to request irq\n"); |
829 | ret = -EBUSY; | 831 | ret = -EBUSY; |
830 | goto err_irq; | 832 | goto err_irq; |
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c index f94b730540e2..e81daff65f62 100644 --- a/drivers/platform/x86/intel_scu_ipc.c +++ b/drivers/platform/x86/intel_scu_ipc.c | |||
@@ -24,7 +24,6 @@ | |||
24 | #include <linux/pci.h> | 24 | #include <linux/pci.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/sfi.h> | 26 | #include <linux/sfi.h> |
27 | #include <linux/module.h> | ||
28 | #include <asm/intel-mid.h> | 27 | #include <asm/intel-mid.h> |
29 | #include <asm/intel_scu_ipc.h> | 28 | #include <asm/intel_scu_ipc.h> |
30 | 29 | ||
@@ -611,28 +610,6 @@ static int ipc_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
611 | return 0; | 610 | return 0; |
612 | } | 611 | } |
613 | 612 | ||
614 | /** | ||
615 | * ipc_remove - remove a bound IPC device | ||
616 | * @pdev: PCI device | ||
617 | * | ||
618 | * In practice the SCU is not removable but this function is also | ||
619 | * called for each device on a module unload or cleanup which is the | ||
620 | * path that will get used. | ||
621 | * | ||
622 | * Free up the mappings and release the PCI resources | ||
623 | */ | ||
624 | static void ipc_remove(struct pci_dev *pdev) | ||
625 | { | ||
626 | struct intel_scu_ipc_dev *scu = pci_get_drvdata(pdev); | ||
627 | |||
628 | mutex_lock(&ipclock); | ||
629 | scu->dev = NULL; | ||
630 | mutex_unlock(&ipclock); | ||
631 | |||
632 | iounmap(scu->i2c_base); | ||
633 | intel_scu_devices_destroy(); | ||
634 | } | ||
635 | |||
636 | static const struct pci_device_id pci_ids[] = { | 613 | static const struct pci_device_id pci_ids[] = { |
637 | { | 614 | { |
638 | PCI_VDEVICE(INTEL, PCI_DEVICE_ID_LINCROFT), | 615 | PCI_VDEVICE(INTEL, PCI_DEVICE_ID_LINCROFT), |
@@ -650,17 +627,13 @@ static const struct pci_device_id pci_ids[] = { | |||
650 | 0, | 627 | 0, |
651 | } | 628 | } |
652 | }; | 629 | }; |
653 | MODULE_DEVICE_TABLE(pci, pci_ids); | ||
654 | 630 | ||
655 | static struct pci_driver ipc_driver = { | 631 | static struct pci_driver ipc_driver = { |
632 | .driver = { | ||
633 | .suppress_bind_attrs = true, | ||
634 | }, | ||
656 | .name = "intel_scu_ipc", | 635 | .name = "intel_scu_ipc", |
657 | .id_table = pci_ids, | 636 | .id_table = pci_ids, |
658 | .probe = ipc_probe, | 637 | .probe = ipc_probe, |
659 | .remove = ipc_remove, | ||
660 | }; | 638 | }; |
661 | 639 | builtin_pci_driver(ipc_driver); | |
662 | module_pci_driver(ipc_driver); | ||
663 | |||
664 | MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>"); | ||
665 | MODULE_DESCRIPTION("Intel SCU IPC driver"); | ||
666 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/platform/x86/intel_telemetry_pltdrv.c b/drivers/platform/x86/intel_telemetry_pltdrv.c index f97019b0106f..397119f83e82 100644 --- a/drivers/platform/x86/intel_telemetry_pltdrv.c +++ b/drivers/platform/x86/intel_telemetry_pltdrv.c | |||
@@ -1030,8 +1030,19 @@ static int telemetry_plt_set_trace_verbosity(enum telemetry_unit telem_unit, | |||
1030 | switch (telem_unit) { | 1030 | switch (telem_unit) { |
1031 | case TELEM_PSS: | 1031 | case TELEM_PSS: |
1032 | ret = intel_punit_ipc_command( | 1032 | ret = intel_punit_ipc_command( |
1033 | IPC_PUNIT_BIOS_READ_TELE_TRACE_CTRL, | ||
1034 | 0, 0, NULL, &temp); | ||
1035 | if (ret) { | ||
1036 | pr_err("PSS TRACE_CTRL Read Failed\n"); | ||
1037 | goto out; | ||
1038 | } | ||
1039 | |||
1040 | TELEM_CLEAR_VERBOSITY_BITS(temp); | ||
1041 | TELEM_SET_VERBOSITY_BITS(temp, verbosity); | ||
1042 | |||
1043 | ret = intel_punit_ipc_command( | ||
1033 | IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL, | 1044 | IPC_PUNIT_BIOS_WRITE_TELE_TRACE_CTRL, |
1034 | 0, 0, &verbosity, NULL); | 1045 | 0, 0, &temp, NULL); |
1035 | if (ret) { | 1046 | if (ret) { |
1036 | pr_err("PSS TRACE_CTRL Verbosity Set Failed\n"); | 1047 | pr_err("PSS TRACE_CTRL Verbosity Set Failed\n"); |
1037 | goto out; | 1048 | goto out; |
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index a268a7abf8ab..e305ab541a22 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c | |||
@@ -6653,18 +6653,16 @@ static void __init tpacpi_detect_brightness_capabilities(void) | |||
6653 | switch (b) { | 6653 | switch (b) { |
6654 | case 16: | 6654 | case 16: |
6655 | bright_maxlvl = 15; | 6655 | bright_maxlvl = 15; |
6656 | pr_info("detected a 16-level brightness capable ThinkPad\n"); | ||
6657 | break; | 6656 | break; |
6658 | case 8: | 6657 | case 8: |
6659 | case 0: | 6658 | case 0: |
6660 | bright_maxlvl = 7; | 6659 | bright_maxlvl = 7; |
6661 | pr_info("detected a 8-level brightness capable ThinkPad\n"); | ||
6662 | break; | 6660 | break; |
6663 | default: | 6661 | default: |
6664 | pr_info("Unsupported brightness interface\n"); | ||
6665 | tp_features.bright_unkfw = 1; | 6662 | tp_features.bright_unkfw = 1; |
6666 | bright_maxlvl = b - 1; | 6663 | bright_maxlvl = b - 1; |
6667 | } | 6664 | } |
6665 | pr_debug("detected %u brightness levels\n", bright_maxlvl + 1); | ||
6668 | } | 6666 | } |
6669 | 6667 | ||
6670 | static int __init brightness_init(struct ibm_init_struct *iibm) | 6668 | static int __init brightness_init(struct ibm_init_struct *iibm) |
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c index 73833079bac8..df1f1a76a862 100644 --- a/drivers/platform/x86/toshiba_acpi.c +++ b/drivers/platform/x86/toshiba_acpi.c | |||
@@ -36,6 +36,7 @@ | |||
36 | 36 | ||
37 | #include <linux/kernel.h> | 37 | #include <linux/kernel.h> |
38 | #include <linux/module.h> | 38 | #include <linux/module.h> |
39 | #include <linux/moduleparam.h> | ||
39 | #include <linux/init.h> | 40 | #include <linux/init.h> |
40 | #include <linux/types.h> | 41 | #include <linux/types.h> |
41 | #include <linux/proc_fs.h> | 42 | #include <linux/proc_fs.h> |
@@ -117,6 +118,7 @@ MODULE_LICENSE("GPL"); | |||
117 | #define HCI_LCD_BRIGHTNESS 0x002a | 118 | #define HCI_LCD_BRIGHTNESS 0x002a |
118 | #define HCI_WIRELESS 0x0056 | 119 | #define HCI_WIRELESS 0x0056 |
119 | #define HCI_ACCELEROMETER 0x006d | 120 | #define HCI_ACCELEROMETER 0x006d |
121 | #define HCI_COOLING_METHOD 0x007f | ||
120 | #define HCI_KBD_ILLUMINATION 0x0095 | 122 | #define HCI_KBD_ILLUMINATION 0x0095 |
121 | #define HCI_ECO_MODE 0x0097 | 123 | #define HCI_ECO_MODE 0x0097 |
122 | #define HCI_ACCELEROMETER2 0x00a6 | 124 | #define HCI_ACCELEROMETER2 0x00a6 |
@@ -186,6 +188,7 @@ struct toshiba_acpi_dev { | |||
186 | int usbsc_bat_level; | 188 | int usbsc_bat_level; |
187 | int usbsc_mode_base; | 189 | int usbsc_mode_base; |
188 | int hotkey_event_type; | 190 | int hotkey_event_type; |
191 | int max_cooling_method; | ||
189 | 192 | ||
190 | unsigned int illumination_supported:1; | 193 | unsigned int illumination_supported:1; |
191 | unsigned int video_supported:1; | 194 | unsigned int video_supported:1; |
@@ -205,6 +208,7 @@ struct toshiba_acpi_dev { | |||
205 | unsigned int panel_power_on_supported:1; | 208 | unsigned int panel_power_on_supported:1; |
206 | unsigned int usb_three_supported:1; | 209 | unsigned int usb_three_supported:1; |
207 | unsigned int wwan_supported:1; | 210 | unsigned int wwan_supported:1; |
211 | unsigned int cooling_method_supported:1; | ||
208 | unsigned int sysfs_created:1; | 212 | unsigned int sysfs_created:1; |
209 | unsigned int special_functions; | 213 | unsigned int special_functions; |
210 | 214 | ||
@@ -217,6 +221,10 @@ struct toshiba_acpi_dev { | |||
217 | 221 | ||
218 | static struct toshiba_acpi_dev *toshiba_acpi; | 222 | static struct toshiba_acpi_dev *toshiba_acpi; |
219 | 223 | ||
224 | static bool disable_hotkeys; | ||
225 | module_param(disable_hotkeys, bool, 0444); | ||
226 | MODULE_PARM_DESC(disable_hotkeys, "Disables the hotkeys activation"); | ||
227 | |||
220 | static const struct acpi_device_id toshiba_device_ids[] = { | 228 | static const struct acpi_device_id toshiba_device_ids[] = { |
221 | {"TOS6200", 0}, | 229 | {"TOS6200", 0}, |
222 | {"TOS6207", 0}, | 230 | {"TOS6207", 0}, |
@@ -1194,6 +1202,53 @@ static int toshiba_wwan_set(struct toshiba_acpi_dev *dev, u32 state) | |||
1194 | return out[0] == TOS_SUCCESS ? 0 : -EIO; | 1202 | return out[0] == TOS_SUCCESS ? 0 : -EIO; |
1195 | } | 1203 | } |
1196 | 1204 | ||
1205 | /* Cooling Method */ | ||
1206 | static void toshiba_cooling_method_available(struct toshiba_acpi_dev *dev) | ||
1207 | { | ||
1208 | u32 in[TCI_WORDS] = { HCI_GET, HCI_COOLING_METHOD, 0, 0, 0, 0 }; | ||
1209 | u32 out[TCI_WORDS]; | ||
1210 | acpi_status status; | ||
1211 | |||
1212 | dev->cooling_method_supported = 0; | ||
1213 | dev->max_cooling_method = 0; | ||
1214 | |||
1215 | status = tci_raw(dev, in, out); | ||
1216 | if (ACPI_FAILURE(status)) | ||
1217 | pr_err("ACPI call to get Cooling Method failed\n"); | ||
1218 | |||
1219 | if (out[0] != TOS_SUCCESS && out[0] != TOS_SUCCESS2) | ||
1220 | return; | ||
1221 | |||
1222 | dev->cooling_method_supported = 1; | ||
1223 | dev->max_cooling_method = out[3]; | ||
1224 | } | ||
1225 | |||
1226 | static int toshiba_cooling_method_get(struct toshiba_acpi_dev *dev, u32 *state) | ||
1227 | { | ||
1228 | u32 result = hci_read(dev, HCI_COOLING_METHOD, state); | ||
1229 | |||
1230 | if (result == TOS_FAILURE) | ||
1231 | pr_err("ACPI call to get Cooling Method failed\n"); | ||
1232 | |||
1233 | if (result == TOS_NOT_SUPPORTED) | ||
1234 | return -ENODEV; | ||
1235 | |||
1236 | return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; | ||
1237 | } | ||
1238 | |||
1239 | static int toshiba_cooling_method_set(struct toshiba_acpi_dev *dev, u32 state) | ||
1240 | { | ||
1241 | u32 result = hci_write(dev, HCI_COOLING_METHOD, state); | ||
1242 | |||
1243 | if (result == TOS_FAILURE) | ||
1244 | pr_err("ACPI call to get Cooling Method failed\n"); | ||
1245 | |||
1246 | if (result == TOS_NOT_SUPPORTED) | ||
1247 | return -ENODEV; | ||
1248 | |||
1249 | return (result == TOS_SUCCESS || result == TOS_SUCCESS2) ? 0 : -EIO; | ||
1250 | } | ||
1251 | |||
1197 | /* Transflective Backlight */ | 1252 | /* Transflective Backlight */ |
1198 | static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) | 1253 | static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, u32 *status) |
1199 | { | 1254 | { |
@@ -2239,6 +2294,54 @@ static ssize_t usb_three_store(struct device *dev, | |||
2239 | } | 2294 | } |
2240 | static DEVICE_ATTR_RW(usb_three); | 2295 | static DEVICE_ATTR_RW(usb_three); |
2241 | 2296 | ||
2297 | static ssize_t cooling_method_show(struct device *dev, | ||
2298 | struct device_attribute *attr, char *buf) | ||
2299 | { | ||
2300 | struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); | ||
2301 | int state; | ||
2302 | int ret; | ||
2303 | |||
2304 | ret = toshiba_cooling_method_get(toshiba, &state); | ||
2305 | if (ret < 0) | ||
2306 | return ret; | ||
2307 | |||
2308 | return sprintf(buf, "%d %d\n", state, toshiba->max_cooling_method); | ||
2309 | } | ||
2310 | |||
2311 | static ssize_t cooling_method_store(struct device *dev, | ||
2312 | struct device_attribute *attr, | ||
2313 | const char *buf, size_t count) | ||
2314 | { | ||
2315 | struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev); | ||
2316 | int state; | ||
2317 | int ret; | ||
2318 | |||
2319 | ret = kstrtoint(buf, 0, &state); | ||
2320 | if (ret) | ||
2321 | return ret; | ||
2322 | |||
2323 | /* | ||
2324 | * Check for supported values | ||
2325 | * Depending on the laptop model, some only support these two: | ||
2326 | * 0 - Maximum Performance | ||
2327 | * 1 - Battery Optimized | ||
2328 | * | ||
2329 | * While some others support all three methods: | ||
2330 | * 0 - Maximum Performance | ||
2331 | * 1 - Performance | ||
2332 | * 2 - Battery Optimized | ||
2333 | */ | ||
2334 | if (state < 0 || state > toshiba->max_cooling_method) | ||
2335 | return -EINVAL; | ||
2336 | |||
2337 | ret = toshiba_cooling_method_set(toshiba, state); | ||
2338 | if (ret) | ||
2339 | return ret; | ||
2340 | |||
2341 | return count; | ||
2342 | } | ||
2343 | static DEVICE_ATTR_RW(cooling_method); | ||
2344 | |||
2242 | static struct attribute *toshiba_attributes[] = { | 2345 | static struct attribute *toshiba_attributes[] = { |
2243 | &dev_attr_version.attr, | 2346 | &dev_attr_version.attr, |
2244 | &dev_attr_fan.attr, | 2347 | &dev_attr_fan.attr, |
@@ -2255,6 +2358,7 @@ static struct attribute *toshiba_attributes[] = { | |||
2255 | &dev_attr_kbd_function_keys.attr, | 2358 | &dev_attr_kbd_function_keys.attr, |
2256 | &dev_attr_panel_power_on.attr, | 2359 | &dev_attr_panel_power_on.attr, |
2257 | &dev_attr_usb_three.attr, | 2360 | &dev_attr_usb_three.attr, |
2361 | &dev_attr_cooling_method.attr, | ||
2258 | NULL, | 2362 | NULL, |
2259 | }; | 2363 | }; |
2260 | 2364 | ||
@@ -2289,6 +2393,8 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj, | |||
2289 | exists = (drv->panel_power_on_supported) ? true : false; | 2393 | exists = (drv->panel_power_on_supported) ? true : false; |
2290 | else if (attr == &dev_attr_usb_three.attr) | 2394 | else if (attr == &dev_attr_usb_three.attr) |
2291 | exists = (drv->usb_three_supported) ? true : false; | 2395 | exists = (drv->usb_three_supported) ? true : false; |
2396 | else if (attr == &dev_attr_cooling_method.attr) | ||
2397 | exists = (drv->cooling_method_supported) ? true : false; | ||
2292 | 2398 | ||
2293 | return exists ? attr->mode : 0; | 2399 | return exists ? attr->mode : 0; |
2294 | } | 2400 | } |
@@ -2591,6 +2697,11 @@ static int toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev) | |||
2591 | acpi_handle ec_handle; | 2697 | acpi_handle ec_handle; |
2592 | int error; | 2698 | int error; |
2593 | 2699 | ||
2700 | if (disable_hotkeys) { | ||
2701 | pr_info("Hotkeys disabled by module parameter\n"); | ||
2702 | return 0; | ||
2703 | } | ||
2704 | |||
2594 | if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { | 2705 | if (wmi_has_guid(TOSHIBA_WMI_EVENT_GUID)) { |
2595 | pr_info("WMI event detected, hotkeys will not be monitored\n"); | 2706 | pr_info("WMI event detected, hotkeys will not be monitored\n"); |
2596 | return 0; | 2707 | return 0; |
@@ -2779,6 +2890,8 @@ static void print_supported_features(struct toshiba_acpi_dev *dev) | |||
2779 | pr_cont(" usb3"); | 2890 | pr_cont(" usb3"); |
2780 | if (dev->wwan_supported) | 2891 | if (dev->wwan_supported) |
2781 | pr_cont(" wwan"); | 2892 | pr_cont(" wwan"); |
2893 | if (dev->cooling_method_supported) | ||
2894 | pr_cont(" cooling-method"); | ||
2782 | 2895 | ||
2783 | pr_cont("\n"); | 2896 | pr_cont("\n"); |
2784 | } | 2897 | } |
@@ -2963,6 +3076,8 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev) | |||
2963 | if (dev->wwan_supported) | 3076 | if (dev->wwan_supported) |
2964 | toshiba_acpi_setup_wwan_rfkill(dev); | 3077 | toshiba_acpi_setup_wwan_rfkill(dev); |
2965 | 3078 | ||
3079 | toshiba_cooling_method_available(dev); | ||
3080 | |||
2966 | print_supported_features(dev); | 3081 | print_supported_features(dev); |
2967 | 3082 | ||
2968 | ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, | 3083 | ret = sysfs_create_group(&dev->acpi_dev->dev.kobj, |