aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2012-06-01 19:51:37 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2012-06-01 19:51:37 -0400
commit48445159e9ecb44a96a4de06c6ae7c54eb43ba5b (patch)
tree992657156c63746d6d43c3b6f7386227a0df34a4
parentaf4f8ba31a4e328677bec493ceeaf112ca193b65 (diff)
parenta2f01a899347fd97cb18094e5a55640cab552818 (diff)
Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
Pull x86 platform driver updates from Matthew Garrett: "Some significant improvements for the Sony driver on newer machines, but other than that mostly just minor fixes and a patch to remove the broken rfkill code from the Dell driver." * 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (35 commits) apple-gmux: Fix up the suspend/resume patch dell-laptop: Remove rfkill code toshiba_acpi: Fix mis-merge dell-laptop: Add touchpad led support for Dell V3450 acer-wmi: add 3 laptops to video backlight vendor mode quirk table sony-laptop: add touchpad enable/disable function sony-laptop: add missing Fn key combos for 0x100 handlers sony-laptop: add support for more WWAN modems sony-laptop: new keyboard backlight handle sony-laptop: add high speed battery charging function sony-laptop: support automatic resume on lid open sony-laptop: adjust error handling in finding SNC handles sony-laptop: add thermal profiles support sony-laptop: support battery care functions sony-laptop: additional debug statements sony-laptop: improve SNC initialization and acpi notify callback code sony-laptop: use kstrtoul to parse sysfs values sony-laptop: generalise ACPI calls into SNC functions sony-laptop: fix return path when no ACPI buffer is allocated sony-laptop: use soft rfkill status stored in hw ...
-rw-r--r--drivers/platform/x86/acer-wmi.c24
-rw-r--r--drivers/platform/x86/apple-gmux.c4
-rw-r--r--drivers/platform/x86/dell-laptop.c308
-rw-r--r--drivers/platform/x86/fujitsu-tablet.c34
-rw-r--r--drivers/platform/x86/hdaps.c2
-rw-r--r--drivers/platform/x86/hp-wmi.c10
-rw-r--r--drivers/platform/x86/ideapad-laptop.c9
-rw-r--r--drivers/platform/x86/sony-laptop.c1498
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c2
-rw-r--r--drivers/platform/x86/toshiba_acpi.c141
-rw-r--r--drivers/platform/x86/xo1-rfkill.c13
11 files changed, 1416 insertions, 629 deletions
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index c1a3fd8e1243..ce875dc365e5 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -523,6 +523,30 @@ static const struct dmi_system_id video_vendor_dmi_table[] = {
523 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"), 523 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4750"),
524 }, 524 },
525 }, 525 },
526 {
527 .callback = video_set_backlight_video_vendor,
528 .ident = "Acer Extensa 5235",
529 .matches = {
530 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
531 DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5235"),
532 },
533 },
534 {
535 .callback = video_set_backlight_video_vendor,
536 .ident = "Acer TravelMate 5760",
537 .matches = {
538 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
539 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5760"),
540 },
541 },
542 {
543 .callback = video_set_backlight_video_vendor,
544 .ident = "Acer Aspire 5750",
545 .matches = {
546 DMI_MATCH(DMI_BOARD_VENDOR, "Acer"),
547 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5750"),
548 },
549 },
526 {} 550 {}
527}; 551};
528 552
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 8a582bdfdc76..694a15a56230 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -87,6 +87,9 @@ static int gmux_update_status(struct backlight_device *bd)
87 struct apple_gmux_data *gmux_data = bl_get_data(bd); 87 struct apple_gmux_data *gmux_data = bl_get_data(bd);
88 u32 brightness = bd->props.brightness; 88 u32 brightness = bd->props.brightness;
89 89
90 if (bd->props.state & BL_CORE_SUSPENDED)
91 return 0;
92
90 /* 93 /*
91 * Older gmux versions require writing out lower bytes first then 94 * Older gmux versions require writing out lower bytes first then
92 * setting the upper byte to 0 to flush the values. Newer versions 95 * setting the upper byte to 0 to flush the values. Newer versions
@@ -102,6 +105,7 @@ static int gmux_update_status(struct backlight_device *bd)
102} 105}
103 106
104static const struct backlight_ops gmux_bl_ops = { 107static const struct backlight_ops gmux_bl_ops = {
108 .options = BL_CORE_SUSPENDRESUME,
105 .get_brightness = gmux_get_brightness, 109 .get_brightness = gmux_get_brightness,
106 .update_status = gmux_update_status, 110 .update_status = gmux_update_status,
107}; 111};
diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c
index e6c08ee8d46c..5f78aac9b163 100644
--- a/drivers/platform/x86/dell-laptop.c
+++ b/drivers/platform/x86/dell-laptop.c
@@ -21,7 +21,6 @@
21#include <linux/err.h> 21#include <linux/err.h>
22#include <linux/dmi.h> 22#include <linux/dmi.h>
23#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/rfkill.h>
25#include <linux/power_supply.h> 24#include <linux/power_supply.h>
26#include <linux/acpi.h> 25#include <linux/acpi.h>
27#include <linux/mm.h> 26#include <linux/mm.h>
@@ -90,11 +89,8 @@ static struct platform_driver platform_driver = {
90 89
91static struct platform_device *platform_device; 90static struct platform_device *platform_device;
92static struct backlight_device *dell_backlight_device; 91static struct backlight_device *dell_backlight_device;
93static struct rfkill *wifi_rfkill;
94static struct rfkill *bluetooth_rfkill;
95static struct rfkill *wwan_rfkill;
96 92
97static const struct dmi_system_id __initdata dell_device_table[] = { 93static const struct dmi_system_id dell_device_table[] __initconst = {
98 { 94 {
99 .ident = "Dell laptop", 95 .ident = "Dell laptop",
100 .matches = { 96 .matches = {
@@ -119,96 +115,94 @@ static const struct dmi_system_id __initdata dell_device_table[] = {
119}; 115};
120MODULE_DEVICE_TABLE(dmi, dell_device_table); 116MODULE_DEVICE_TABLE(dmi, dell_device_table);
121 117
122static struct dmi_system_id __devinitdata dell_blacklist[] = { 118static struct dmi_system_id __devinitdata dell_quirks[] = {
123 /* Supported by compal-laptop */
124 {
125 .ident = "Dell Mini 9",
126 .matches = {
127 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
128 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"),
129 },
130 },
131 { 119 {
132 .ident = "Dell Mini 10", 120 .callback = dmi_matched,
121 .ident = "Dell Vostro V130",
133 .matches = { 122 .matches = {
134 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 123 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
135 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"), 124 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"),
136 }, 125 },
126 .driver_data = &quirk_dell_vostro_v130,
137 }, 127 },
138 { 128 {
139 .ident = "Dell Mini 10v", 129 .callback = dmi_matched,
130 .ident = "Dell Vostro V131",
140 .matches = { 131 .matches = {
141 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 132 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
142 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), 133 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"),
143 }, 134 },
135 .driver_data = &quirk_dell_vostro_v130,
144 }, 136 },
145 { 137 {
146 .ident = "Dell Mini 1012", 138 .callback = dmi_matched,
139 .ident = "Dell Vostro 3350",
147 .matches = { 140 .matches = {
148 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 141 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
149 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), 142 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"),
150 }, 143 },
144 .driver_data = &quirk_dell_vostro_v130,
151 }, 145 },
152 { 146 {
153 .ident = "Dell Inspiron 11z", 147 .callback = dmi_matched,
148 .ident = "Dell Vostro 3555",
154 .matches = { 149 .matches = {
155 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 150 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
156 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"), 151 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"),
157 }, 152 },
153 .driver_data = &quirk_dell_vostro_v130,
158 }, 154 },
159 { 155 {
160 .ident = "Dell Mini 12", 156 .callback = dmi_matched,
157 .ident = "Dell Inspiron N311z",
161 .matches = { 158 .matches = {
162 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 159 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
163 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"), 160 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"),
164 }, 161 },
162 .driver_data = &quirk_dell_vostro_v130,
165 }, 163 },
166 {}
167};
168
169static struct dmi_system_id __devinitdata dell_quirks[] = {
170 { 164 {
171 .callback = dmi_matched, 165 .callback = dmi_matched,
172 .ident = "Dell Vostro V130", 166 .ident = "Dell Inspiron M5110",
173 .matches = { 167 .matches = {
174 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 168 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
175 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V130"), 169 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"),
176 }, 170 },
177 .driver_data = &quirk_dell_vostro_v130, 171 .driver_data = &quirk_dell_vostro_v130,
178 }, 172 },
179 { 173 {
180 .callback = dmi_matched, 174 .callback = dmi_matched,
181 .ident = "Dell Vostro V131", 175 .ident = "Dell Vostro 3360",
182 .matches = { 176 .matches = {
183 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 177 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
184 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), 178 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3360"),
185 }, 179 },
186 .driver_data = &quirk_dell_vostro_v130, 180 .driver_data = &quirk_dell_vostro_v130,
187 }, 181 },
188 { 182 {
189 .callback = dmi_matched, 183 .callback = dmi_matched,
190 .ident = "Dell Vostro 3555", 184 .ident = "Dell Vostro 3460",
191 .matches = { 185 .matches = {
192 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 186 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
193 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3555"), 187 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3460"),
194 }, 188 },
195 .driver_data = &quirk_dell_vostro_v130, 189 .driver_data = &quirk_dell_vostro_v130,
196 }, 190 },
197 { 191 {
198 .callback = dmi_matched, 192 .callback = dmi_matched,
199 .ident = "Dell Inspiron N311z", 193 .ident = "Dell Vostro 3560",
200 .matches = { 194 .matches = {
201 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 195 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
202 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron N311z"), 196 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3560"),
203 }, 197 },
204 .driver_data = &quirk_dell_vostro_v130, 198 .driver_data = &quirk_dell_vostro_v130,
205 }, 199 },
206 { 200 {
207 .callback = dmi_matched, 201 .callback = dmi_matched,
208 .ident = "Dell Inspiron M5110", 202 .ident = "Dell Vostro 3450",
209 .matches = { 203 .matches = {
210 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 204 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
211 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), 205 DMI_MATCH(DMI_PRODUCT_NAME, "Dell System Vostro 3450"),
212 }, 206 },
213 .driver_data = &quirk_dell_vostro_v130, 207 .driver_data = &quirk_dell_vostro_v130,
214 }, 208 },
@@ -305,94 +299,6 @@ dell_send_request(struct calling_interface_buffer *buffer, int class,
305 return buffer; 299 return buffer;
306} 300}
307 301
308/* Derived from information in DellWirelessCtl.cpp:
309 Class 17, select 11 is radio control. It returns an array of 32-bit values.
310
311 Input byte 0 = 0: Wireless information
312
313 result[0]: return code
314 result[1]:
315 Bit 0: Hardware switch supported
316 Bit 1: Wifi locator supported
317 Bit 2: Wifi is supported
318 Bit 3: Bluetooth is supported
319 Bit 4: WWAN is supported
320 Bit 5: Wireless keyboard supported
321 Bits 6-7: Reserved
322 Bit 8: Wifi is installed
323 Bit 9: Bluetooth is installed
324 Bit 10: WWAN is installed
325 Bits 11-15: Reserved
326 Bit 16: Hardware switch is on
327 Bit 17: Wifi is blocked
328 Bit 18: Bluetooth is blocked
329 Bit 19: WWAN is blocked
330 Bits 20-31: Reserved
331 result[2]: NVRAM size in bytes
332 result[3]: NVRAM format version number
333
334 Input byte 0 = 2: Wireless switch configuration
335 result[0]: return code
336 result[1]:
337 Bit 0: Wifi controlled by switch
338 Bit 1: Bluetooth controlled by switch
339 Bit 2: WWAN controlled by switch
340 Bits 3-6: Reserved
341 Bit 7: Wireless switch config locked
342 Bit 8: Wifi locator enabled
343 Bits 9-14: Reserved
344 Bit 15: Wifi locator setting locked
345 Bits 16-31: Reserved
346*/
347
348static int dell_rfkill_set(void *data, bool blocked)
349{
350 int disable = blocked ? 1 : 0;
351 unsigned long radio = (unsigned long)data;
352 int hwswitch_bit = (unsigned long)data - 1;
353 int ret = 0;
354
355 get_buffer();
356 dell_send_request(buffer, 17, 11);
357
358 /* If the hardware switch controls this radio, and the hardware
359 switch is disabled, don't allow changing the software state */
360 if ((hwswitch_state & BIT(hwswitch_bit)) &&
361 !(buffer->output[1] & BIT(16))) {
362 ret = -EINVAL;
363 goto out;
364 }
365
366 buffer->input[0] = (1 | (radio<<8) | (disable << 16));
367 dell_send_request(buffer, 17, 11);
368
369out:
370 release_buffer();
371 return ret;
372}
373
374static void dell_rfkill_query(struct rfkill *rfkill, void *data)
375{
376 int status;
377 int bit = (unsigned long)data + 16;
378 int hwswitch_bit = (unsigned long)data - 1;
379
380 get_buffer();
381 dell_send_request(buffer, 17, 11);
382 status = buffer->output[1];
383 release_buffer();
384
385 rfkill_set_sw_state(rfkill, !!(status & BIT(bit)));
386
387 if (hwswitch_state & (BIT(hwswitch_bit)))
388 rfkill_set_hw_state(rfkill, !(status & BIT(16)));
389}
390
391static const struct rfkill_ops dell_rfkill_ops = {
392 .set_block = dell_rfkill_set,
393 .query = dell_rfkill_query,
394};
395
396static struct dentry *dell_laptop_dir; 302static struct dentry *dell_laptop_dir;
397 303
398static int dell_debugfs_show(struct seq_file *s, void *data) 304static int dell_debugfs_show(struct seq_file *s, void *data)
@@ -462,108 +368,6 @@ static const struct file_operations dell_debugfs_fops = {
462 .release = single_release, 368 .release = single_release,
463}; 369};
464 370
465static void dell_update_rfkill(struct work_struct *ignored)
466{
467 if (wifi_rfkill)
468 dell_rfkill_query(wifi_rfkill, (void *)1);
469 if (bluetooth_rfkill)
470 dell_rfkill_query(bluetooth_rfkill, (void *)2);
471 if (wwan_rfkill)
472 dell_rfkill_query(wwan_rfkill, (void *)3);
473}
474static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
475
476
477static int __init dell_setup_rfkill(void)
478{
479 int status;
480 int ret;
481
482 if (dmi_check_system(dell_blacklist)) {
483 pr_info("Blacklisted hardware detected - not enabling rfkill\n");
484 return 0;
485 }
486
487 get_buffer();
488 dell_send_request(buffer, 17, 11);
489 status = buffer->output[1];
490 buffer->input[0] = 0x2;
491 dell_send_request(buffer, 17, 11);
492 hwswitch_state = buffer->output[1];
493 release_buffer();
494
495 if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) {
496 wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev,
497 RFKILL_TYPE_WLAN,
498 &dell_rfkill_ops, (void *) 1);
499 if (!wifi_rfkill) {
500 ret = -ENOMEM;
501 goto err_wifi;
502 }
503 ret = rfkill_register(wifi_rfkill);
504 if (ret)
505 goto err_wifi;
506 }
507
508 if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) {
509 bluetooth_rfkill = rfkill_alloc("dell-bluetooth",
510 &platform_device->dev,
511 RFKILL_TYPE_BLUETOOTH,
512 &dell_rfkill_ops, (void *) 2);
513 if (!bluetooth_rfkill) {
514 ret = -ENOMEM;
515 goto err_bluetooth;
516 }
517 ret = rfkill_register(bluetooth_rfkill);
518 if (ret)
519 goto err_bluetooth;
520 }
521
522 if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) {
523 wwan_rfkill = rfkill_alloc("dell-wwan",
524 &platform_device->dev,
525 RFKILL_TYPE_WWAN,
526 &dell_rfkill_ops, (void *) 3);
527 if (!wwan_rfkill) {
528 ret = -ENOMEM;
529 goto err_wwan;
530 }
531 ret = rfkill_register(wwan_rfkill);
532 if (ret)
533 goto err_wwan;
534 }
535
536 return 0;
537err_wwan:
538 rfkill_destroy(wwan_rfkill);
539 if (bluetooth_rfkill)
540 rfkill_unregister(bluetooth_rfkill);
541err_bluetooth:
542 rfkill_destroy(bluetooth_rfkill);
543 if (wifi_rfkill)
544 rfkill_unregister(wifi_rfkill);
545err_wifi:
546 rfkill_destroy(wifi_rfkill);
547
548 return ret;
549}
550
551static void dell_cleanup_rfkill(void)
552{
553 if (wifi_rfkill) {
554 rfkill_unregister(wifi_rfkill);
555 rfkill_destroy(wifi_rfkill);
556 }
557 if (bluetooth_rfkill) {
558 rfkill_unregister(bluetooth_rfkill);
559 rfkill_destroy(bluetooth_rfkill);
560 }
561 if (wwan_rfkill) {
562 rfkill_unregister(wwan_rfkill);
563 rfkill_destroy(wwan_rfkill);
564 }
565}
566
567static int dell_send_intensity(struct backlight_device *bd) 371static int dell_send_intensity(struct backlight_device *bd)
568{ 372{
569 int ret = 0; 373 int ret = 0;
@@ -655,30 +459,6 @@ static void touchpad_led_exit(void)
655 led_classdev_unregister(&touchpad_led); 459 led_classdev_unregister(&touchpad_led);
656} 460}
657 461
658static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
659 struct serio *port)
660{
661 static bool extended;
662
663 if (str & 0x20)
664 return false;
665
666 if (unlikely(data == 0xe0)) {
667 extended = true;
668 return false;
669 } else if (unlikely(extended)) {
670 switch (data) {
671 case 0x8:
672 schedule_delayed_work(&dell_rfkill_work,
673 round_jiffies_relative(HZ));
674 break;
675 }
676 extended = false;
677 }
678
679 return false;
680}
681
682static int __init dell_init(void) 462static int __init dell_init(void)
683{ 463{
684 int max_intensity = 0; 464 int max_intensity = 0;
@@ -720,26 +500,10 @@ static int __init dell_init(void)
720 goto fail_buffer; 500 goto fail_buffer;
721 buffer = page_address(bufferpage); 501 buffer = page_address(bufferpage);
722 502
723 ret = dell_setup_rfkill();
724
725 if (ret) {
726 pr_warn("Unable to setup rfkill\n");
727 goto fail_rfkill;
728 }
729
730 ret = i8042_install_filter(dell_laptop_i8042_filter);
731 if (ret) {
732 pr_warn("Unable to install key filter\n");
733 goto fail_filter;
734 }
735
736 if (quirks && quirks->touchpad_led) 503 if (quirks && quirks->touchpad_led)
737 touchpad_led_init(&platform_device->dev); 504 touchpad_led_init(&platform_device->dev);
738 505
739 dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); 506 dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
740 if (dell_laptop_dir != NULL)
741 debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
742 &dell_debugfs_fops);
743 507
744#ifdef CONFIG_ACPI 508#ifdef CONFIG_ACPI
745 /* In the event of an ACPI backlight being available, don't 509 /* In the event of an ACPI backlight being available, don't
@@ -782,11 +546,6 @@ static int __init dell_init(void)
782 return 0; 546 return 0;
783 547
784fail_backlight: 548fail_backlight:
785 i8042_remove_filter(dell_laptop_i8042_filter);
786 cancel_delayed_work_sync(&dell_rfkill_work);
787fail_filter:
788 dell_cleanup_rfkill();
789fail_rfkill:
790 free_page((unsigned long)bufferpage); 549 free_page((unsigned long)bufferpage);
791fail_buffer: 550fail_buffer:
792 platform_device_del(platform_device); 551 platform_device_del(platform_device);
@@ -804,10 +563,7 @@ static void __exit dell_exit(void)
804 debugfs_remove_recursive(dell_laptop_dir); 563 debugfs_remove_recursive(dell_laptop_dir);
805 if (quirks && quirks->touchpad_led) 564 if (quirks && quirks->touchpad_led)
806 touchpad_led_exit(); 565 touchpad_led_exit();
807 i8042_remove_filter(dell_laptop_i8042_filter);
808 cancel_delayed_work_sync(&dell_rfkill_work);
809 backlight_device_unregister(dell_backlight_device); 566 backlight_device_unregister(dell_backlight_device);
810 dell_cleanup_rfkill();
811 if (platform_device) { 567 if (platform_device) {
812 platform_device_unregister(platform_device); 568 platform_device_unregister(platform_device);
813 platform_driver_unregister(&platform_driver); 569 platform_driver_unregister(&platform_driver);
diff --git a/drivers/platform/x86/fujitsu-tablet.c b/drivers/platform/x86/fujitsu-tablet.c
index 580d80a73c3a..da267eae8ba8 100644
--- a/drivers/platform/x86/fujitsu-tablet.c
+++ b/drivers/platform/x86/fujitsu-tablet.c
@@ -16,6 +16,8 @@
16 * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA. 16 * 59 Temple Place Suite 330, Boston, MA 02111-1307, USA.
17 */ 17 */
18 18
19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
19#include <linux/kernel.h> 21#include <linux/kernel.h>
20#include <linux/module.h> 22#include <linux/module.h>
21#include <linux/init.h> 23#include <linux/init.h>
@@ -34,7 +36,8 @@
34#define ACPI_FUJITSU_CLASS "fujitsu" 36#define ACPI_FUJITSU_CLASS "fujitsu"
35 37
36#define INVERT_TABLET_MODE_BIT 0x01 38#define INVERT_TABLET_MODE_BIT 0x01
37#define FORCE_TABLET_MODE_IF_UNDOCK 0x02 39#define INVERT_DOCK_STATE_BIT 0x02
40#define FORCE_TABLET_MODE_IF_UNDOCK 0x04
38 41
39#define KEYMAP_LEN 16 42#define KEYMAP_LEN 16
40 43
@@ -161,6 +164,8 @@ static void fujitsu_send_state(void)
161 state = fujitsu_read_register(0xdd); 164 state = fujitsu_read_register(0xdd);
162 165
163 dock = state & 0x02; 166 dock = state & 0x02;
167 if (fujitsu.config.quirks & INVERT_DOCK_STATE_BIT)
168 dock = !dock;
164 169
165 if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) { 170 if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) {
166 tablet_mode = 1; 171 tablet_mode = 1;
@@ -221,9 +226,6 @@ static int __devinit input_fujitsu_setup(struct device *parent,
221 input_set_capability(idev, EV_SW, SW_DOCK); 226 input_set_capability(idev, EV_SW, SW_DOCK);
222 input_set_capability(idev, EV_SW, SW_TABLET_MODE); 227 input_set_capability(idev, EV_SW, SW_TABLET_MODE);
223 228
224 input_set_capability(idev, EV_SW, SW_DOCK);
225 input_set_capability(idev, EV_SW, SW_TABLET_MODE);
226
227 error = input_register_device(idev); 229 error = input_register_device(idev);
228 if (error) { 230 if (error) {
229 input_free_device(idev); 231 input_free_device(idev);
@@ -275,25 +277,31 @@ static irqreturn_t fujitsu_interrupt(int irq, void *dev_id)
275 return IRQ_HANDLED; 277 return IRQ_HANDLED;
276} 278}
277 279
278static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi) 280static void __devinit fujitsu_dmi_common(const struct dmi_system_id *dmi)
279{ 281{
280 printk(KERN_INFO MODULENAME ": %s\n", dmi->ident); 282 pr_info("%s\n", dmi->ident);
281 memcpy(fujitsu.config.keymap, dmi->driver_data, 283 memcpy(fujitsu.config.keymap, dmi->driver_data,
282 sizeof(fujitsu.config.keymap)); 284 sizeof(fujitsu.config.keymap));
285}
286
287static int __devinit fujitsu_dmi_lifebook(const struct dmi_system_id *dmi)
288{
289 fujitsu_dmi_common(dmi);
290 fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT;
283 return 1; 291 return 1;
284} 292}
285 293
286static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) 294static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi)
287{ 295{
288 fujitsu_dmi_default(dmi); 296 fujitsu_dmi_common(dmi);
289 fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; 297 fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK;
290 fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; 298 fujitsu.config.quirks |= INVERT_DOCK_STATE_BIT;
291 return 1; 299 return 1;
292} 300}
293 301
294static struct dmi_system_id dmi_ids[] __initconst = { 302static struct dmi_system_id dmi_ids[] __initconst = {
295 { 303 {
296 .callback = fujitsu_dmi_default, 304 .callback = fujitsu_dmi_lifebook,
297 .ident = "Fujitsu Siemens P/T Series", 305 .ident = "Fujitsu Siemens P/T Series",
298 .matches = { 306 .matches = {
299 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 307 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
@@ -302,7 +310,7 @@ static struct dmi_system_id dmi_ids[] __initconst = {
302 .driver_data = keymap_Lifebook_Tseries 310 .driver_data = keymap_Lifebook_Tseries
303 }, 311 },
304 { 312 {
305 .callback = fujitsu_dmi_default, 313 .callback = fujitsu_dmi_lifebook,
306 .ident = "Fujitsu Lifebook T Series", 314 .ident = "Fujitsu Lifebook T Series",
307 .matches = { 315 .matches = {
308 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 316 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
@@ -320,7 +328,7 @@ static struct dmi_system_id dmi_ids[] __initconst = {
320 .driver_data = keymap_Stylistic_Tseries 328 .driver_data = keymap_Stylistic_Tseries
321 }, 329 },
322 { 330 {
323 .callback = fujitsu_dmi_default, 331 .callback = fujitsu_dmi_lifebook,
324 .ident = "Fujitsu LifeBook U810", 332 .ident = "Fujitsu LifeBook U810",
325 .matches = { 333 .matches = {
326 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 334 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
@@ -347,7 +355,7 @@ static struct dmi_system_id dmi_ids[] __initconst = {
347 .driver_data = keymap_Stylistic_ST5xxx 355 .driver_data = keymap_Stylistic_ST5xxx
348 }, 356 },
349 { 357 {
350 .callback = fujitsu_dmi_default, 358 .callback = fujitsu_dmi_lifebook,
351 .ident = "Unknown (using defaults)", 359 .ident = "Unknown (using defaults)",
352 .matches = { 360 .matches = {
353 DMI_MATCH(DMI_SYS_VENDOR, ""), 361 DMI_MATCH(DMI_SYS_VENDOR, ""),
@@ -473,6 +481,6 @@ module_exit(fujitsu_module_exit);
473MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>"); 481MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>");
474MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); 482MODULE_DESCRIPTION("Fujitsu tablet pc extras driver");
475MODULE_LICENSE("GPL"); 483MODULE_LICENSE("GPL");
476MODULE_VERSION("2.4"); 484MODULE_VERSION("2.5");
477 485
478MODULE_DEVICE_TABLE(acpi, fujitsu_ids); 486MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
diff --git a/drivers/platform/x86/hdaps.c b/drivers/platform/x86/hdaps.c
index 7387f97a2941..24a3ae065f1b 100644
--- a/drivers/platform/x86/hdaps.c
+++ b/drivers/platform/x86/hdaps.c
@@ -2,7 +2,7 @@
2 * hdaps.c - driver for IBM's Hard Drive Active Protection System 2 * hdaps.c - driver for IBM's Hard Drive Active Protection System
3 * 3 *
4 * Copyright (C) 2005 Robert Love <rml@novell.com> 4 * Copyright (C) 2005 Robert Love <rml@novell.com>
5 * Copyright (C) 2005 Jesper Juhl <jesper.juhl@gmail.com> 5 * Copyright (C) 2005 Jesper Juhl <jj@chaosbits.net>
6 * 6 *
7 * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads 7 * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads
8 * starting with the R40, T41, and X40. It provides a basic two-axis 8 * starting with the R40, T41, and X40. It provides a basic two-axis
diff --git a/drivers/platform/x86/hp-wmi.c b/drivers/platform/x86/hp-wmi.c
index e2faa3cbb792..387183a2d6dd 100644
--- a/drivers/platform/x86/hp-wmi.c
+++ b/drivers/platform/x86/hp-wmi.c
@@ -634,6 +634,8 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
634 RFKILL_TYPE_WLAN, 634 RFKILL_TYPE_WLAN,
635 &hp_wmi_rfkill_ops, 635 &hp_wmi_rfkill_ops,
636 (void *) HPWMI_WIFI); 636 (void *) HPWMI_WIFI);
637 if (!wifi_rfkill)
638 return -ENOMEM;
637 rfkill_init_sw_state(wifi_rfkill, 639 rfkill_init_sw_state(wifi_rfkill,
638 hp_wmi_get_sw_state(HPWMI_WIFI)); 640 hp_wmi_get_sw_state(HPWMI_WIFI));
639 rfkill_set_hw_state(wifi_rfkill, 641 rfkill_set_hw_state(wifi_rfkill,
@@ -648,6 +650,10 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
648 RFKILL_TYPE_BLUETOOTH, 650 RFKILL_TYPE_BLUETOOTH,
649 &hp_wmi_rfkill_ops, 651 &hp_wmi_rfkill_ops,
650 (void *) HPWMI_BLUETOOTH); 652 (void *) HPWMI_BLUETOOTH);
653 if (!bluetooth_rfkill) {
654 err = -ENOMEM;
655 goto register_wifi_error;
656 }
651 rfkill_init_sw_state(bluetooth_rfkill, 657 rfkill_init_sw_state(bluetooth_rfkill,
652 hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); 658 hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
653 rfkill_set_hw_state(bluetooth_rfkill, 659 rfkill_set_hw_state(bluetooth_rfkill,
@@ -662,6 +668,10 @@ static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
662 RFKILL_TYPE_WWAN, 668 RFKILL_TYPE_WWAN,
663 &hp_wmi_rfkill_ops, 669 &hp_wmi_rfkill_ops,
664 (void *) HPWMI_WWAN); 670 (void *) HPWMI_WWAN);
671 if (!wwan_rfkill) {
672 err = -ENOMEM;
673 goto register_bluetooth_error;
674 }
665 rfkill_init_sw_state(wwan_rfkill, 675 rfkill_init_sw_state(wwan_rfkill,
666 hp_wmi_get_sw_state(HPWMI_WWAN)); 676 hp_wmi_get_sw_state(HPWMI_WWAN));
667 rfkill_set_hw_state(wwan_rfkill, 677 rfkill_set_hw_state(wwan_rfkill,
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index ac902f7a9baa..4f20f8dd3d7c 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -194,7 +194,6 @@ static int write_ec_cmd(acpi_handle handle, int cmd, unsigned long data)
194/* 194/*
195 * debugfs 195 * debugfs
196 */ 196 */
197#define DEBUGFS_EVENT_LEN (4096)
198static int debugfs_status_show(struct seq_file *s, void *data) 197static int debugfs_status_show(struct seq_file *s, void *data)
199{ 198{
200 unsigned long value; 199 unsigned long value;
@@ -315,7 +314,7 @@ static int __devinit ideapad_debugfs_init(struct ideapad_private *priv)
315 node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL, 314 node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL,
316 &debugfs_status_fops); 315 &debugfs_status_fops);
317 if (!node) { 316 if (!node) {
318 pr_err("failed to create event in debugfs"); 317 pr_err("failed to create status in debugfs");
319 goto errout; 318 goto errout;
320 } 319 }
321 320
@@ -785,6 +784,10 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
785 case 9: 784 case 9:
786 ideapad_sync_rfk_state(priv); 785 ideapad_sync_rfk_state(priv);
787 break; 786 break;
787 case 13:
788 case 6:
789 ideapad_input_report(priv, vpc_bit);
790 break;
788 case 4: 791 case 4:
789 ideapad_backlight_notify_brightness(priv); 792 ideapad_backlight_notify_brightness(priv);
790 break; 793 break;
@@ -795,7 +798,7 @@ static void ideapad_acpi_notify(struct acpi_device *adevice, u32 event)
795 ideapad_backlight_notify_power(priv); 798 ideapad_backlight_notify_power(priv);
796 break; 799 break;
797 default: 800 default:
798 ideapad_input_report(priv, vpc_bit); 801 pr_info("Unknown event: %lu\n", vpc_bit);
799 } 802 }
800 } 803 }
801 } 804 }
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 8a51795aa02a..210d4ae547c2 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -141,6 +141,27 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
141 "(default: 0)"); 141 "(default: 0)");
142 142
143static void sony_nc_kbd_backlight_resume(void); 143static void sony_nc_kbd_backlight_resume(void);
144static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
145 unsigned int handle);
146static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
147
148static int sony_nc_battery_care_setup(struct platform_device *pd,
149 unsigned int handle);
150static void sony_nc_battery_care_cleanup(struct platform_device *pd);
151
152static int sony_nc_thermal_setup(struct platform_device *pd);
153static void sony_nc_thermal_cleanup(struct platform_device *pd);
154static void sony_nc_thermal_resume(void);
155
156static int sony_nc_lid_resume_setup(struct platform_device *pd);
157static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
158
159static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
160static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
161
162static int sony_nc_touchpad_setup(struct platform_device *pd,
163 unsigned int handle);
164static void sony_nc_touchpad_cleanup(struct platform_device *pd);
144 165
145enum sony_nc_rfkill { 166enum sony_nc_rfkill {
146 SONY_WIFI, 167 SONY_WIFI,
@@ -153,6 +174,9 @@ enum sony_nc_rfkill {
153static int sony_rfkill_handle; 174static int sony_rfkill_handle;
154static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; 175static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
155static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; 176static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
177static int sony_nc_rfkill_setup(struct acpi_device *device,
178 unsigned int handle);
179static void sony_nc_rfkill_cleanup(void);
156static void sony_nc_rfkill_update(void); 180static void sony_nc_rfkill_update(void);
157 181
158/*********** Input Devices ***********/ 182/*********** Input Devices ***********/
@@ -691,59 +715,97 @@ static struct acpi_device *sony_nc_acpi_device = NULL;
691 715
692/* 716/*
693 * acpi_evaluate_object wrappers 717 * acpi_evaluate_object wrappers
718 * all useful calls into SNC methods take one or zero parameters and return
719 * integers or arrays.
694 */ 720 */
695static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) 721static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
722 u64 *value)
696{ 723{
697 struct acpi_buffer output; 724 union acpi_object *result = NULL;
698 union acpi_object out_obj; 725 struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
699 acpi_status status; 726 acpi_status status;
700 727
701 output.length = sizeof(out_obj); 728 if (value) {
702 output.pointer = &out_obj; 729 struct acpi_object_list params;
730 union acpi_object in;
731 in.type = ACPI_TYPE_INTEGER;
732 in.integer.value = *value;
733 params.count = 1;
734 params.pointer = &in;
735 status = acpi_evaluate_object(handle, method, &params, &output);
736 dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method,
737 (unsigned int)(*value >> 32),
738 (unsigned int)*value & 0xffffffff);
739 } else {
740 status = acpi_evaluate_object(handle, method, NULL, &output);
741 dprintk("__call_snc_method: [%s]\n", method);
742 }
703 743
704 status = acpi_evaluate_object(handle, name, NULL, &output); 744 if (ACPI_FAILURE(status)) {
705 if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { 745 pr_err("Failed to evaluate [%s]\n", method);
706 *result = out_obj.integer.value; 746 return NULL;
707 return 0;
708 } 747 }
709 748
710 pr_warn("acpi_callreadfunc failed\n"); 749 result = (union acpi_object *) output.pointer;
750 if (!result)
751 dprintk("No return object [%s]\n", method);
711 752
712 return -1; 753 return result;
713} 754}
714 755
715static int acpi_callsetfunc(acpi_handle handle, char *name, int value, 756static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
716 int *result) 757 int *result)
717{ 758{
718 struct acpi_object_list params; 759 union acpi_object *object = NULL;
719 union acpi_object in_obj; 760 if (value) {
720 struct acpi_buffer output; 761 u64 v = *value;
721 union acpi_object out_obj; 762 object = __call_snc_method(handle, name, &v);
722 acpi_status status; 763 } else
723 764 object = __call_snc_method(handle, name, NULL);
724 params.count = 1;
725 params.pointer = &in_obj;
726 in_obj.type = ACPI_TYPE_INTEGER;
727 in_obj.integer.value = value;
728 765
729 output.length = sizeof(out_obj); 766 if (!object)
730 output.pointer = &out_obj; 767 return -EINVAL;
731 768
732 status = acpi_evaluate_object(handle, name, &params, &output); 769 if (object->type != ACPI_TYPE_INTEGER) {
733 if (status == AE_OK) { 770 pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
734 if (result != NULL) { 771 ACPI_TYPE_INTEGER, object->type);
735 if (out_obj.type != ACPI_TYPE_INTEGER) { 772 kfree(object);
736 pr_warn("acpi_evaluate_object bad return type\n"); 773 return -EINVAL;
737 return -1;
738 }
739 *result = out_obj.integer.value;
740 }
741 return 0;
742 } 774 }
743 775
744 pr_warn("acpi_evaluate_object failed\n"); 776 if (result)
777 *result = object->integer.value;
778
779 kfree(object);
780 return 0;
781}
782
783#define MIN(a, b) (a > b ? b : a)
784static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
785 void *buffer, size_t buflen)
786{
787 size_t len = len;
788 union acpi_object *object = __call_snc_method(handle, name, value);
789
790 if (!object)
791 return -EINVAL;
792
793 if (object->type == ACPI_TYPE_BUFFER)
794 len = MIN(buflen, object->buffer.length);
795
796 else if (object->type == ACPI_TYPE_INTEGER)
797 len = MIN(buflen, sizeof(object->integer.value));
798
799 else {
800 pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
801 ACPI_TYPE_BUFFER, object->type);
802 kfree(object);
803 return -EINVAL;
804 }
745 805
746 return -1; 806 memcpy(buffer, object->buffer.pointer, len);
807 kfree(object);
808 return 0;
747} 809}
748 810
749struct sony_nc_handles { 811struct sony_nc_handles {
@@ -770,16 +832,17 @@ static ssize_t sony_nc_handles_show(struct device *dev,
770 832
771static int sony_nc_handles_setup(struct platform_device *pd) 833static int sony_nc_handles_setup(struct platform_device *pd)
772{ 834{
773 int i; 835 int i, r, result, arg;
774 int result;
775 836
776 handles = kzalloc(sizeof(*handles), GFP_KERNEL); 837 handles = kzalloc(sizeof(*handles), GFP_KERNEL);
777 if (!handles) 838 if (!handles)
778 return -ENOMEM; 839 return -ENOMEM;
779 840
780 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 841 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
781 if (!acpi_callsetfunc(sony_nc_acpi_handle, 842 arg = i + 0x20;
782 "SN00", i + 0x20, &result)) { 843 r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
844 &result);
845 if (!r) {
783 dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", 846 dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
784 result, i); 847 result, i);
785 handles->cap[i] = result; 848 handles->cap[i] = result;
@@ -819,8 +882,8 @@ static int sony_find_snc_handle(int handle)
819 int i; 882 int i;
820 883
821 /* not initialized yet, return early */ 884 /* not initialized yet, return early */
822 if (!handles) 885 if (!handles || !handle)
823 return -1; 886 return -EINVAL;
824 887
825 for (i = 0; i < 0x10; i++) { 888 for (i = 0; i < 0x10; i++) {
826 if (handles->cap[i] == handle) { 889 if (handles->cap[i] == handle) {
@@ -830,21 +893,20 @@ static int sony_find_snc_handle(int handle)
830 } 893 }
831 } 894 }
832 dprintk("handle 0x%.4x not found\n", handle); 895 dprintk("handle 0x%.4x not found\n", handle);
833 return -1; 896 return -EINVAL;
834} 897}
835 898
836static int sony_call_snc_handle(int handle, int argument, int *result) 899static int sony_call_snc_handle(int handle, int argument, int *result)
837{ 900{
838 int ret = 0; 901 int arg, ret = 0;
839 int offset = sony_find_snc_handle(handle); 902 int offset = sony_find_snc_handle(handle);
840 903
841 if (offset < 0) 904 if (offset < 0)
842 return -1; 905 return offset;
843 906
844 ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, 907 arg = offset | argument;
845 result); 908 ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
846 dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, 909 dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
847 *result);
848 return ret; 910 return ret;
849} 911}
850 912
@@ -889,14 +951,16 @@ static int boolean_validate(const int direction, const int value)
889static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, 951static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
890 char *buffer) 952 char *buffer)
891{ 953{
892 int value; 954 int value, ret = 0;
893 struct sony_nc_value *item = 955 struct sony_nc_value *item =
894 container_of(attr, struct sony_nc_value, devattr); 956 container_of(attr, struct sony_nc_value, devattr);
895 957
896 if (!*item->acpiget) 958 if (!*item->acpiget)
897 return -EIO; 959 return -EIO;
898 960
899 if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) 961 ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL,
962 &value);
963 if (ret < 0)
900 return -EIO; 964 return -EIO;
901 965
902 if (item->validate) 966 if (item->validate)
@@ -909,7 +973,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
909 struct device_attribute *attr, 973 struct device_attribute *attr,
910 const char *buffer, size_t count) 974 const char *buffer, size_t count)
911{ 975{
912 int value; 976 unsigned long value = 0;
977 int ret = 0;
913 struct sony_nc_value *item = 978 struct sony_nc_value *item =
914 container_of(attr, struct sony_nc_value, devattr); 979 container_of(attr, struct sony_nc_value, devattr);
915 980
@@ -919,7 +984,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
919 if (count > 31) 984 if (count > 31)
920 return -EINVAL; 985 return -EINVAL;
921 986
922 value = simple_strtoul(buffer, NULL, 10); 987 if (kstrtoul(buffer, 10, &value))
988 return -EINVAL;
923 989
924 if (item->validate) 990 if (item->validate)
925 value = item->validate(SNC_VALIDATE_IN, value); 991 value = item->validate(SNC_VALIDATE_IN, value);
@@ -927,8 +993,11 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
927 if (value < 0) 993 if (value < 0)
928 return value; 994 return value;
929 995
930 if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) 996 ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
997 (int *)&value, NULL);
998 if (ret < 0)
931 return -EIO; 999 return -EIO;
1000
932 item->value = value; 1001 item->value = value;
933 item->valid = 1; 1002 item->valid = 1;
934 return count; 1003 return count;
@@ -948,15 +1017,15 @@ struct sony_backlight_props sony_bl_props;
948 1017
949static int sony_backlight_update_status(struct backlight_device *bd) 1018static int sony_backlight_update_status(struct backlight_device *bd)
950{ 1019{
951 return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", 1020 int arg = bd->props.brightness + 1;
952 bd->props.brightness + 1, NULL); 1021 return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL);
953} 1022}
954 1023
955static int sony_backlight_get_brightness(struct backlight_device *bd) 1024static int sony_backlight_get_brightness(struct backlight_device *bd)
956{ 1025{
957 int value; 1026 int value;
958 1027
959 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) 1028 if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value))
960 return 0; 1029 return 0;
961 /* brightness levels are 1-based, while backlight ones are 0-based */ 1030 /* brightness levels are 1-based, while backlight ones are 0-based */
962 return value - 1; 1031 return value - 1;
@@ -1024,10 +1093,14 @@ static struct sony_nc_event sony_100_events[] = {
1024 { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, 1093 { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
1025 { 0x87, SONYPI_EVENT_FNKEY_F7 }, 1094 { 0x87, SONYPI_EVENT_FNKEY_F7 },
1026 { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, 1095 { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
1096 { 0x88, SONYPI_EVENT_FNKEY_F8 },
1097 { 0x08, SONYPI_EVENT_FNKEY_RELEASED },
1027 { 0x89, SONYPI_EVENT_FNKEY_F9 }, 1098 { 0x89, SONYPI_EVENT_FNKEY_F9 },
1028 { 0x09, SONYPI_EVENT_FNKEY_RELEASED }, 1099 { 0x09, SONYPI_EVENT_FNKEY_RELEASED },
1029 { 0x8A, SONYPI_EVENT_FNKEY_F10 }, 1100 { 0x8A, SONYPI_EVENT_FNKEY_F10 },
1030 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, 1101 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
1102 { 0x8B, SONYPI_EVENT_FNKEY_F11 },
1103 { 0x0B, SONYPI_EVENT_FNKEY_RELEASED },
1031 { 0x8C, SONYPI_EVENT_FNKEY_F12 }, 1104 { 0x8C, SONYPI_EVENT_FNKEY_F12 },
1032 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, 1105 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
1033 { 0x9d, SONYPI_EVENT_ZOOM_PRESSED }, 1106 { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
@@ -1063,63 +1136,116 @@ static struct sony_nc_event sony_127_events[] = {
1063 { 0, 0 }, 1136 { 0, 0 },
1064}; 1137};
1065 1138
1139static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
1140{
1141 int ret = -EINVAL;
1142 unsigned int result = 0;
1143 struct sony_nc_event *key_event;
1144
1145 if (sony_call_snc_handle(handle, 0x200, &result)) {
1146 dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle,
1147 event);
1148 return -EINVAL;
1149 }
1150
1151 result &= 0xFF;
1152
1153 if (handle == 0x0100)
1154 key_event = sony_100_events;
1155 else
1156 key_event = sony_127_events;
1157
1158 for (; key_event->data; key_event++) {
1159 if (key_event->data == result) {
1160 ret = key_event->event;
1161 break;
1162 }
1163 }
1164
1165 if (!key_event->data)
1166 pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n",
1167 event, result, handle);
1168
1169 return ret;
1170}
1171
1066/* 1172/*
1067 * ACPI callbacks 1173 * ACPI callbacks
1068 */ 1174 */
1069static void sony_nc_notify(struct acpi_device *device, u32 event) 1175static void sony_nc_notify(struct acpi_device *device, u32 event)
1070{ 1176{
1071 u32 ev = event; 1177 u32 real_ev = event;
1178 u8 ev_type = 0;
1179 dprintk("sony_nc_notify, event: 0x%.2x\n", event);
1180
1181 if (event >= 0x90) {
1182 unsigned int result = 0;
1183 unsigned int arg = 0;
1184 unsigned int handle = 0;
1185 unsigned int offset = event - 0x90;
1186
1187 if (offset >= ARRAY_SIZE(handles->cap)) {
1188 pr_err("Event 0x%x outside of capabilities list\n",
1189 event);
1190 return;
1191 }
1192 handle = handles->cap[offset];
1193
1194 /* list of handles known for generating events */
1195 switch (handle) {
1196 /* hotkey event */
1197 case 0x0100:
1198 case 0x0127:
1199 ev_type = 1;
1200 real_ev = sony_nc_hotkeys_decode(event, handle);
1201
1202 if (real_ev > 0)
1203 sony_laptop_report_input_event(real_ev);
1204 else
1205 /* restore the original event for reporting */
1206 real_ev = event;
1072 1207
1073 if (ev >= 0x90) { 1208 break;
1074 /* New-style event */
1075 int result;
1076 int key_handle = 0;
1077 ev -= 0x90;
1078
1079 if (sony_find_snc_handle(0x100) == ev)
1080 key_handle = 0x100;
1081 if (sony_find_snc_handle(0x127) == ev)
1082 key_handle = 0x127;
1083
1084 if (key_handle) {
1085 struct sony_nc_event *key_event;
1086
1087 if (sony_call_snc_handle(key_handle, 0x200, &result)) {
1088 dprintk("sony_nc_notify, unable to decode"
1089 " event 0x%.2x 0x%.2x\n", key_handle,
1090 ev);
1091 /* restore the original event */
1092 ev = event;
1093 } else {
1094 ev = result & 0xFF;
1095
1096 if (key_handle == 0x100)
1097 key_event = sony_100_events;
1098 else
1099 key_event = sony_127_events;
1100
1101 for (; key_event->data; key_event++) {
1102 if (key_event->data == ev) {
1103 ev = key_event->event;
1104 break;
1105 }
1106 }
1107 1209
1108 if (!key_event->data) 1210 /* wlan switch */
1109 pr_info("Unknown event: 0x%x 0x%x\n", 1211 case 0x0124:
1110 key_handle, ev); 1212 case 0x0135:
1111 else 1213 /* events on this handle are reported when the
1112 sony_laptop_report_input_event(ev); 1214 * switch changes position or for battery
1113 } 1215 * events. We'll notify both of them but only
1114 } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) { 1216 * update the rfkill device status when the
1115 sony_nc_rfkill_update(); 1217 * switch is moved.
1116 return; 1218 */
1219 ev_type = 2;
1220 sony_call_snc_handle(handle, 0x0100, &result);
1221 real_ev = result & 0x03;
1222
1223 /* hw switch event */
1224 if (real_ev == 1)
1225 sony_nc_rfkill_update();
1226
1227 break;
1228
1229 default:
1230 dprintk("Unknown event 0x%x for handle 0x%x\n",
1231 event, handle);
1232 break;
1117 } 1233 }
1118 } else
1119 sony_laptop_report_input_event(ev);
1120 1234
1121 dprintk("sony_nc_notify, event: 0x%.2x\n", ev); 1235 /* clear the event (and the event reason when present) */
1122 acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); 1236 arg = 1 << offset;
1237 sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result);
1238
1239 } else {
1240 /* old style event */
1241 ev_type = 1;
1242 sony_laptop_report_input_event(real_ev);
1243 }
1244
1245 acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev);
1246
1247 acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
1248 dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
1123} 1249}
1124 1250
1125static acpi_status sony_walk_callback(acpi_handle handle, u32 level, 1251static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -1140,20 +1266,190 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
1140/* 1266/*
1141 * ACPI device 1267 * ACPI device
1142 */ 1268 */
1143static int sony_nc_function_setup(struct acpi_device *device) 1269static void sony_nc_function_setup(struct acpi_device *device,
1270 struct platform_device *pf_device)
1144{ 1271{
1145 int result; 1272 unsigned int i, result, bitmask, arg;
1273
1274 if (!handles)
1275 return;
1276
1277 /* setup found handles here */
1278 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1279 unsigned int handle = handles->cap[i];
1280
1281 if (!handle)
1282 continue;
1283
1284 dprintk("setting up handle 0x%.4x\n", handle);
1285
1286 switch (handle) {
1287 case 0x0100:
1288 case 0x0101:
1289 case 0x0127:
1290 /* setup hotkeys */
1291 sony_call_snc_handle(handle, 0, &result);
1292 break;
1293 case 0x0102:
1294 /* setup hotkeys */
1295 sony_call_snc_handle(handle, 0x100, &result);
1296 break;
1297 case 0x0105:
1298 case 0x0148:
1299 /* touchpad enable/disable */
1300 result = sony_nc_touchpad_setup(pf_device, handle);
1301 if (result)
1302 pr_err("couldn't set up touchpad control function (%d)\n",
1303 result);
1304 break;
1305 case 0x0115:
1306 case 0x0136:
1307 case 0x013f:
1308 result = sony_nc_battery_care_setup(pf_device, handle);
1309 if (result)
1310 pr_err("couldn't set up battery care function (%d)\n",
1311 result);
1312 break;
1313 case 0x0119:
1314 result = sony_nc_lid_resume_setup(pf_device);
1315 if (result)
1316 pr_err("couldn't set up lid resume function (%d)\n",
1317 result);
1318 break;
1319 case 0x0122:
1320 result = sony_nc_thermal_setup(pf_device);
1321 if (result)
1322 pr_err("couldn't set up thermal profile function (%d)\n",
1323 result);
1324 break;
1325 case 0x0131:
1326 result = sony_nc_highspeed_charging_setup(pf_device);
1327 if (result)
1328 pr_err("couldn't set up high speed charging function (%d)\n",
1329 result);
1330 break;
1331 case 0x0124:
1332 case 0x0135:
1333 result = sony_nc_rfkill_setup(device, handle);
1334 if (result)
1335 pr_err("couldn't set up rfkill support (%d)\n",
1336 result);
1337 break;
1338 case 0x0137:
1339 case 0x0143:
1340 result = sony_nc_kbd_backlight_setup(pf_device, handle);
1341 if (result)
1342 pr_err("couldn't set up keyboard backlight function (%d)\n",
1343 result);
1344 break;
1345 default:
1346 continue;
1347 }
1348 }
1146 1349
1147 /* Enable all events */ 1350 /* Enable all events */
1148 acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result); 1351 arg = 0x10;
1352 if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1353 sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1354 &result);
1355}
1356
1357static void sony_nc_function_cleanup(struct platform_device *pd)
1358{
1359 unsigned int i, result, bitmask, handle;
1149 1360
1150 /* Setup hotkeys */ 1361 /* get enabled events and disable them */
1151 sony_call_snc_handle(0x0100, 0, &result); 1362 sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask);
1152 sony_call_snc_handle(0x0101, 0, &result); 1363 sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result);
1153 sony_call_snc_handle(0x0102, 0x100, &result);
1154 sony_call_snc_handle(0x0127, 0, &result);
1155 1364
1156 return 0; 1365 /* cleanup handles here */
1366 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1367
1368 handle = handles->cap[i];
1369
1370 if (!handle)
1371 continue;
1372
1373 switch (handle) {
1374 case 0x0105:
1375 case 0x0148:
1376 sony_nc_touchpad_cleanup(pd);
1377 break;
1378 case 0x0115:
1379 case 0x0136:
1380 case 0x013f:
1381 sony_nc_battery_care_cleanup(pd);
1382 break;
1383 case 0x0119:
1384 sony_nc_lid_resume_cleanup(pd);
1385 break;
1386 case 0x0122:
1387 sony_nc_thermal_cleanup(pd);
1388 break;
1389 case 0x0131:
1390 sony_nc_highspeed_charging_cleanup(pd);
1391 break;
1392 case 0x0124:
1393 case 0x0135:
1394 sony_nc_rfkill_cleanup();
1395 break;
1396 case 0x0137:
1397 case 0x0143:
1398 sony_nc_kbd_backlight_cleanup(pd);
1399 break;
1400 default:
1401 continue;
1402 }
1403 }
1404
1405 /* finally cleanup the handles list */
1406 sony_nc_handles_cleanup(pd);
1407}
1408
1409static void sony_nc_function_resume(void)
1410{
1411 unsigned int i, result, bitmask, arg;
1412
1413 dprintk("Resuming SNC device\n");
1414
1415 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
1416 unsigned int handle = handles->cap[i];
1417
1418 if (!handle)
1419 continue;
1420
1421 switch (handle) {
1422 case 0x0100:
1423 case 0x0101:
1424 case 0x0127:
1425 /* re-enable hotkeys */
1426 sony_call_snc_handle(handle, 0, &result);
1427 break;
1428 case 0x0102:
1429 /* re-enable hotkeys */
1430 sony_call_snc_handle(handle, 0x100, &result);
1431 break;
1432 case 0x0122:
1433 sony_nc_thermal_resume();
1434 break;
1435 case 0x0124:
1436 case 0x0135:
1437 sony_nc_rfkill_update();
1438 break;
1439 case 0x0137:
1440 case 0x0143:
1441 sony_nc_kbd_backlight_resume();
1442 break;
1443 default:
1444 continue;
1445 }
1446 }
1447
1448 /* Enable all events */
1449 arg = 0x10;
1450 if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
1451 sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
1452 &result);
1157} 1453}
1158 1454
1159static int sony_nc_resume(struct acpi_device *device) 1455static int sony_nc_resume(struct acpi_device *device)
@@ -1166,8 +1462,8 @@ static int sony_nc_resume(struct acpi_device *device)
1166 1462
1167 if (!item->valid) 1463 if (!item->valid)
1168 continue; 1464 continue;
1169 ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, 1465 ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
1170 item->value, NULL); 1466 &item->value, NULL);
1171 if (ret < 0) { 1467 if (ret < 0) {
1172 pr_err("%s: %d\n", __func__, ret); 1468 pr_err("%s: %d\n", __func__, ret);
1173 break; 1469 break;
@@ -1176,21 +1472,14 @@ static int sony_nc_resume(struct acpi_device *device)
1176 1472
1177 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", 1473 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
1178 &handle))) { 1474 &handle))) {
1179 if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) 1475 int arg = 1;
1476 if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
1180 dprintk("ECON Method failed\n"); 1477 dprintk("ECON Method failed\n");
1181 } 1478 }
1182 1479
1183 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 1480 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1184 &handle))) { 1481 &handle)))
1185 dprintk("Doing SNC setup\n"); 1482 sony_nc_function_resume();
1186 sony_nc_function_setup(device);
1187 }
1188
1189 /* re-read rfkill state */
1190 sony_nc_rfkill_update();
1191
1192 /* restore kbd backlight states */
1193 sony_nc_kbd_backlight_resume();
1194 1483
1195 return 0; 1484 return 0;
1196} 1485}
@@ -1213,7 +1502,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked)
1213 int argument = sony_rfkill_address[(long) data] + 0x100; 1502 int argument = sony_rfkill_address[(long) data] + 0x100;
1214 1503
1215 if (!blocked) 1504 if (!blocked)
1216 argument |= 0xff0000; 1505 argument |= 0x030000;
1217 1506
1218 return sony_call_snc_handle(sony_rfkill_handle, argument, &result); 1507 return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1219} 1508}
@@ -1230,7 +1519,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
1230 enum rfkill_type type; 1519 enum rfkill_type type;
1231 const char *name; 1520 const char *name;
1232 int result; 1521 int result;
1233 bool hwblock; 1522 bool hwblock, swblock;
1234 1523
1235 switch (nc_type) { 1524 switch (nc_type) {
1236 case SONY_WIFI: 1525 case SONY_WIFI:
@@ -1258,8 +1547,21 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
1258 if (!rfk) 1547 if (!rfk)
1259 return -ENOMEM; 1548 return -ENOMEM;
1260 1549
1261 sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); 1550 if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) {
1551 rfkill_destroy(rfk);
1552 return -1;
1553 }
1262 hwblock = !(result & 0x1); 1554 hwblock = !(result & 0x1);
1555
1556 if (sony_call_snc_handle(sony_rfkill_handle,
1557 sony_rfkill_address[nc_type],
1558 &result) < 0) {
1559 rfkill_destroy(rfk);
1560 return -1;
1561 }
1562 swblock = !(result & 0x2);
1563
1564 rfkill_init_sw_state(rfk, swblock);
1263 rfkill_set_hw_state(rfk, hwblock); 1565 rfkill_set_hw_state(rfk, hwblock);
1264 1566
1265 err = rfkill_register(rfk); 1567 err = rfkill_register(rfk);
@@ -1295,101 +1597,79 @@ static void sony_nc_rfkill_update(void)
1295 1597
1296 sony_call_snc_handle(sony_rfkill_handle, argument, &result); 1598 sony_call_snc_handle(sony_rfkill_handle, argument, &result);
1297 rfkill_set_states(sony_rfkill_devices[i], 1599 rfkill_set_states(sony_rfkill_devices[i],
1298 !(result & 0xf), false); 1600 !(result & 0x2), false);
1299 } 1601 }
1300} 1602}
1301 1603
1302static void sony_nc_rfkill_setup(struct acpi_device *device) 1604static int sony_nc_rfkill_setup(struct acpi_device *device,
1605 unsigned int handle)
1303{ 1606{
1304 int offset; 1607 u64 offset;
1305 u8 dev_code, i; 1608 int i;
1306 acpi_status status; 1609 unsigned char buffer[32] = { 0 };
1307 struct acpi_object_list params;
1308 union acpi_object in_obj;
1309 union acpi_object *device_enum;
1310 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1311
1312 offset = sony_find_snc_handle(0x124);
1313 if (offset == -1) {
1314 offset = sony_find_snc_handle(0x135);
1315 if (offset == -1)
1316 return;
1317 else
1318 sony_rfkill_handle = 0x135;
1319 } else
1320 sony_rfkill_handle = 0x124;
1321 dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
1322
1323 /* need to read the whole buffer returned by the acpi call to SN06
1324 * here otherwise we may miss some features
1325 */
1326 params.count = 1;
1327 params.pointer = &in_obj;
1328 in_obj.type = ACPI_TYPE_INTEGER;
1329 in_obj.integer.value = offset;
1330 status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
1331 &buffer);
1332 if (ACPI_FAILURE(status)) {
1333 dprintk("Radio device enumeration failed\n");
1334 return;
1335 }
1336
1337 device_enum = (union acpi_object *) buffer.pointer;
1338 if (!device_enum) {
1339 pr_err("No SN06 return object\n");
1340 goto out_no_enum;
1341 }
1342 if (device_enum->type != ACPI_TYPE_BUFFER) {
1343 pr_err("Invalid SN06 return object 0x%.2x\n",
1344 device_enum->type);
1345 goto out_no_enum;
1346 }
1347 1610
1348 /* the buffer is filled with magic numbers describing the devices 1611 offset = sony_find_snc_handle(handle);
1349 * available, 0xff terminates the enumeration 1612 sony_rfkill_handle = handle;
1613
1614 i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
1615 32);
1616 if (i < 0)
1617 return i;
1618
1619 /* The buffer is filled with magic numbers describing the devices
1620 * available, 0xff terminates the enumeration.
1621 * Known codes:
1622 * 0x00 WLAN
1623 * 0x10 BLUETOOTH
1624 * 0x20 WWAN GPRS-EDGE
1625 * 0x21 WWAN HSDPA
1626 * 0x22 WWAN EV-DO
1627 * 0x23 WWAN GPS
1628 * 0x25 Gobi WWAN no GPS
1629 * 0x26 Gobi WWAN + GPS
1630 * 0x28 Gobi WWAN no GPS
1631 * 0x29 Gobi WWAN + GPS
1632 * 0x30 WIMAX
1633 * 0x50 Gobi WWAN no GPS
1634 * 0x51 Gobi WWAN + GPS
1635 * 0x70 no SIM card slot
1636 * 0x71 SIM card slot
1350 */ 1637 */
1351 for (i = 0; i < device_enum->buffer.length; i++) { 1638 for (i = 0; i < ARRAY_SIZE(buffer); i++) {
1352 1639
1353 dev_code = *(device_enum->buffer.pointer + i); 1640 if (buffer[i] == 0xff)
1354 if (dev_code == 0xff)
1355 break; 1641 break;
1356 1642
1357 dprintk("Radio devices, looking at 0x%.2x\n", dev_code); 1643 dprintk("Radio devices, found 0x%.2x\n", buffer[i]);
1358 1644
1359 if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) 1645 if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
1360 sony_nc_setup_rfkill(device, SONY_WIFI); 1646 sony_nc_setup_rfkill(device, SONY_WIFI);
1361 1647
1362 if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) 1648 if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
1363 sony_nc_setup_rfkill(device, SONY_BLUETOOTH); 1649 sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
1364 1650
1365 if ((0xf0 & dev_code) == 0x20 && 1651 if (((0xf0 & buffer[i]) == 0x20 ||
1652 (0xf0 & buffer[i]) == 0x50) &&
1366 !sony_rfkill_devices[SONY_WWAN]) 1653 !sony_rfkill_devices[SONY_WWAN])
1367 sony_nc_setup_rfkill(device, SONY_WWAN); 1654 sony_nc_setup_rfkill(device, SONY_WWAN);
1368 1655
1369 if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) 1656 if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
1370 sony_nc_setup_rfkill(device, SONY_WIMAX); 1657 sony_nc_setup_rfkill(device, SONY_WIMAX);
1371 } 1658 }
1372 1659 return 0;
1373out_no_enum:
1374 kfree(buffer.pointer);
1375 return;
1376} 1660}
1377 1661
1378/* Keyboard backlight feature */ 1662/* Keyboard backlight feature */
1379#define KBDBL_HANDLER 0x137
1380#define KBDBL_PRESENT 0xB00
1381#define SET_MODE 0xC00
1382#define SET_STATE 0xD00
1383#define SET_TIMEOUT 0xE00
1384
1385struct kbd_backlight { 1663struct kbd_backlight {
1386 int mode; 1664 unsigned int handle;
1387 int timeout; 1665 unsigned int base;
1666 unsigned int mode;
1667 unsigned int timeout;
1388 struct device_attribute mode_attr; 1668 struct device_attribute mode_attr;
1389 struct device_attribute timeout_attr; 1669 struct device_attribute timeout_attr;
1390}; 1670};
1391 1671
1392static struct kbd_backlight *kbdbl_handle; 1672static struct kbd_backlight *kbdbl_ctl;
1393 1673
1394static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) 1674static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1395{ 1675{
@@ -1398,15 +1678,15 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
1398 if (value > 1) 1678 if (value > 1)
1399 return -EINVAL; 1679 return -EINVAL;
1400 1680
1401 if (sony_call_snc_handle(KBDBL_HANDLER, 1681 if (sony_call_snc_handle(kbdbl_ctl->handle,
1402 (value << 0x10) | SET_MODE, &result)) 1682 (value << 0x10) | (kbdbl_ctl->base), &result))
1403 return -EIO; 1683 return -EIO;
1404 1684
1405 /* Try to turn the light on/off immediately */ 1685 /* Try to turn the light on/off immediately */
1406 sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE, 1686 sony_call_snc_handle(kbdbl_ctl->handle,
1407 &result); 1687 (value << 0x10) | (kbdbl_ctl->base + 0x100), &result);
1408 1688
1409 kbdbl_handle->mode = value; 1689 kbdbl_ctl->mode = value;
1410 1690
1411 return 0; 1691 return 0;
1412} 1692}
@@ -1421,7 +1701,7 @@ static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
1421 if (count > 31) 1701 if (count > 31)
1422 return -EINVAL; 1702 return -EINVAL;
1423 1703
1424 if (strict_strtoul(buffer, 10, &value)) 1704 if (kstrtoul(buffer, 10, &value))
1425 return -EINVAL; 1705 return -EINVAL;
1426 1706
1427 ret = __sony_nc_kbd_backlight_mode_set(value); 1707 ret = __sony_nc_kbd_backlight_mode_set(value);
@@ -1435,7 +1715,7 @@ static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
1435 struct device_attribute *attr, char *buffer) 1715 struct device_attribute *attr, char *buffer)
1436{ 1716{
1437 ssize_t count = 0; 1717 ssize_t count = 0;
1438 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); 1718 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode);
1439 return count; 1719 return count;
1440} 1720}
1441 1721
@@ -1446,11 +1726,11 @@ static int __sony_nc_kbd_backlight_timeout_set(u8 value)
1446 if (value > 3) 1726 if (value > 3)
1447 return -EINVAL; 1727 return -EINVAL;
1448 1728
1449 if (sony_call_snc_handle(KBDBL_HANDLER, 1729 if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) |
1450 (value << 0x10) | SET_TIMEOUT, &result)) 1730 (kbdbl_ctl->base + 0x200), &result))
1451 return -EIO; 1731 return -EIO;
1452 1732
1453 kbdbl_handle->timeout = value; 1733 kbdbl_ctl->timeout = value;
1454 1734
1455 return 0; 1735 return 0;
1456} 1736}
@@ -1465,7 +1745,7 @@ static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
1465 if (count > 31) 1745 if (count > 31)
1466 return -EINVAL; 1746 return -EINVAL;
1467 1747
1468 if (strict_strtoul(buffer, 10, &value)) 1748 if (kstrtoul(buffer, 10, &value))
1469 return -EINVAL; 1749 return -EINVAL;
1470 1750
1471 ret = __sony_nc_kbd_backlight_timeout_set(value); 1751 ret = __sony_nc_kbd_backlight_timeout_set(value);
@@ -1479,39 +1759,58 @@ static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
1479 struct device_attribute *attr, char *buffer) 1759 struct device_attribute *attr, char *buffer)
1480{ 1760{
1481 ssize_t count = 0; 1761 ssize_t count = 0;
1482 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); 1762 count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout);
1483 return count; 1763 return count;
1484} 1764}
1485 1765
1486static int sony_nc_kbd_backlight_setup(struct platform_device *pd) 1766static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
1767 unsigned int handle)
1487{ 1768{
1488 int result; 1769 int result;
1770 int ret = 0;
1489 1771
1490 if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) 1772 /* verify the kbd backlight presence, these handles are not used for
1491 return 0; 1773 * keyboard backlight only
1492 if (!(result & 0x02)) 1774 */
1775 ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100,
1776 &result);
1777 if (ret)
1778 return ret;
1779
1780 if ((handle == 0x0137 && !(result & 0x02)) ||
1781 !(result & 0x01)) {
1782 dprintk("no backlight keyboard found\n");
1493 return 0; 1783 return 0;
1784 }
1494 1785
1495 kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); 1786 kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
1496 if (!kbdbl_handle) 1787 if (!kbdbl_ctl)
1497 return -ENOMEM; 1788 return -ENOMEM;
1498 1789
1499 sysfs_attr_init(&kbdbl_handle->mode_attr.attr); 1790 kbdbl_ctl->handle = handle;
1500 kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; 1791 if (handle == 0x0137)
1501 kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; 1792 kbdbl_ctl->base = 0x0C00;
1502 kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; 1793 else
1503 kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; 1794 kbdbl_ctl->base = 0x4000;
1795
1796 sysfs_attr_init(&kbdbl_ctl->mode_attr.attr);
1797 kbdbl_ctl->mode_attr.attr.name = "kbd_backlight";
1798 kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
1799 kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
1800 kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store;
1504 1801
1505 sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); 1802 sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
1506 kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; 1803 kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
1507 kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; 1804 kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
1508 kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; 1805 kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
1509 kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; 1806 kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
1510 1807
1511 if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) 1808 ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr);
1809 if (ret)
1512 goto outkzalloc; 1810 goto outkzalloc;
1513 1811
1514 if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) 1812 ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1813 if (ret)
1515 goto outmode; 1814 goto outmode;
1516 1815
1517 __sony_nc_kbd_backlight_mode_set(kbd_backlight); 1816 __sony_nc_kbd_backlight_mode_set(kbd_backlight);
@@ -1520,57 +1819,661 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
1520 return 0; 1819 return 0;
1521 1820
1522outmode: 1821outmode:
1523 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1822 device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1524outkzalloc: 1823outkzalloc:
1525 kfree(kbdbl_handle); 1824 kfree(kbdbl_ctl);
1526 kbdbl_handle = NULL; 1825 kbdbl_ctl = NULL;
1527 return -1; 1826 return ret;
1528} 1827}
1529 1828
1530static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) 1829static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
1531{ 1830{
1532 if (kbdbl_handle) { 1831 if (kbdbl_ctl) {
1533 int result; 1832 int result;
1534 1833
1535 device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1834 device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
1536 device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); 1835 device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
1537 1836
1538 /* restore the default hw behaviour */ 1837 /* restore the default hw behaviour */
1539 sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result); 1838 sony_call_snc_handle(kbdbl_ctl->handle,
1540 sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result); 1839 kbdbl_ctl->base | 0x10000, &result);
1840 sony_call_snc_handle(kbdbl_ctl->handle,
1841 kbdbl_ctl->base + 0x200, &result);
1541 1842
1542 kfree(kbdbl_handle); 1843 kfree(kbdbl_ctl);
1844 kbdbl_ctl = NULL;
1543 } 1845 }
1544 return 0;
1545} 1846}
1546 1847
1547static void sony_nc_kbd_backlight_resume(void) 1848static void sony_nc_kbd_backlight_resume(void)
1548{ 1849{
1549 int ignore = 0; 1850 int ignore = 0;
1550 1851
1551 if (!kbdbl_handle) 1852 if (!kbdbl_ctl)
1552 return; 1853 return;
1553 1854
1554 if (kbdbl_handle->mode == 0) 1855 if (kbdbl_ctl->mode == 0)
1555 sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore); 1856 sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base,
1556
1557 if (kbdbl_handle->timeout != 0)
1558 sony_call_snc_handle(KBDBL_HANDLER,
1559 (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
1560 &ignore); 1857 &ignore);
1858
1859 if (kbdbl_ctl->timeout != 0)
1860 sony_call_snc_handle(kbdbl_ctl->handle,
1861 (kbdbl_ctl->base + 0x200) |
1862 (kbdbl_ctl->timeout << 0x10), &ignore);
1863}
1864
1865struct battery_care_control {
1866 struct device_attribute attrs[2];
1867 unsigned int handle;
1868};
1869static struct battery_care_control *bcare_ctl;
1870
1871static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
1872 struct device_attribute *attr,
1873 const char *buffer, size_t count)
1874{
1875 unsigned int result, cmd;
1876 unsigned long value;
1877
1878 if (count > 31)
1879 return -EINVAL;
1880
1881 if (kstrtoul(buffer, 10, &value))
1882 return -EINVAL;
1883
1884 /* limit values (2 bits):
1885 * 00 - none
1886 * 01 - 80%
1887 * 10 - 50%
1888 * 11 - 100%
1889 *
1890 * bit 0: 0 disable BCL, 1 enable BCL
1891 * bit 1: 1 tell to store the battery limit (see bits 6,7) too
1892 * bits 2,3: reserved
1893 * bits 4,5: store the limit into the EC
1894 * bits 6,7: store the limit into the battery
1895 */
1896
1897 /*
1898 * handle 0x0115 should allow storing on battery too;
1899 * handle 0x0136 same as 0x0115 + health status;
1900 * handle 0x013f, same as 0x0136 but no storing on the battery
1901 *
1902 * Store only inside the EC for now, regardless the handle number
1903 */
1904 if (value == 0)
1905 /* disable limits */
1906 cmd = 0x0;
1907
1908 else if (value <= 50)
1909 cmd = 0x21;
1910
1911 else if (value <= 80)
1912 cmd = 0x11;
1913
1914 else if (value <= 100)
1915 cmd = 0x31;
1916
1917 else
1918 return -EINVAL;
1919
1920 if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100,
1921 &result))
1922 return -EIO;
1923
1924 return count;
1925}
1926
1927static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
1928 struct device_attribute *attr, char *buffer)
1929{
1930 unsigned int result, status;
1931
1932 if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result))
1933 return -EIO;
1934
1935 status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0;
1936 switch (status) {
1937 case 1:
1938 status = 80;
1939 break;
1940 case 2:
1941 status = 50;
1942 break;
1943 case 3:
1944 status = 100;
1945 break;
1946 default:
1947 status = 0;
1948 break;
1949 }
1950
1951 return snprintf(buffer, PAGE_SIZE, "%d\n", status);
1952}
1953
1954static ssize_t sony_nc_battery_care_health_show(struct device *dev,
1955 struct device_attribute *attr, char *buffer)
1956{
1957 ssize_t count = 0;
1958 unsigned int health;
1959
1960 if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health))
1961 return -EIO;
1962
1963 count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
1964
1965 return count;
1966}
1967
1968static int sony_nc_battery_care_setup(struct platform_device *pd,
1969 unsigned int handle)
1970{
1971 int ret = 0;
1972
1973 bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL);
1974 if (!bcare_ctl)
1975 return -ENOMEM;
1976
1977 bcare_ctl->handle = handle;
1978
1979 sysfs_attr_init(&bcare_ctl->attrs[0].attr);
1980 bcare_ctl->attrs[0].attr.name = "battery_care_limiter";
1981 bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
1982 bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show;
1983 bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store;
1984
1985 ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]);
1986 if (ret)
1987 goto outkzalloc;
1988
1989 /* 0x0115 is for models with no health reporting capability */
1990 if (handle == 0x0115)
1991 return 0;
1992
1993 sysfs_attr_init(&bcare_ctl->attrs[1].attr);
1994 bcare_ctl->attrs[1].attr.name = "battery_care_health";
1995 bcare_ctl->attrs[1].attr.mode = S_IRUGO;
1996 bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show;
1997
1998 ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]);
1999 if (ret)
2000 goto outlimiter;
2001
2002 return 0;
2003
2004outlimiter:
2005 device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2006
2007outkzalloc:
2008 kfree(bcare_ctl);
2009 bcare_ctl = NULL;
2010
2011 return ret;
2012}
2013
2014static void sony_nc_battery_care_cleanup(struct platform_device *pd)
2015{
2016 if (bcare_ctl) {
2017 device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
2018 if (bcare_ctl->handle != 0x0115)
2019 device_remove_file(&pd->dev, &bcare_ctl->attrs[1]);
2020
2021 kfree(bcare_ctl);
2022 bcare_ctl = NULL;
2023 }
2024}
2025
2026struct snc_thermal_ctrl {
2027 unsigned int mode;
2028 unsigned int profiles;
2029 struct device_attribute mode_attr;
2030 struct device_attribute profiles_attr;
2031};
2032static struct snc_thermal_ctrl *th_handle;
2033
2034#define THM_PROFILE_MAX 3
2035static const char * const snc_thermal_profiles[] = {
2036 "balanced",
2037 "silent",
2038 "performance"
2039};
2040
2041static int sony_nc_thermal_mode_set(unsigned short mode)
2042{
2043 unsigned int result;
2044
2045 /* the thermal profile seems to be a two bit bitmask:
2046 * lsb -> silent
2047 * msb -> performance
2048 * no bit set is the normal operation and is always valid
2049 * Some vaio models only have "balanced" and "performance"
2050 */
2051 if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX)
2052 return -EINVAL;
2053
2054 if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result))
2055 return -EIO;
2056
2057 th_handle->mode = mode;
2058
2059 return 0;
2060}
2061
2062static int sony_nc_thermal_mode_get(void)
2063{
2064 unsigned int result;
2065
2066 if (sony_call_snc_handle(0x0122, 0x0100, &result))
2067 return -EIO;
2068
2069 return result & 0xff;
2070}
2071
2072static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
2073 struct device_attribute *attr, char *buffer)
2074{
2075 short cnt;
2076 size_t idx = 0;
2077
2078 for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
2079 if (!cnt || (th_handle->profiles & cnt))
2080 idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
2081 snc_thermal_profiles[cnt]);
2082 }
2083 idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n");
2084
2085 return idx;
2086}
2087
2088static ssize_t sony_nc_thermal_mode_store(struct device *dev,
2089 struct device_attribute *attr,
2090 const char *buffer, size_t count)
2091{
2092 unsigned short cmd;
2093 size_t len = count;
2094
2095 if (count == 0)
2096 return -EINVAL;
2097
2098 /* skip the newline if present */
2099 if (buffer[len - 1] == '\n')
2100 len--;
2101
2102 for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++)
2103 if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0)
2104 break;
2105
2106 if (sony_nc_thermal_mode_set(cmd))
2107 return -EIO;
2108
2109 return count;
2110}
2111
2112static ssize_t sony_nc_thermal_mode_show(struct device *dev,
2113 struct device_attribute *attr, char *buffer)
2114{
2115 ssize_t count = 0;
2116 unsigned int mode = sony_nc_thermal_mode_get();
2117
2118 if (mode < 0)
2119 return mode;
2120
2121 count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]);
2122
2123 return count;
2124}
2125
2126static int sony_nc_thermal_setup(struct platform_device *pd)
2127{
2128 int ret = 0;
2129 th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
2130 if (!th_handle)
2131 return -ENOMEM;
2132
2133 ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
2134 if (ret) {
2135 pr_warn("couldn't to read the thermal profiles\n");
2136 goto outkzalloc;
2137 }
2138
2139 ret = sony_nc_thermal_mode_get();
2140 if (ret < 0) {
2141 pr_warn("couldn't to read the current thermal profile");
2142 goto outkzalloc;
2143 }
2144 th_handle->mode = ret;
2145
2146 sysfs_attr_init(&th_handle->profiles_attr.attr);
2147 th_handle->profiles_attr.attr.name = "thermal_profiles";
2148 th_handle->profiles_attr.attr.mode = S_IRUGO;
2149 th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
2150
2151 sysfs_attr_init(&th_handle->mode_attr.attr);
2152 th_handle->mode_attr.attr.name = "thermal_control";
2153 th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
2154 th_handle->mode_attr.show = sony_nc_thermal_mode_show;
2155 th_handle->mode_attr.store = sony_nc_thermal_mode_store;
2156
2157 ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
2158 if (ret)
2159 goto outkzalloc;
2160
2161 ret = device_create_file(&pd->dev, &th_handle->mode_attr);
2162 if (ret)
2163 goto outprofiles;
2164
2165 return 0;
2166
2167outprofiles:
2168 device_remove_file(&pd->dev, &th_handle->profiles_attr);
2169outkzalloc:
2170 kfree(th_handle);
2171 th_handle = NULL;
2172 return ret;
2173}
2174
2175static void sony_nc_thermal_cleanup(struct platform_device *pd)
2176{
2177 if (th_handle) {
2178 device_remove_file(&pd->dev, &th_handle->profiles_attr);
2179 device_remove_file(&pd->dev, &th_handle->mode_attr);
2180 kfree(th_handle);
2181 th_handle = NULL;
2182 }
2183}
2184
2185static void sony_nc_thermal_resume(void)
2186{
2187 unsigned int status = sony_nc_thermal_mode_get();
2188
2189 if (status != th_handle->mode)
2190 sony_nc_thermal_mode_set(th_handle->mode);
2191}
2192
2193/* resume on LID open */
2194struct snc_lid_resume_control {
2195 struct device_attribute attrs[3];
2196 unsigned int status;
2197};
2198static struct snc_lid_resume_control *lid_ctl;
2199
2200static ssize_t sony_nc_lid_resume_store(struct device *dev,
2201 struct device_attribute *attr,
2202 const char *buffer, size_t count)
2203{
2204 unsigned int result, pos;
2205 unsigned long value;
2206 if (count > 31)
2207 return -EINVAL;
2208
2209 if (kstrtoul(buffer, 10, &value) || value > 1)
2210 return -EINVAL;
2211
2212 /* the value we have to write to SNC is a bitmask:
2213 * +--------------+
2214 * | S3 | S4 | S5 |
2215 * +--------------+
2216 * 2 1 0
2217 */
2218 if (strcmp(attr->attr.name, "lid_resume_S3") == 0)
2219 pos = 2;
2220 else if (strcmp(attr->attr.name, "lid_resume_S4") == 0)
2221 pos = 1;
2222 else if (strcmp(attr->attr.name, "lid_resume_S5") == 0)
2223 pos = 0;
2224 else
2225 return -EINVAL;
2226
2227 if (value)
2228 value = lid_ctl->status | (1 << pos);
2229 else
2230 value = lid_ctl->status & ~(1 << pos);
2231
2232 if (sony_call_snc_handle(0x0119, value << 0x10 | 0x0100, &result))
2233 return -EIO;
2234
2235 lid_ctl->status = value;
2236
2237 return count;
2238}
2239
2240static ssize_t sony_nc_lid_resume_show(struct device *dev,
2241 struct device_attribute *attr, char *buffer)
2242{
2243 unsigned int pos;
2244
2245 if (strcmp(attr->attr.name, "lid_resume_S3") == 0)
2246 pos = 2;
2247 else if (strcmp(attr->attr.name, "lid_resume_S4") == 0)
2248 pos = 1;
2249 else if (strcmp(attr->attr.name, "lid_resume_S5") == 0)
2250 pos = 0;
2251 else
2252 return -EINVAL;
2253
2254 return snprintf(buffer, PAGE_SIZE, "%d\n",
2255 (lid_ctl->status >> pos) & 0x01);
2256}
2257
2258static int sony_nc_lid_resume_setup(struct platform_device *pd)
2259{
2260 unsigned int result;
2261 int i;
2262
2263 if (sony_call_snc_handle(0x0119, 0x0000, &result))
2264 return -EIO;
2265
2266 lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL);
2267 if (!lid_ctl)
2268 return -ENOMEM;
2269
2270 lid_ctl->status = result & 0x7;
2271
2272 sysfs_attr_init(&lid_ctl->attrs[0].attr);
2273 lid_ctl->attrs[0].attr.name = "lid_resume_S3";
2274 lid_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
2275 lid_ctl->attrs[0].show = sony_nc_lid_resume_show;
2276 lid_ctl->attrs[0].store = sony_nc_lid_resume_store;
2277
2278 sysfs_attr_init(&lid_ctl->attrs[1].attr);
2279 lid_ctl->attrs[1].attr.name = "lid_resume_S4";
2280 lid_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR;
2281 lid_ctl->attrs[1].show = sony_nc_lid_resume_show;
2282 lid_ctl->attrs[1].store = sony_nc_lid_resume_store;
2283
2284 sysfs_attr_init(&lid_ctl->attrs[2].attr);
2285 lid_ctl->attrs[2].attr.name = "lid_resume_S5";
2286 lid_ctl->attrs[2].attr.mode = S_IRUGO | S_IWUSR;
2287 lid_ctl->attrs[2].show = sony_nc_lid_resume_show;
2288 lid_ctl->attrs[2].store = sony_nc_lid_resume_store;
2289
2290 for (i = 0; i < 3; i++) {
2291 result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
2292 if (result)
2293 goto liderror;
2294 }
2295
2296 return 0;
2297
2298liderror:
2299 for (; i > 0; i--)
2300 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2301
2302 kfree(lid_ctl);
2303 lid_ctl = NULL;
2304
2305 return result;
2306}
2307
2308static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
2309{
2310 int i;
2311
2312 if (lid_ctl) {
2313 for (i = 0; i < 3; i++)
2314 device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
2315
2316 kfree(lid_ctl);
2317 lid_ctl = NULL;
2318 }
2319}
2320
2321/* High speed charging function */
2322static struct device_attribute *hsc_handle;
2323
2324static ssize_t sony_nc_highspeed_charging_store(struct device *dev,
2325 struct device_attribute *attr,
2326 const char *buffer, size_t count)
2327{
2328 unsigned int result;
2329 unsigned long value;
2330
2331 if (count > 31)
2332 return -EINVAL;
2333
2334 if (kstrtoul(buffer, 10, &value) || value > 1)
2335 return -EINVAL;
2336
2337 if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
2338 return -EIO;
2339
2340 return count;
2341}
2342
2343static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
2344 struct device_attribute *attr, char *buffer)
2345{
2346 unsigned int result;
2347
2348 if (sony_call_snc_handle(0x0131, 0x0100, &result))
2349 return -EIO;
2350
2351 return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2352}
2353
2354static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
2355{
2356 unsigned int result;
2357
2358 if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
2359 /* some models advertise the handle but have no implementation
2360 * for it
2361 */
2362 pr_info("No High Speed Charging capability found\n");
2363 return 0;
2364 }
2365
2366 hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2367 if (!hsc_handle)
2368 return -ENOMEM;
2369
2370 sysfs_attr_init(&hsc_handle->attr);
2371 hsc_handle->attr.name = "battery_highspeed_charging";
2372 hsc_handle->attr.mode = S_IRUGO | S_IWUSR;
2373 hsc_handle->show = sony_nc_highspeed_charging_show;
2374 hsc_handle->store = sony_nc_highspeed_charging_store;
2375
2376 result = device_create_file(&pd->dev, hsc_handle);
2377 if (result) {
2378 kfree(hsc_handle);
2379 hsc_handle = NULL;
2380 return result;
2381 }
2382
2383 return 0;
2384}
2385
2386static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
2387{
2388 if (hsc_handle) {
2389 device_remove_file(&pd->dev, hsc_handle);
2390 kfree(hsc_handle);
2391 hsc_handle = NULL;
2392 }
2393}
2394
2395/* Touchpad enable/disable */
2396struct touchpad_control {
2397 struct device_attribute attr;
2398 int handle;
2399};
2400static struct touchpad_control *tp_ctl;
2401
2402static ssize_t sony_nc_touchpad_store(struct device *dev,
2403 struct device_attribute *attr, const char *buffer, size_t count)
2404{
2405 unsigned int result;
2406 unsigned long value;
2407
2408 if (count > 31)
2409 return -EINVAL;
2410
2411 if (kstrtoul(buffer, 10, &value) || value > 1)
2412 return -EINVAL;
2413
2414 /* sysfs: 0 disabled, 1 enabled
2415 * EC: 0 enabled, 1 disabled
2416 */
2417 if (sony_call_snc_handle(tp_ctl->handle,
2418 (!value << 0x10) | 0x100, &result))
2419 return -EIO;
2420
2421 return count;
2422}
2423
2424static ssize_t sony_nc_touchpad_show(struct device *dev,
2425 struct device_attribute *attr, char *buffer)
2426{
2427 unsigned int result;
2428
2429 if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result))
2430 return -EINVAL;
2431
2432 return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
2433}
2434
2435static int sony_nc_touchpad_setup(struct platform_device *pd,
2436 unsigned int handle)
2437{
2438 int ret = 0;
2439
2440 tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL);
2441 if (!tp_ctl)
2442 return -ENOMEM;
2443
2444 tp_ctl->handle = handle;
2445
2446 sysfs_attr_init(&tp_ctl->attr.attr);
2447 tp_ctl->attr.attr.name = "touchpad";
2448 tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR;
2449 tp_ctl->attr.show = sony_nc_touchpad_show;
2450 tp_ctl->attr.store = sony_nc_touchpad_store;
2451
2452 ret = device_create_file(&pd->dev, &tp_ctl->attr);
2453 if (ret) {
2454 kfree(tp_ctl);
2455 tp_ctl = NULL;
2456 }
2457
2458 return ret;
2459}
2460
2461static void sony_nc_touchpad_cleanup(struct platform_device *pd)
2462{
2463 if (tp_ctl) {
2464 device_remove_file(&pd->dev, &tp_ctl->attr);
2465 kfree(tp_ctl);
2466 tp_ctl = NULL;
2467 }
1561} 2468}
1562 2469
1563static void sony_nc_backlight_ng_read_limits(int handle, 2470static void sony_nc_backlight_ng_read_limits(int handle,
1564 struct sony_backlight_props *props) 2471 struct sony_backlight_props *props)
1565{ 2472{
1566 int offset; 2473 u64 offset;
1567 acpi_status status; 2474 int i;
1568 u8 brlvl, i;
1569 u8 min = 0xff, max = 0x00; 2475 u8 min = 0xff, max = 0x00;
1570 struct acpi_object_list params; 2476 unsigned char buffer[32] = { 0 };
1571 union acpi_object in_obj;
1572 union acpi_object *lvl_enum;
1573 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
1574 2477
1575 props->handle = handle; 2478 props->handle = handle;
1576 props->offset = 0; 2479 props->offset = 0;
@@ -1583,50 +2486,31 @@ static void sony_nc_backlight_ng_read_limits(int handle,
1583 /* try to read the boundaries from ACPI tables, if we fail the above 2486 /* try to read the boundaries from ACPI tables, if we fail the above
1584 * defaults should be reasonable 2487 * defaults should be reasonable
1585 */ 2488 */
1586 params.count = 1; 2489 i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
1587 params.pointer = &in_obj; 2490 32);
1588 in_obj.type = ACPI_TYPE_INTEGER; 2491 if (i < 0)
1589 in_obj.integer.value = offset;
1590 status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
1591 &buffer);
1592 if (ACPI_FAILURE(status))
1593 return; 2492 return;
1594 2493
1595 lvl_enum = (union acpi_object *) buffer.pointer;
1596 if (!lvl_enum) {
1597 pr_err("No SN06 return object.");
1598 return;
1599 }
1600 if (lvl_enum->type != ACPI_TYPE_BUFFER) {
1601 pr_err("Invalid SN06 return object 0x%.2x\n",
1602 lvl_enum->type);
1603 goto out_invalid;
1604 }
1605
1606 /* the buffer lists brightness levels available, brightness levels are 2494 /* the buffer lists brightness levels available, brightness levels are
1607 * from 0 to 8 in the array, other values are used by ALS control. 2495 * from position 0 to 8 in the array, other values are used by ALS
2496 * control.
1608 */ 2497 */
1609 for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { 2498 for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) {
1610 2499
1611 brlvl = *(lvl_enum->buffer.pointer + i); 2500 dprintk("Brightness level: %d\n", buffer[i]);
1612 dprintk("Brightness level: %d\n", brlvl);
1613 2501
1614 if (!brlvl) 2502 if (!buffer[i])
1615 break; 2503 break;
1616 2504
1617 if (brlvl > max) 2505 if (buffer[i] > max)
1618 max = brlvl; 2506 max = buffer[i];
1619 if (brlvl < min) 2507 if (buffer[i] < min)
1620 min = brlvl; 2508 min = buffer[i];
1621 } 2509 }
1622 props->offset = min; 2510 props->offset = min;
1623 props->maxlvl = max; 2511 props->maxlvl = max;
1624 dprintk("Brightness levels: min=%d max=%d\n", props->offset, 2512 dprintk("Brightness levels: min=%d max=%d\n", props->offset,
1625 props->maxlvl); 2513 props->maxlvl);
1626
1627out_invalid:
1628 kfree(buffer.pointer);
1629 return;
1630} 2514}
1631 2515
1632static void sony_nc_backlight_setup(void) 2516static void sony_nc_backlight_setup(void)
@@ -1715,28 +2599,25 @@ static int sony_nc_add(struct acpi_device *device)
1715 2599
1716 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", 2600 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
1717 &handle))) { 2601 &handle))) {
1718 if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) 2602 int arg = 1;
2603 if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
1719 dprintk("ECON Method failed\n"); 2604 dprintk("ECON Method failed\n");
1720 } 2605 }
1721 2606
1722 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 2607 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
1723 &handle))) { 2608 &handle))) {
1724 dprintk("Doing SNC setup\n"); 2609 dprintk("Doing SNC setup\n");
2610 /* retrieve the available handles */
1725 result = sony_nc_handles_setup(sony_pf_device); 2611 result = sony_nc_handles_setup(sony_pf_device);
1726 if (result) 2612 if (!result)
1727 goto outpresent; 2613 sony_nc_function_setup(device, sony_pf_device);
1728 result = sony_nc_kbd_backlight_setup(sony_pf_device);
1729 if (result)
1730 goto outsnc;
1731 sony_nc_function_setup(device);
1732 sony_nc_rfkill_setup(device);
1733 } 2614 }
1734 2615
1735 /* setup input devices and helper fifo */ 2616 /* setup input devices and helper fifo */
1736 result = sony_laptop_setup_input(device); 2617 result = sony_laptop_setup_input(device);
1737 if (result) { 2618 if (result) {
1738 pr_err("Unable to create input devices\n"); 2619 pr_err("Unable to create input devices\n");
1739 goto outkbdbacklight; 2620 goto outsnc;
1740 } 2621 }
1741 2622
1742 if (acpi_video_backlight_support()) { 2623 if (acpi_video_backlight_support()) {
@@ -1794,10 +2675,8 @@ static int sony_nc_add(struct acpi_device *device)
1794 2675
1795 sony_laptop_remove_input(); 2676 sony_laptop_remove_input();
1796 2677
1797 outkbdbacklight:
1798 sony_nc_kbd_backlight_cleanup(sony_pf_device);
1799
1800 outsnc: 2678 outsnc:
2679 sony_nc_function_cleanup(sony_pf_device);
1801 sony_nc_handles_cleanup(sony_pf_device); 2680 sony_nc_handles_cleanup(sony_pf_device);
1802 2681
1803 outpresent: 2682 outpresent:
@@ -1820,11 +2699,10 @@ static int sony_nc_remove(struct acpi_device *device, int type)
1820 device_remove_file(&sony_pf_device->dev, &item->devattr); 2699 device_remove_file(&sony_pf_device->dev, &item->devattr);
1821 } 2700 }
1822 2701
1823 sony_nc_kbd_backlight_cleanup(sony_pf_device); 2702 sony_nc_function_cleanup(sony_pf_device);
1824 sony_nc_handles_cleanup(sony_pf_device); 2703 sony_nc_handles_cleanup(sony_pf_device);
1825 sony_pf_remove(); 2704 sony_pf_remove();
1826 sony_laptop_remove_input(); 2705 sony_laptop_remove_input();
1827 sony_nc_rfkill_cleanup();
1828 dprintk(SONY_NC_DRIVER_NAME " removed.\n"); 2706 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
1829 2707
1830 return 0; 2708 return 0;
@@ -2437,7 +3315,9 @@ static ssize_t sony_pic_wwanpower_store(struct device *dev,
2437 if (count > 31) 3315 if (count > 31)
2438 return -EINVAL; 3316 return -EINVAL;
2439 3317
2440 value = simple_strtoul(buffer, NULL, 10); 3318 if (kstrtoul(buffer, 10, &value))
3319 return -EINVAL;
3320
2441 mutex_lock(&spic_dev.lock); 3321 mutex_lock(&spic_dev.lock);
2442 __sony_pic_set_wwanpower(value); 3322 __sony_pic_set_wwanpower(value);
2443 mutex_unlock(&spic_dev.lock); 3323 mutex_unlock(&spic_dev.lock);
@@ -2474,7 +3354,9 @@ static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
2474 if (count > 31) 3354 if (count > 31)
2475 return -EINVAL; 3355 return -EINVAL;
2476 3356
2477 value = simple_strtoul(buffer, NULL, 10); 3357 if (kstrtoul(buffer, 10, &value))
3358 return -EINVAL;
3359
2478 mutex_lock(&spic_dev.lock); 3360 mutex_lock(&spic_dev.lock);
2479 __sony_pic_set_bluetoothpower(value); 3361 __sony_pic_set_bluetoothpower(value);
2480 mutex_unlock(&spic_dev.lock); 3362 mutex_unlock(&spic_dev.lock);
@@ -2513,7 +3395,9 @@ static ssize_t sony_pic_fanspeed_store(struct device *dev,
2513 if (count > 31) 3395 if (count > 31)
2514 return -EINVAL; 3396 return -EINVAL;
2515 3397
2516 value = simple_strtoul(buffer, NULL, 10); 3398 if (kstrtoul(buffer, 10, &value))
3399 return -EINVAL;
3400
2517 if (sony_pic_set_fanspeed(value)) 3401 if (sony_pic_set_fanspeed(value))
2518 return -EIO; 3402 return -EIO;
2519 3403
@@ -2671,7 +3555,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
2671 ret = -EIO; 3555 ret = -EIO;
2672 break; 3556 break;
2673 } 3557 }
2674 if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { 3558 if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
3559 &value)) {
2675 ret = -EIO; 3560 ret = -EIO;
2676 break; 3561 break;
2677 } 3562 }
@@ -2688,8 +3573,9 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
2688 ret = -EFAULT; 3573 ret = -EFAULT;
2689 break; 3574 break;
2690 } 3575 }
2691 if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", 3576 value = (val8 >> 5) + 1;
2692 (val8 >> 5) + 1, NULL)) { 3577 if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
3578 NULL)) {
2693 ret = -EIO; 3579 ret = -EIO;
2694 break; 3580 break;
2695 } 3581 }
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index d68c0002f4a2..8b5610d88418 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -3402,7 +3402,7 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
3402 /* Do not issue duplicate brightness change events to 3402 /* Do not issue duplicate brightness change events to
3403 * userspace. tpacpi_detect_brightness_capabilities() must have 3403 * userspace. tpacpi_detect_brightness_capabilities() must have
3404 * been called before this point */ 3404 * been called before this point */
3405 if (tp_features.bright_acpimode && acpi_video_backlight_support()) { 3405 if (acpi_video_backlight_support()) {
3406 pr_info("This ThinkPad has standard ACPI backlight " 3406 pr_info("This ThinkPad has standard ACPI backlight "
3407 "brightness control, supported by the ACPI " 3407 "brightness control, supported by the ACPI "
3408 "video driver\n"); 3408 "video driver\n");
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index 57787d87d9a4..dab10f6edcd4 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -95,6 +95,7 @@ MODULE_LICENSE("GPL");
95 95
96/* registers */ 96/* registers */
97#define HCI_FAN 0x0004 97#define HCI_FAN 0x0004
98#define HCI_TR_BACKLIGHT 0x0005
98#define HCI_SYSTEM_EVENT 0x0016 99#define HCI_SYSTEM_EVENT 0x0016
99#define HCI_VIDEO_OUT 0x001c 100#define HCI_VIDEO_OUT 0x001c
100#define HCI_HOTKEY_EVENT 0x001e 101#define HCI_HOTKEY_EVENT 0x001e
@@ -134,6 +135,7 @@ struct toshiba_acpi_dev {
134 unsigned int system_event_supported:1; 135 unsigned int system_event_supported:1;
135 unsigned int ntfy_supported:1; 136 unsigned int ntfy_supported:1;
136 unsigned int info_supported:1; 137 unsigned int info_supported:1;
138 unsigned int tr_backlight_supported:1;
137 139
138 struct mutex mutex; 140 struct mutex mutex;
139}; 141};
@@ -478,34 +480,70 @@ static const struct rfkill_ops toshiba_rfk_ops = {
478 .poll = bt_rfkill_poll, 480 .poll = bt_rfkill_poll,
479}; 481};
480 482
483static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled)
484{
485 u32 hci_result;
486 u32 status;
487
488 hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result);
489 *enabled = !status;
490 return hci_result == HCI_SUCCESS ? 0 : -EIO;
491}
492
493static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
494{
495 u32 hci_result;
496 u32 value = !enable;
497
498 hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result);
499 return hci_result == HCI_SUCCESS ? 0 : -EIO;
500}
501
481static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; 502static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
482 503
483static int get_lcd(struct backlight_device *bd) 504static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
484{ 505{
485 struct toshiba_acpi_dev *dev = bl_get_data(bd);
486 u32 hci_result; 506 u32 hci_result;
487 u32 value; 507 u32 value;
508 int brightness = 0;
509
510 if (dev->tr_backlight_supported) {
511 bool enabled;
512 int ret = get_tr_backlight_status(dev, &enabled);
513 if (ret)
514 return ret;
515 if (enabled)
516 return 0;
517 brightness++;
518 }
488 519
489 hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); 520 hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result);
490 if (hci_result == HCI_SUCCESS) 521 if (hci_result == HCI_SUCCESS)
491 return (value >> HCI_LCD_BRIGHTNESS_SHIFT); 522 return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT);
492 523
493 return -EIO; 524 return -EIO;
494} 525}
495 526
527static int get_lcd_brightness(struct backlight_device *bd)
528{
529 struct toshiba_acpi_dev *dev = bl_get_data(bd);
530 return __get_lcd_brightness(dev);
531}
532
496static int lcd_proc_show(struct seq_file *m, void *v) 533static int lcd_proc_show(struct seq_file *m, void *v)
497{ 534{
498 struct toshiba_acpi_dev *dev = m->private; 535 struct toshiba_acpi_dev *dev = m->private;
499 int value; 536 int value;
537 int levels;
500 538
501 if (!dev->backlight_dev) 539 if (!dev->backlight_dev)
502 return -ENODEV; 540 return -ENODEV;
503 541
504 value = get_lcd(dev->backlight_dev); 542 levels = dev->backlight_dev->props.max_brightness + 1;
543 value = get_lcd_brightness(dev->backlight_dev);
505 if (value >= 0) { 544 if (value >= 0) {
506 seq_printf(m, "brightness: %d\n", value); 545 seq_printf(m, "brightness: %d\n", value);
507 seq_printf(m, "brightness_levels: %d\n", 546 seq_printf(m, "brightness_levels: %d\n", levels);
508 HCI_LCD_BRIGHTNESS_LEVELS);
509 return 0; 547 return 0;
510 } 548 }
511 549
@@ -518,10 +556,19 @@ static int lcd_proc_open(struct inode *inode, struct file *file)
518 return single_open(file, lcd_proc_show, PDE(inode)->data); 556 return single_open(file, lcd_proc_show, PDE(inode)->data);
519} 557}
520 558
521static int set_lcd(struct toshiba_acpi_dev *dev, int value) 559static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
522{ 560{
523 u32 hci_result; 561 u32 hci_result;
524 562
563 if (dev->tr_backlight_supported) {
564 bool enable = !value;
565 int ret = set_tr_backlight_status(dev, enable);
566 if (ret)
567 return ret;
568 if (value)
569 value--;
570 }
571
525 value = value << HCI_LCD_BRIGHTNESS_SHIFT; 572 value = value << HCI_LCD_BRIGHTNESS_SHIFT;
526 hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); 573 hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result);
527 return hci_result == HCI_SUCCESS ? 0 : -EIO; 574 return hci_result == HCI_SUCCESS ? 0 : -EIO;
@@ -530,7 +577,7 @@ static int set_lcd(struct toshiba_acpi_dev *dev, int value)
530static int set_lcd_status(struct backlight_device *bd) 577static int set_lcd_status(struct backlight_device *bd)
531{ 578{
532 struct toshiba_acpi_dev *dev = bl_get_data(bd); 579 struct toshiba_acpi_dev *dev = bl_get_data(bd);
533 return set_lcd(dev, bd->props.brightness); 580 return set_lcd_brightness(dev, bd->props.brightness);
534} 581}
535 582
536static ssize_t lcd_proc_write(struct file *file, const char __user *buf, 583static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
@@ -541,6 +588,7 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
541 size_t len; 588 size_t len;
542 int value; 589 int value;
543 int ret; 590 int ret;
591 int levels = dev->backlight_dev->props.max_brightness + 1;
544 592
545 len = min(count, sizeof(cmd) - 1); 593 len = min(count, sizeof(cmd) - 1);
546 if (copy_from_user(cmd, buf, len)) 594 if (copy_from_user(cmd, buf, len))
@@ -548,8 +596,8 @@ static ssize_t lcd_proc_write(struct file *file, const char __user *buf,
548 cmd[len] = '\0'; 596 cmd[len] = '\0';
549 597
550 if (sscanf(cmd, " brightness : %i", &value) == 1 && 598 if (sscanf(cmd, " brightness : %i", &value) == 1 &&
551 value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { 599 value >= 0 && value < levels) {
552 ret = set_lcd(dev, value); 600 ret = set_lcd_brightness(dev, value);
553 if (ret == 0) 601 if (ret == 0)
554 ret = count; 602 ret = count;
555 } else { 603 } else {
@@ -860,8 +908,9 @@ static void remove_toshiba_proc_entries(struct toshiba_acpi_dev *dev)
860} 908}
861 909
862static const struct backlight_ops toshiba_backlight_data = { 910static const struct backlight_ops toshiba_backlight_data = {
863 .get_brightness = get_lcd, 911 .options = BL_CORE_SUSPENDRESUME,
864 .update_status = set_lcd_status, 912 .get_brightness = get_lcd_brightness,
913 .update_status = set_lcd_status,
865}; 914};
866 915
867static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, 916static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str,
@@ -1020,6 +1069,56 @@ static int __devinit toshiba_acpi_setup_keyboard(struct toshiba_acpi_dev *dev)
1020 return error; 1069 return error;
1021} 1070}
1022 1071
1072static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
1073{
1074 struct backlight_properties props;
1075 int brightness;
1076 int ret;
1077 bool enabled;
1078
1079 /*
1080 * Some machines don't support the backlight methods at all, and
1081 * others support it read-only. Either of these is pretty useless,
1082 * so only register the backlight device if the backlight method
1083 * supports both reads and writes.
1084 */
1085 brightness = __get_lcd_brightness(dev);
1086 if (brightness < 0)
1087 return 0;
1088 ret = set_lcd_brightness(dev, brightness);
1089 if (ret) {
1090 pr_debug("Backlight method is read-only, disabling backlight support\n");
1091 return 0;
1092 }
1093
1094 /* Determine whether or not BIOS supports transflective backlight */
1095 ret = get_tr_backlight_status(dev, &enabled);
1096 dev->tr_backlight_supported = !ret;
1097
1098 memset(&props, 0, sizeof(props));
1099 props.type = BACKLIGHT_PLATFORM;
1100 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
1101
1102 /* adding an extra level and having 0 change to transflective mode */
1103 if (dev->tr_backlight_supported)
1104 props.max_brightness++;
1105
1106 dev->backlight_dev = backlight_device_register("toshiba",
1107 &dev->acpi_dev->dev,
1108 dev,
1109 &toshiba_backlight_data,
1110 &props);
1111 if (IS_ERR(dev->backlight_dev)) {
1112 ret = PTR_ERR(dev->backlight_dev);
1113 pr_err("Could not register toshiba backlight device\n");
1114 dev->backlight_dev = NULL;
1115 return ret;
1116 }
1117
1118 dev->backlight_dev->props.brightness = brightness;
1119 return 0;
1120}
1121
1023static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type) 1122static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type)
1024{ 1123{
1025 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); 1124 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev);
@@ -1078,7 +1177,6 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
1078 u32 dummy; 1177 u32 dummy;
1079 bool bt_present; 1178 bool bt_present;
1080 int ret = 0; 1179 int ret = 0;
1081 struct backlight_properties props;
1082 1180
1083 if (toshiba_acpi) 1181 if (toshiba_acpi)
1084 return -EBUSY; 1182 return -EBUSY;
@@ -1104,22 +1202,9 @@ static int __devinit toshiba_acpi_add(struct acpi_device *acpi_dev)
1104 1202
1105 mutex_init(&dev->mutex); 1203 mutex_init(&dev->mutex);
1106 1204
1107 memset(&props, 0, sizeof(props)); 1205 ret = toshiba_acpi_setup_backlight(dev);
1108 props.type = BACKLIGHT_PLATFORM; 1206 if (ret)
1109 props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
1110 dev->backlight_dev = backlight_device_register("toshiba",
1111 &acpi_dev->dev,
1112 dev,
1113 &toshiba_backlight_data,
1114 &props);
1115 if (IS_ERR(dev->backlight_dev)) {
1116 ret = PTR_ERR(dev->backlight_dev);
1117
1118 pr_err("Could not register toshiba backlight device\n");
1119 dev->backlight_dev = NULL;
1120 goto error; 1207 goto error;
1121 }
1122 dev->backlight_dev->props.brightness = get_lcd(dev->backlight_dev);
1123 1208
1124 /* Register rfkill switch for Bluetooth */ 1209 /* Register rfkill switch for Bluetooth */
1125 if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) { 1210 if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) {
diff --git a/drivers/platform/x86/xo1-rfkill.c b/drivers/platform/x86/xo1-rfkill.c
index 41781ed8301c..b57ad8641480 100644
--- a/drivers/platform/x86/xo1-rfkill.c
+++ b/drivers/platform/x86/xo1-rfkill.c
@@ -15,15 +15,26 @@
15 15
16#include <asm/olpc.h> 16#include <asm/olpc.h>
17 17
18static bool card_blocked;
19
18static int rfkill_set_block(void *data, bool blocked) 20static int rfkill_set_block(void *data, bool blocked)
19{ 21{
20 unsigned char cmd; 22 unsigned char cmd;
23 int r;
24
25 if (blocked == card_blocked)
26 return 0;
27
21 if (blocked) 28 if (blocked)
22 cmd = EC_WLAN_ENTER_RESET; 29 cmd = EC_WLAN_ENTER_RESET;
23 else 30 else
24 cmd = EC_WLAN_LEAVE_RESET; 31 cmd = EC_WLAN_LEAVE_RESET;
25 32
26 return olpc_ec_cmd(cmd, NULL, 0, NULL, 0); 33 r = olpc_ec_cmd(cmd, NULL, 0, NULL, 0);
34 if (r == 0)
35 card_blocked = blocked;
36
37 return r;
27} 38}
28 39
29static const struct rfkill_ops rfkill_ops = { 40static const struct rfkill_ops rfkill_ops = {