diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 19:51:37 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-06-01 19:51:37 -0400 |
| commit | 48445159e9ecb44a96a4de06c6ae7c54eb43ba5b (patch) | |
| tree | 992657156c63746d6d43c3b6f7386227a0df34a4 | |
| parent | af4f8ba31a4e328677bec493ceeaf112ca193b65 (diff) | |
| parent | a2f01a899347fd97cb18094e5a55640cab552818 (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.c | 24 | ||||
| -rw-r--r-- | drivers/platform/x86/apple-gmux.c | 4 | ||||
| -rw-r--r-- | drivers/platform/x86/dell-laptop.c | 308 | ||||
| -rw-r--r-- | drivers/platform/x86/fujitsu-tablet.c | 34 | ||||
| -rw-r--r-- | drivers/platform/x86/hdaps.c | 2 | ||||
| -rw-r--r-- | drivers/platform/x86/hp-wmi.c | 10 | ||||
| -rw-r--r-- | drivers/platform/x86/ideapad-laptop.c | 9 | ||||
| -rw-r--r-- | drivers/platform/x86/sony-laptop.c | 1498 | ||||
| -rw-r--r-- | drivers/platform/x86/thinkpad_acpi.c | 2 | ||||
| -rw-r--r-- | drivers/platform/x86/toshiba_acpi.c | 141 | ||||
| -rw-r--r-- | drivers/platform/x86/xo1-rfkill.c | 13 |
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 | ||
| 104 | static const struct backlight_ops gmux_bl_ops = { | 107 | static 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 | ||
| 91 | static struct platform_device *platform_device; | 90 | static struct platform_device *platform_device; |
| 92 | static struct backlight_device *dell_backlight_device; | 91 | static struct backlight_device *dell_backlight_device; |
| 93 | static struct rfkill *wifi_rfkill; | ||
| 94 | static struct rfkill *bluetooth_rfkill; | ||
| 95 | static struct rfkill *wwan_rfkill; | ||
| 96 | 92 | ||
| 97 | static const struct dmi_system_id __initdata dell_device_table[] = { | 93 | static 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 | }; |
| 120 | MODULE_DEVICE_TABLE(dmi, dell_device_table); | 116 | MODULE_DEVICE_TABLE(dmi, dell_device_table); |
| 121 | 117 | ||
| 122 | static struct dmi_system_id __devinitdata dell_blacklist[] = { | 118 | static 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 | |||
| 169 | static 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 | |||
| 348 | static 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 | |||
| 369 | out: | ||
| 370 | release_buffer(); | ||
| 371 | return ret; | ||
| 372 | } | ||
| 373 | |||
| 374 | static 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 | |||
| 391 | static const struct rfkill_ops dell_rfkill_ops = { | ||
| 392 | .set_block = dell_rfkill_set, | ||
| 393 | .query = dell_rfkill_query, | ||
| 394 | }; | ||
| 395 | |||
| 396 | static struct dentry *dell_laptop_dir; | 302 | static struct dentry *dell_laptop_dir; |
| 397 | 303 | ||
| 398 | static int dell_debugfs_show(struct seq_file *s, void *data) | 304 | static 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 | ||
| 465 | static 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 | } | ||
| 474 | static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); | ||
| 475 | |||
| 476 | |||
| 477 | static 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; | ||
| 537 | err_wwan: | ||
| 538 | rfkill_destroy(wwan_rfkill); | ||
| 539 | if (bluetooth_rfkill) | ||
| 540 | rfkill_unregister(bluetooth_rfkill); | ||
| 541 | err_bluetooth: | ||
| 542 | rfkill_destroy(bluetooth_rfkill); | ||
| 543 | if (wifi_rfkill) | ||
| 544 | rfkill_unregister(wifi_rfkill); | ||
| 545 | err_wifi: | ||
| 546 | rfkill_destroy(wifi_rfkill); | ||
| 547 | |||
| 548 | return ret; | ||
| 549 | } | ||
| 550 | |||
| 551 | static 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 | |||
| 567 | static int dell_send_intensity(struct backlight_device *bd) | 371 | static 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 | ||
| 658 | static 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 | |||
| 682 | static int __init dell_init(void) | 462 | static 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 | ||
| 784 | fail_backlight: | 548 | fail_backlight: |
| 785 | i8042_remove_filter(dell_laptop_i8042_filter); | ||
| 786 | cancel_delayed_work_sync(&dell_rfkill_work); | ||
| 787 | fail_filter: | ||
| 788 | dell_cleanup_rfkill(); | ||
| 789 | fail_rfkill: | ||
| 790 | free_page((unsigned long)bufferpage); | 549 | free_page((unsigned long)bufferpage); |
| 791 | fail_buffer: | 550 | fail_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 | ||
| 278 | static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi) | 280 | static 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 | |||
| 287 | static 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 | ||
| 286 | static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) | 294 | static 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 | ||
| 294 | static struct dmi_system_id dmi_ids[] __initconst = { | 302 | static 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); | |||
| 473 | MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>"); | 481 | MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>"); |
| 474 | MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); | 482 | MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); |
| 475 | MODULE_LICENSE("GPL"); | 483 | MODULE_LICENSE("GPL"); |
| 476 | MODULE_VERSION("2.4"); | 484 | MODULE_VERSION("2.5"); |
| 477 | 485 | ||
| 478 | MODULE_DEVICE_TABLE(acpi, fujitsu_ids); | 486 | MODULE_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) | ||
| 198 | static int debugfs_status_show(struct seq_file *s, void *data) | 197 | static 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 | ||
| 143 | static void sony_nc_kbd_backlight_resume(void); | 143 | static void sony_nc_kbd_backlight_resume(void); |
| 144 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd, | ||
| 145 | unsigned int handle); | ||
| 146 | static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd); | ||
| 147 | |||
| 148 | static int sony_nc_battery_care_setup(struct platform_device *pd, | ||
| 149 | unsigned int handle); | ||
| 150 | static void sony_nc_battery_care_cleanup(struct platform_device *pd); | ||
| 151 | |||
| 152 | static int sony_nc_thermal_setup(struct platform_device *pd); | ||
| 153 | static void sony_nc_thermal_cleanup(struct platform_device *pd); | ||
| 154 | static void sony_nc_thermal_resume(void); | ||
| 155 | |||
| 156 | static int sony_nc_lid_resume_setup(struct platform_device *pd); | ||
| 157 | static void sony_nc_lid_resume_cleanup(struct platform_device *pd); | ||
| 158 | |||
| 159 | static int sony_nc_highspeed_charging_setup(struct platform_device *pd); | ||
| 160 | static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd); | ||
| 161 | |||
| 162 | static int sony_nc_touchpad_setup(struct platform_device *pd, | ||
| 163 | unsigned int handle); | ||
| 164 | static void sony_nc_touchpad_cleanup(struct platform_device *pd); | ||
| 144 | 165 | ||
| 145 | enum sony_nc_rfkill { | 166 | enum sony_nc_rfkill { |
| 146 | SONY_WIFI, | 167 | SONY_WIFI, |
| @@ -153,6 +174,9 @@ enum sony_nc_rfkill { | |||
| 153 | static int sony_rfkill_handle; | 174 | static int sony_rfkill_handle; |
| 154 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; | 175 | static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; |
| 155 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; | 176 | static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; |
| 177 | static int sony_nc_rfkill_setup(struct acpi_device *device, | ||
| 178 | unsigned int handle); | ||
| 179 | static void sony_nc_rfkill_cleanup(void); | ||
| 156 | static void sony_nc_rfkill_update(void); | 180 | static 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 | */ |
| 695 | static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) | 721 | static 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 = ∈ | ||
| 735 | status = acpi_evaluate_object(handle, method, ¶ms, &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 | ||
| 715 | static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | 756 | static 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, ¶ms, &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) | ||
| 784 | static 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 | ||
| 749 | struct sony_nc_handles { | 811 | struct sony_nc_handles { |
| @@ -770,16 +832,17 @@ static ssize_t sony_nc_handles_show(struct device *dev, | |||
| 770 | 832 | ||
| 771 | static int sony_nc_handles_setup(struct platform_device *pd) | 833 | static 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 | ||
| 836 | static int sony_call_snc_handle(int handle, int argument, int *result) | 899 | static 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) | |||
| 889 | static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, | 951 | static 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 | ||
| 949 | static int sony_backlight_update_status(struct backlight_device *bd) | 1018 | static 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 | ||
| 955 | static int sony_backlight_get_brightness(struct backlight_device *bd) | 1024 | static 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 | ||
| 1139 | static 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 | */ |
| 1069 | static void sony_nc_notify(struct acpi_device *device, u32 event) | 1175 | static 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 | ||
| 1125 | static acpi_status sony_walk_callback(acpi_handle handle, u32 level, | 1251 | static 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 | */ |
| 1143 | static int sony_nc_function_setup(struct acpi_device *device) | 1269 | static 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 | |||
| 1357 | static 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 | |||
| 1409 | static 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 | ||
| 1159 | static int sony_nc_resume(struct acpi_device *device) | 1455 | static 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 | ||
| 1302 | static void sony_nc_rfkill_setup(struct acpi_device *device) | 1604 | static 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", ¶ms, | ||
| 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; | |
| 1373 | out_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 | |||
| 1385 | struct kbd_backlight { | 1663 | struct 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 | ||
| 1392 | static struct kbd_backlight *kbdbl_handle; | 1672 | static struct kbd_backlight *kbdbl_ctl; |
| 1393 | 1673 | ||
| 1394 | static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) | 1674 | static 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 | ||
| 1486 | static int sony_nc_kbd_backlight_setup(struct platform_device *pd) | 1766 | static 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 | ||
| 1522 | outmode: | 1821 | outmode: |
| 1523 | device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); | 1822 | device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); |
| 1524 | outkzalloc: | 1823 | outkzalloc: |
| 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 | ||
| 1530 | static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) | 1829 | static 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 | ||
| 1547 | static void sony_nc_kbd_backlight_resume(void) | 1848 | static 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 | |||
| 1865 | struct battery_care_control { | ||
| 1866 | struct device_attribute attrs[2]; | ||
| 1867 | unsigned int handle; | ||
| 1868 | }; | ||
| 1869 | static struct battery_care_control *bcare_ctl; | ||
| 1870 | |||
| 1871 | static 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 | |||
| 1927 | static 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 | |||
| 1954 | static 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 | |||
| 1968 | static 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 | |||
| 2004 | outlimiter: | ||
| 2005 | device_remove_file(&pd->dev, &bcare_ctl->attrs[0]); | ||
| 2006 | |||
| 2007 | outkzalloc: | ||
| 2008 | kfree(bcare_ctl); | ||
| 2009 | bcare_ctl = NULL; | ||
| 2010 | |||
| 2011 | return ret; | ||
| 2012 | } | ||
| 2013 | |||
| 2014 | static 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 | |||
| 2026 | struct snc_thermal_ctrl { | ||
| 2027 | unsigned int mode; | ||
| 2028 | unsigned int profiles; | ||
| 2029 | struct device_attribute mode_attr; | ||
| 2030 | struct device_attribute profiles_attr; | ||
| 2031 | }; | ||
| 2032 | static struct snc_thermal_ctrl *th_handle; | ||
| 2033 | |||
| 2034 | #define THM_PROFILE_MAX 3 | ||
| 2035 | static const char * const snc_thermal_profiles[] = { | ||
| 2036 | "balanced", | ||
| 2037 | "silent", | ||
| 2038 | "performance" | ||
| 2039 | }; | ||
| 2040 | |||
| 2041 | static 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 | |||
| 2062 | static 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 | |||
| 2072 | static 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 | |||
| 2088 | static 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 | |||
| 2112 | static 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 | |||
| 2126 | static 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 | |||
| 2167 | outprofiles: | ||
| 2168 | device_remove_file(&pd->dev, &th_handle->profiles_attr); | ||
| 2169 | outkzalloc: | ||
| 2170 | kfree(th_handle); | ||
| 2171 | th_handle = NULL; | ||
| 2172 | return ret; | ||
| 2173 | } | ||
| 2174 | |||
| 2175 | static 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 | |||
| 2185 | static 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 */ | ||
| 2194 | struct snc_lid_resume_control { | ||
| 2195 | struct device_attribute attrs[3]; | ||
| 2196 | unsigned int status; | ||
| 2197 | }; | ||
| 2198 | static struct snc_lid_resume_control *lid_ctl; | ||
| 2199 | |||
| 2200 | static 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 | |||
| 2240 | static 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 | |||
| 2258 | static 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 | |||
| 2298 | liderror: | ||
| 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 | |||
| 2308 | static 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 */ | ||
| 2322 | static struct device_attribute *hsc_handle; | ||
| 2323 | |||
| 2324 | static 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 | |||
| 2343 | static 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 | |||
| 2354 | static 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 | |||
| 2386 | static 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 */ | ||
| 2396 | struct touchpad_control { | ||
| 2397 | struct device_attribute attr; | ||
| 2398 | int handle; | ||
| 2399 | }; | ||
| 2400 | static struct touchpad_control *tp_ctl; | ||
| 2401 | |||
| 2402 | static 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 | |||
| 2424 | static 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 | |||
| 2435 | static 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 | |||
| 2461 | static 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 | ||
| 1563 | static void sony_nc_backlight_ng_read_limits(int handle, | 2470 | static 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", ¶ms, | ||
| 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 | |||
| 1627 | out_invalid: | ||
| 1628 | kfree(buffer.pointer); | ||
| 1629 | return; | ||
| 1630 | } | 2514 | } |
| 1631 | 2515 | ||
| 1632 | static void sony_nc_backlight_setup(void) | 2516 | static 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 | ||
| 483 | static 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 | |||
| 493 | static 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 | |||
| 481 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; | 502 | static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; |
| 482 | 503 | ||
| 483 | static int get_lcd(struct backlight_device *bd) | 504 | static 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 | ||
| 527 | static 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 | |||
| 496 | static int lcd_proc_show(struct seq_file *m, void *v) | 533 | static 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 | ||
| 521 | static int set_lcd(struct toshiba_acpi_dev *dev, int value) | 559 | static 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) | |||
| 530 | static int set_lcd_status(struct backlight_device *bd) | 577 | static 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 | ||
| 536 | static ssize_t lcd_proc_write(struct file *file, const char __user *buf, | 583 | static 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 | ||
| 862 | static const struct backlight_ops toshiba_backlight_data = { | 910 | static 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 | ||
| 867 | static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, | 916 | static 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 | ||
| 1072 | static 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 | |||
| 1023 | static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type) | 1122 | static 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 | ||
| 18 | static bool card_blocked; | ||
| 19 | |||
| 18 | static int rfkill_set_block(void *data, bool blocked) | 20 | static 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 | ||
| 29 | static const struct rfkill_ops rfkill_ops = { | 40 | static const struct rfkill_ops rfkill_ops = { |
