diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/platform/x86/dell-laptop.c | 122 |
1 files changed, 83 insertions, 39 deletions
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index d8b1b39aa9db..1a0bfd43f8f0 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/rfkill.h> | 22 | #include <linux/rfkill.h> |
23 | #include <linux/power_supply.h> | 23 | #include <linux/power_supply.h> |
24 | #include <linux/acpi.h> | 24 | #include <linux/acpi.h> |
25 | #include <linux/mm.h> | ||
25 | #include <linux/i8042.h> | 26 | #include <linux/i8042.h> |
26 | #include "../../firmware/dcdbas.h" | 27 | #include "../../firmware/dcdbas.h" |
27 | 28 | ||
@@ -123,6 +124,21 @@ static struct dmi_system_id __devinitdata dell_blacklist[] = { | |||
123 | {} | 124 | {} |
124 | }; | 125 | }; |
125 | 126 | ||
127 | static struct calling_interface_buffer *buffer; | ||
128 | struct page *bufferpage; | ||
129 | DEFINE_MUTEX(buffer_mutex); | ||
130 | |||
131 | static void get_buffer(void) | ||
132 | { | ||
133 | mutex_lock(&buffer_mutex); | ||
134 | memset(buffer, 0, sizeof(struct calling_interface_buffer)); | ||
135 | } | ||
136 | |||
137 | static void release_buffer(void) | ||
138 | { | ||
139 | mutex_unlock(&buffer_mutex); | ||
140 | } | ||
141 | |||
126 | static void __init parse_da_table(const struct dmi_header *dm) | 142 | static void __init parse_da_table(const struct dmi_header *dm) |
127 | { | 143 | { |
128 | /* Final token is a terminator, so we don't want to copy it */ | 144 | /* Final token is a terminator, so we don't want to copy it */ |
@@ -225,30 +241,35 @@ dell_send_request(struct calling_interface_buffer *buffer, int class, | |||
225 | 241 | ||
226 | static int dell_rfkill_set(void *data, bool blocked) | 242 | static int dell_rfkill_set(void *data, bool blocked) |
227 | { | 243 | { |
228 | struct calling_interface_buffer buffer; | ||
229 | int disable = blocked ? 1 : 0; | 244 | int disable = blocked ? 1 : 0; |
230 | unsigned long radio = (unsigned long)data; | 245 | unsigned long radio = (unsigned long)data; |
246 | int ret = 0; | ||
231 | 247 | ||
232 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 248 | get_buffer(); |
233 | dell_send_request(&buffer, 17, 11); | 249 | dell_send_request(buffer, 17, 11); |
234 | if (!(buffer.output[1] & BIT(16))) | ||
235 | return -EINVAL; | ||
236 | 250 | ||
237 | buffer.input[0] = (1 | (radio<<8) | (disable << 16)); | 251 | if (!(buffer->output[1] & BIT(16))) { |
238 | dell_send_request(&buffer, 17, 11); | 252 | ret = -EINVAL; |
253 | goto out; | ||
254 | } | ||
239 | 255 | ||
240 | return 0; | 256 | buffer->input[0] = (1 | (radio<<8) | (disable << 16)); |
257 | dell_send_request(buffer, 17, 11); | ||
258 | |||
259 | out: | ||
260 | release_buffer(); | ||
261 | return ret; | ||
241 | } | 262 | } |
242 | 263 | ||
243 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) | 264 | static void dell_rfkill_query(struct rfkill *rfkill, void *data) |
244 | { | 265 | { |
245 | struct calling_interface_buffer buffer; | ||
246 | int status; | 266 | int status; |
247 | int bit = (unsigned long)data + 16; | 267 | int bit = (unsigned long)data + 16; |
248 | 268 | ||
249 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 269 | get_buffer(); |
250 | dell_send_request(&buffer, 17, 11); | 270 | dell_send_request(buffer, 17, 11); |
251 | status = buffer.output[1]; | 271 | status = buffer->output[1]; |
272 | release_buffer(); | ||
252 | 273 | ||
253 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); | 274 | rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); |
254 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); | 275 | rfkill_set_hw_state(rfkill, !(status & BIT(16))); |
@@ -273,7 +294,6 @@ static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | |||
273 | 294 | ||
274 | static int __init dell_setup_rfkill(void) | 295 | static int __init dell_setup_rfkill(void) |
275 | { | 296 | { |
276 | struct calling_interface_buffer buffer; | ||
277 | int status; | 297 | int status; |
278 | int ret; | 298 | int ret; |
279 | 299 | ||
@@ -283,9 +303,10 @@ static int __init dell_setup_rfkill(void) | |||
283 | return 0; | 303 | return 0; |
284 | } | 304 | } |
285 | 305 | ||
286 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 306 | get_buffer(); |
287 | dell_send_request(&buffer, 17, 11); | 307 | dell_send_request(buffer, 17, 11); |
288 | status = buffer.output[1]; | 308 | status = buffer->output[1]; |
309 | release_buffer(); | ||
289 | 310 | ||
290 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { | 311 | if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { |
291 | wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, | 312 | wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, |
@@ -361,39 +382,49 @@ static void dell_cleanup_rfkill(void) | |||
361 | 382 | ||
362 | static int dell_send_intensity(struct backlight_device *bd) | 383 | static int dell_send_intensity(struct backlight_device *bd) |
363 | { | 384 | { |
364 | struct calling_interface_buffer buffer; | 385 | int ret = 0; |
365 | 386 | ||
366 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 387 | get_buffer(); |
367 | buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); | 388 | buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN); |
368 | buffer.input[1] = bd->props.brightness; | 389 | buffer->input[1] = bd->props.brightness; |
369 | 390 | ||
370 | if (buffer.input[0] == -1) | 391 | if (buffer->input[0] == -1) { |
371 | return -ENODEV; | 392 | ret = -ENODEV; |
393 | goto out; | ||
394 | } | ||
372 | 395 | ||
373 | if (power_supply_is_system_supplied() > 0) | 396 | if (power_supply_is_system_supplied() > 0) |
374 | dell_send_request(&buffer, 1, 2); | 397 | dell_send_request(buffer, 1, 2); |
375 | else | 398 | else |
376 | dell_send_request(&buffer, 1, 1); | 399 | dell_send_request(buffer, 1, 1); |
377 | 400 | ||
401 | out: | ||
402 | release_buffer(); | ||
378 | return 0; | 403 | return 0; |
379 | } | 404 | } |
380 | 405 | ||
381 | static int dell_get_intensity(struct backlight_device *bd) | 406 | static int dell_get_intensity(struct backlight_device *bd) |
382 | { | 407 | { |
383 | struct calling_interface_buffer buffer; | 408 | int ret = 0; |
384 | 409 | ||
385 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 410 | get_buffer(); |
386 | buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); | 411 | buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN); |
387 | 412 | ||
388 | if (buffer.input[0] == -1) | 413 | if (buffer->input[0] == -1) { |
389 | return -ENODEV; | 414 | ret = -ENODEV; |
415 | goto out; | ||
416 | } | ||
390 | 417 | ||
391 | if (power_supply_is_system_supplied() > 0) | 418 | if (power_supply_is_system_supplied() > 0) |
392 | dell_send_request(&buffer, 0, 2); | 419 | dell_send_request(buffer, 0, 2); |
393 | else | 420 | else |
394 | dell_send_request(&buffer, 0, 1); | 421 | dell_send_request(buffer, 0, 1); |
395 | 422 | ||
396 | return buffer.output[1]; | 423 | out: |
424 | release_buffer(); | ||
425 | if (ret) | ||
426 | return ret; | ||
427 | return buffer->output[1]; | ||
397 | } | 428 | } |
398 | 429 | ||
399 | static struct backlight_ops dell_ops = { | 430 | static struct backlight_ops dell_ops = { |
@@ -427,7 +458,6 @@ bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, | |||
427 | 458 | ||
428 | static int __init dell_init(void) | 459 | static int __init dell_init(void) |
429 | { | 460 | { |
430 | struct calling_interface_buffer buffer; | ||
431 | int max_intensity = 0; | 461 | int max_intensity = 0; |
432 | int ret; | 462 | int ret; |
433 | 463 | ||
@@ -453,6 +483,17 @@ static int __init dell_init(void) | |||
453 | if (ret) | 483 | if (ret) |
454 | goto fail_platform_device2; | 484 | goto fail_platform_device2; |
455 | 485 | ||
486 | /* | ||
487 | * Allocate buffer below 4GB for SMI data--only 32-bit physical addr | ||
488 | * is passed to SMI handler. | ||
489 | */ | ||
490 | bufferpage = alloc_page(GFP_KERNEL | GFP_DMA32); | ||
491 | |||
492 | if (!bufferpage) | ||
493 | goto fail_buffer; | ||
494 | buffer = page_address(bufferpage); | ||
495 | mutex_init(&buffer_mutex); | ||
496 | |||
456 | ret = dell_setup_rfkill(); | 497 | ret = dell_setup_rfkill(); |
457 | 498 | ||
458 | if (ret) { | 499 | if (ret) { |
@@ -475,13 +516,13 @@ static int __init dell_init(void) | |||
475 | return 0; | 516 | return 0; |
476 | #endif | 517 | #endif |
477 | 518 | ||
478 | memset(&buffer, 0, sizeof(struct calling_interface_buffer)); | 519 | get_buffer(); |
479 | buffer.input[0] = find_token_location(BRIGHTNESS_TOKEN); | 520 | buffer->input[0] = find_token_location(BRIGHTNESS_TOKEN); |
480 | 521 | if (buffer->input[0] != -1) { | |
481 | if (buffer.input[0] != -1) { | 522 | dell_send_request(buffer, 0, 2); |
482 | dell_send_request(&buffer, 0, 2); | 523 | max_intensity = buffer->output[3]; |
483 | max_intensity = buffer.output[3]; | ||
484 | } | 524 | } |
525 | release_buffer(); | ||
485 | 526 | ||
486 | if (max_intensity) { | 527 | if (max_intensity) { |
487 | dell_backlight_device = backlight_device_register( | 528 | dell_backlight_device = backlight_device_register( |
@@ -508,6 +549,8 @@ fail_backlight: | |||
508 | fail_filter: | 549 | fail_filter: |
509 | dell_cleanup_rfkill(); | 550 | dell_cleanup_rfkill(); |
510 | fail_rfkill: | 551 | fail_rfkill: |
552 | free_page((unsigned long)bufferpage); | ||
553 | fail_buffer: | ||
511 | platform_device_del(platform_device); | 554 | platform_device_del(platform_device); |
512 | fail_platform_device2: | 555 | fail_platform_device2: |
513 | platform_device_put(platform_device); | 556 | platform_device_put(platform_device); |
@@ -529,6 +572,7 @@ static void __exit dell_exit(void) | |||
529 | platform_driver_unregister(&platform_driver); | 572 | platform_driver_unregister(&platform_driver); |
530 | } | 573 | } |
531 | kfree(da_tokens); | 574 | kfree(da_tokens); |
575 | free_page((unsigned long)buffer); | ||
532 | } | 576 | } |
533 | 577 | ||
534 | module_init(dell_init); | 578 | module_init(dell_init); |