Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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
...

+1430 -643
+24
drivers/platform/x86/acer-wmi.c
··· 523 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
+4
drivers/platform/x86/apple-gmux.c
··· 87 87 struct apple_gmux_data *gmux_data = bl_get_data(bd); 88 88 u32 brightness = bd->props.brightness; 89 89 90 + if (bd->props.state & BL_CORE_SUSPENDED) 91 + return 0; 92 + 90 93 /* 91 94 * Older gmux versions require writing out lower bytes first then 92 95 * setting the upper byte to 0 to flush the values. Newer versions ··· 105 102 } 106 103 107 104 static const struct backlight_ops gmux_bl_ops = { 105 + .options = BL_CORE_SUSPENDRESUME, 108 106 .get_brightness = gmux_get_brightness, 109 107 .update_status = gmux_update_status, 110 108 };
+46 -290
drivers/platform/x86/dell-laptop.c
··· 21 21 #include <linux/err.h> 22 22 #include <linux/dmi.h> 23 23 #include <linux/io.h> 24 - #include <linux/rfkill.h> 25 24 #include <linux/power_supply.h> 26 25 #include <linux/acpi.h> 27 26 #include <linux/mm.h> ··· 89 90 90 91 static struct platform_device *platform_device; 91 92 static struct backlight_device *dell_backlight_device; 92 - static struct rfkill *wifi_rfkill; 93 - static struct rfkill *bluetooth_rfkill; 94 - static struct rfkill *wwan_rfkill; 95 93 96 - static const struct dmi_system_id __initdata dell_device_table[] = { 94 + static const struct dmi_system_id dell_device_table[] __initconst = { 97 95 { 98 96 .ident = "Dell laptop", 99 97 .matches = { ··· 115 119 }; 116 120 MODULE_DEVICE_TABLE(dmi, dell_device_table); 117 121 118 - static struct dmi_system_id __devinitdata dell_blacklist[] = { 119 - /* Supported by compal-laptop */ 120 - { 121 - .ident = "Dell Mini 9", 122 - .matches = { 123 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 124 - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 910"), 125 - }, 126 - }, 127 - { 128 - .ident = "Dell Mini 10", 129 - .matches = { 130 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 131 - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1010"), 132 - }, 133 - }, 134 - { 135 - .ident = "Dell Mini 10v", 136 - .matches = { 137 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 138 - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1011"), 139 - }, 140 - }, 141 - { 142 - .ident = "Dell Mini 1012", 143 - .matches = { 144 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 145 - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1012"), 146 - }, 147 - }, 148 - { 149 - .ident = "Dell Inspiron 11z", 150 - .matches = { 151 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 152 - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1110"), 153 - }, 154 - }, 155 - { 156 - .ident = "Dell Mini 12", 157 - .matches = { 158 - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 159 - DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron 1210"), 160 - }, 161 - }, 162 - {} 163 - }; 164 - 165 122 static struct dmi_system_id __devinitdata dell_quirks[] = { 166 123 { 167 124 .callback = dmi_matched, ··· 131 182 .matches = { 132 183 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 133 184 DMI_MATCH(DMI_PRODUCT_NAME, "Vostro V131"), 185 + }, 186 + .driver_data = &quirk_dell_vostro_v130, 187 + }, 188 + { 189 + .callback = dmi_matched, 190 + .ident = "Dell Vostro 3350", 191 + .matches = { 192 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 193 + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3350"), 134 194 }, 135 195 .driver_data = &quirk_dell_vostro_v130, 136 196 }, ··· 167 209 .matches = { 168 210 DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 169 211 DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron M5110"), 212 + }, 213 + .driver_data = &quirk_dell_vostro_v130, 214 + }, 215 + { 216 + .callback = dmi_matched, 217 + .ident = "Dell Vostro 3360", 218 + .matches = { 219 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 220 + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3360"), 221 + }, 222 + .driver_data = &quirk_dell_vostro_v130, 223 + }, 224 + { 225 + .callback = dmi_matched, 226 + .ident = "Dell Vostro 3460", 227 + .matches = { 228 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 229 + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3460"), 230 + }, 231 + .driver_data = &quirk_dell_vostro_v130, 232 + }, 233 + { 234 + .callback = dmi_matched, 235 + .ident = "Dell Vostro 3560", 236 + .matches = { 237 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 238 + DMI_MATCH(DMI_PRODUCT_NAME, "Vostro 3560"), 239 + }, 240 + .driver_data = &quirk_dell_vostro_v130, 241 + }, 242 + { 243 + .callback = dmi_matched, 244 + .ident = "Dell Vostro 3450", 245 + .matches = { 246 + DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), 247 + DMI_MATCH(DMI_PRODUCT_NAME, "Dell System Vostro 3450"), 170 248 }, 171 249 .driver_data = &quirk_dell_vostro_v130, 172 250 }, ··· 299 305 return buffer; 300 306 } 301 307 302 - /* Derived from information in DellWirelessCtl.cpp: 303 - Class 17, select 11 is radio control. It returns an array of 32-bit values. 304 - 305 - Input byte 0 = 0: Wireless information 306 - 307 - result[0]: return code 308 - result[1]: 309 - Bit 0: Hardware switch supported 310 - Bit 1: Wifi locator supported 311 - Bit 2: Wifi is supported 312 - Bit 3: Bluetooth is supported 313 - Bit 4: WWAN is supported 314 - Bit 5: Wireless keyboard supported 315 - Bits 6-7: Reserved 316 - Bit 8: Wifi is installed 317 - Bit 9: Bluetooth is installed 318 - Bit 10: WWAN is installed 319 - Bits 11-15: Reserved 320 - Bit 16: Hardware switch is on 321 - Bit 17: Wifi is blocked 322 - Bit 18: Bluetooth is blocked 323 - Bit 19: WWAN is blocked 324 - Bits 20-31: Reserved 325 - result[2]: NVRAM size in bytes 326 - result[3]: NVRAM format version number 327 - 328 - Input byte 0 = 2: Wireless switch configuration 329 - result[0]: return code 330 - result[1]: 331 - Bit 0: Wifi controlled by switch 332 - Bit 1: Bluetooth controlled by switch 333 - Bit 2: WWAN controlled by switch 334 - Bits 3-6: Reserved 335 - Bit 7: Wireless switch config locked 336 - Bit 8: Wifi locator enabled 337 - Bits 9-14: Reserved 338 - Bit 15: Wifi locator setting locked 339 - Bits 16-31: Reserved 340 - */ 341 - 342 - static int dell_rfkill_set(void *data, bool blocked) 343 - { 344 - int disable = blocked ? 1 : 0; 345 - unsigned long radio = (unsigned long)data; 346 - int hwswitch_bit = (unsigned long)data - 1; 347 - int ret = 0; 348 - 349 - get_buffer(); 350 - dell_send_request(buffer, 17, 11); 351 - 352 - /* If the hardware switch controls this radio, and the hardware 353 - switch is disabled, don't allow changing the software state */ 354 - if ((hwswitch_state & BIT(hwswitch_bit)) && 355 - !(buffer->output[1] & BIT(16))) { 356 - ret = -EINVAL; 357 - goto out; 358 - } 359 - 360 - buffer->input[0] = (1 | (radio<<8) | (disable << 16)); 361 - dell_send_request(buffer, 17, 11); 362 - 363 - out: 364 - release_buffer(); 365 - return ret; 366 - } 367 - 368 - static void dell_rfkill_query(struct rfkill *rfkill, void *data) 369 - { 370 - int status; 371 - int bit = (unsigned long)data + 16; 372 - int hwswitch_bit = (unsigned long)data - 1; 373 - 374 - get_buffer(); 375 - dell_send_request(buffer, 17, 11); 376 - status = buffer->output[1]; 377 - release_buffer(); 378 - 379 - rfkill_set_sw_state(rfkill, !!(status & BIT(bit))); 380 - 381 - if (hwswitch_state & (BIT(hwswitch_bit))) 382 - rfkill_set_hw_state(rfkill, !(status & BIT(16))); 383 - } 384 - 385 - static const struct rfkill_ops dell_rfkill_ops = { 386 - .set_block = dell_rfkill_set, 387 - .query = dell_rfkill_query, 388 - }; 389 - 390 308 static struct dentry *dell_laptop_dir; 391 309 392 310 static int dell_debugfs_show(struct seq_file *s, void *data) ··· 367 461 .llseek = seq_lseek, 368 462 .release = single_release, 369 463 }; 370 - 371 - static void dell_update_rfkill(struct work_struct *ignored) 372 - { 373 - if (wifi_rfkill) 374 - dell_rfkill_query(wifi_rfkill, (void *)1); 375 - if (bluetooth_rfkill) 376 - dell_rfkill_query(bluetooth_rfkill, (void *)2); 377 - if (wwan_rfkill) 378 - dell_rfkill_query(wwan_rfkill, (void *)3); 379 - } 380 - static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill); 381 - 382 - 383 - static int __init dell_setup_rfkill(void) 384 - { 385 - int status; 386 - int ret; 387 - 388 - if (dmi_check_system(dell_blacklist)) { 389 - pr_info("Blacklisted hardware detected - not enabling rfkill\n"); 390 - return 0; 391 - } 392 - 393 - get_buffer(); 394 - dell_send_request(buffer, 17, 11); 395 - status = buffer->output[1]; 396 - buffer->input[0] = 0x2; 397 - dell_send_request(buffer, 17, 11); 398 - hwswitch_state = buffer->output[1]; 399 - release_buffer(); 400 - 401 - if ((status & (1<<2|1<<8)) == (1<<2|1<<8)) { 402 - wifi_rfkill = rfkill_alloc("dell-wifi", &platform_device->dev, 403 - RFKILL_TYPE_WLAN, 404 - &dell_rfkill_ops, (void *) 1); 405 - if (!wifi_rfkill) { 406 - ret = -ENOMEM; 407 - goto err_wifi; 408 - } 409 - ret = rfkill_register(wifi_rfkill); 410 - if (ret) 411 - goto err_wifi; 412 - } 413 - 414 - if ((status & (1<<3|1<<9)) == (1<<3|1<<9)) { 415 - bluetooth_rfkill = rfkill_alloc("dell-bluetooth", 416 - &platform_device->dev, 417 - RFKILL_TYPE_BLUETOOTH, 418 - &dell_rfkill_ops, (void *) 2); 419 - if (!bluetooth_rfkill) { 420 - ret = -ENOMEM; 421 - goto err_bluetooth; 422 - } 423 - ret = rfkill_register(bluetooth_rfkill); 424 - if (ret) 425 - goto err_bluetooth; 426 - } 427 - 428 - if ((status & (1<<4|1<<10)) == (1<<4|1<<10)) { 429 - wwan_rfkill = rfkill_alloc("dell-wwan", 430 - &platform_device->dev, 431 - RFKILL_TYPE_WWAN, 432 - &dell_rfkill_ops, (void *) 3); 433 - if (!wwan_rfkill) { 434 - ret = -ENOMEM; 435 - goto err_wwan; 436 - } 437 - ret = rfkill_register(wwan_rfkill); 438 - if (ret) 439 - goto err_wwan; 440 - } 441 - 442 - return 0; 443 - err_wwan: 444 - rfkill_destroy(wwan_rfkill); 445 - if (bluetooth_rfkill) 446 - rfkill_unregister(bluetooth_rfkill); 447 - err_bluetooth: 448 - rfkill_destroy(bluetooth_rfkill); 449 - if (wifi_rfkill) 450 - rfkill_unregister(wifi_rfkill); 451 - err_wifi: 452 - rfkill_destroy(wifi_rfkill); 453 - 454 - return ret; 455 - } 456 - 457 - static void dell_cleanup_rfkill(void) 458 - { 459 - if (wifi_rfkill) { 460 - rfkill_unregister(wifi_rfkill); 461 - rfkill_destroy(wifi_rfkill); 462 - } 463 - if (bluetooth_rfkill) { 464 - rfkill_unregister(bluetooth_rfkill); 465 - rfkill_destroy(bluetooth_rfkill); 466 - } 467 - if (wwan_rfkill) { 468 - rfkill_unregister(wwan_rfkill); 469 - rfkill_destroy(wwan_rfkill); 470 - } 471 - } 472 464 473 465 static int dell_send_intensity(struct backlight_device *bd) 474 466 { ··· 459 655 led_classdev_unregister(&touchpad_led); 460 656 } 461 657 462 - static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str, 463 - struct serio *port) 464 - { 465 - static bool extended; 466 - 467 - if (str & 0x20) 468 - return false; 469 - 470 - if (unlikely(data == 0xe0)) { 471 - extended = true; 472 - return false; 473 - } else if (unlikely(extended)) { 474 - switch (data) { 475 - case 0x8: 476 - schedule_delayed_work(&dell_rfkill_work, 477 - round_jiffies_relative(HZ)); 478 - break; 479 - } 480 - extended = false; 481 - } 482 - 483 - return false; 484 - } 485 - 486 658 static int __init dell_init(void) 487 659 { 488 660 int max_intensity = 0; ··· 500 720 goto fail_buffer; 501 721 buffer = page_address(bufferpage); 502 722 503 - ret = dell_setup_rfkill(); 504 - 505 - if (ret) { 506 - pr_warn("Unable to setup rfkill\n"); 507 - goto fail_rfkill; 508 - } 509 - 510 - ret = i8042_install_filter(dell_laptop_i8042_filter); 511 - if (ret) { 512 - pr_warn("Unable to install key filter\n"); 513 - goto fail_filter; 514 - } 515 - 516 723 if (quirks && quirks->touchpad_led) 517 724 touchpad_led_init(&platform_device->dev); 518 725 519 726 dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL); 520 - if (dell_laptop_dir != NULL) 521 - debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL, 522 - &dell_debugfs_fops); 523 727 524 728 #ifdef CONFIG_ACPI 525 729 /* In the event of an ACPI backlight being available, don't ··· 546 782 return 0; 547 783 548 784 fail_backlight: 549 - i8042_remove_filter(dell_laptop_i8042_filter); 550 - cancel_delayed_work_sync(&dell_rfkill_work); 551 - fail_filter: 552 - dell_cleanup_rfkill(); 553 - fail_rfkill: 554 785 free_page((unsigned long)bufferpage); 555 786 fail_buffer: 556 787 platform_device_del(platform_device); ··· 563 804 debugfs_remove_recursive(dell_laptop_dir); 564 805 if (quirks && quirks->touchpad_led) 565 806 touchpad_led_exit(); 566 - i8042_remove_filter(dell_laptop_i8042_filter); 567 - cancel_delayed_work_sync(&dell_rfkill_work); 568 807 backlight_device_unregister(dell_backlight_device); 569 - dell_cleanup_rfkill(); 570 808 if (platform_device) { 571 809 platform_device_unregister(platform_device); 572 810 platform_driver_unregister(&platform_driver);
+21 -13
drivers/platform/x86/fujitsu-tablet.c
··· 16 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 21 #include <linux/kernel.h> 20 22 #include <linux/module.h> 21 23 #include <linux/init.h> ··· 36 34 #define ACPI_FUJITSU_CLASS "fujitsu" 37 35 38 36 #define INVERT_TABLET_MODE_BIT 0x01 39 - #define FORCE_TABLET_MODE_IF_UNDOCK 0x02 37 + #define INVERT_DOCK_STATE_BIT 0x02 38 + #define FORCE_TABLET_MODE_IF_UNDOCK 0x04 40 39 41 40 #define KEYMAP_LEN 16 42 41 ··· 164 161 state = fujitsu_read_register(0xdd); 165 162 166 163 dock = state & 0x02; 164 + if (fujitsu.config.quirks & INVERT_DOCK_STATE_BIT) 165 + dock = !dock; 167 166 168 167 if ((fujitsu.config.quirks & FORCE_TABLET_MODE_IF_UNDOCK) && (!dock)) { 169 168 tablet_mode = 1; ··· 226 221 input_set_capability(idev, EV_SW, SW_DOCK); 227 222 input_set_capability(idev, EV_SW, SW_TABLET_MODE); 228 223 229 - input_set_capability(idev, EV_SW, SW_DOCK); 230 - input_set_capability(idev, EV_SW, SW_TABLET_MODE); 231 - 232 224 error = input_register_device(idev); 233 225 if (error) { 234 226 input_free_device(idev); ··· 277 275 return IRQ_HANDLED; 278 276 } 279 277 280 - static int __devinit fujitsu_dmi_default(const struct dmi_system_id *dmi) 278 + static void __devinit fujitsu_dmi_common(const struct dmi_system_id *dmi) 281 279 { 282 - printk(KERN_INFO MODULENAME ": %s\n", dmi->ident); 280 + pr_info("%s\n", dmi->ident); 283 281 memcpy(fujitsu.config.keymap, dmi->driver_data, 284 282 sizeof(fujitsu.config.keymap)); 283 + } 284 + 285 + static int __devinit fujitsu_dmi_lifebook(const struct dmi_system_id *dmi) 286 + { 287 + fujitsu_dmi_common(dmi); 288 + fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; 285 289 return 1; 286 290 } 287 291 288 292 static int __devinit fujitsu_dmi_stylistic(const struct dmi_system_id *dmi) 289 293 { 290 - fujitsu_dmi_default(dmi); 294 + fujitsu_dmi_common(dmi); 291 295 fujitsu.config.quirks |= FORCE_TABLET_MODE_IF_UNDOCK; 292 - fujitsu.config.quirks |= INVERT_TABLET_MODE_BIT; 296 + fujitsu.config.quirks |= INVERT_DOCK_STATE_BIT; 293 297 return 1; 294 298 } 295 299 296 300 static struct dmi_system_id dmi_ids[] __initconst = { 297 301 { 298 - .callback = fujitsu_dmi_default, 302 + .callback = fujitsu_dmi_lifebook, 299 303 .ident = "Fujitsu Siemens P/T Series", 300 304 .matches = { 301 305 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ··· 310 302 .driver_data = keymap_Lifebook_Tseries 311 303 }, 312 304 { 313 - .callback = fujitsu_dmi_default, 305 + .callback = fujitsu_dmi_lifebook, 314 306 .ident = "Fujitsu Lifebook T Series", 315 307 .matches = { 316 308 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ··· 328 320 .driver_data = keymap_Stylistic_Tseries 329 321 }, 330 322 { 331 - .callback = fujitsu_dmi_default, 323 + .callback = fujitsu_dmi_lifebook, 332 324 .ident = "Fujitsu LifeBook U810", 333 325 .matches = { 334 326 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), ··· 355 347 .driver_data = keymap_Stylistic_ST5xxx 356 348 }, 357 349 { 358 - .callback = fujitsu_dmi_default, 350 + .callback = fujitsu_dmi_lifebook, 359 351 .ident = "Unknown (using defaults)", 360 352 .matches = { 361 353 DMI_MATCH(DMI_SYS_VENDOR, ""), ··· 481 473 MODULE_AUTHOR("Robert Gerlach <khnz@gmx.de>"); 482 474 MODULE_DESCRIPTION("Fujitsu tablet pc extras driver"); 483 475 MODULE_LICENSE("GPL"); 484 - MODULE_VERSION("2.4"); 476 + MODULE_VERSION("2.5"); 485 477 486 478 MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
+1 -1
drivers/platform/x86/hdaps.c
··· 2 2 * hdaps.c - driver for IBM's Hard Drive Active Protection System 3 3 * 4 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 7 * The HardDisk Active Protection System (hdaps) is present in IBM ThinkPads 8 8 * starting with the R40, T41, and X40. It provides a basic two-axis
+10
drivers/platform/x86/hp-wmi.c
··· 634 634 RFKILL_TYPE_WLAN, 635 635 &hp_wmi_rfkill_ops, 636 636 (void *) HPWMI_WIFI); 637 + if (!wifi_rfkill) 638 + return -ENOMEM; 637 639 rfkill_init_sw_state(wifi_rfkill, 638 640 hp_wmi_get_sw_state(HPWMI_WIFI)); 639 641 rfkill_set_hw_state(wifi_rfkill, ··· 650 648 RFKILL_TYPE_BLUETOOTH, 651 649 &hp_wmi_rfkill_ops, 652 650 (void *) HPWMI_BLUETOOTH); 651 + if (!bluetooth_rfkill) { 652 + err = -ENOMEM; 653 + goto register_wifi_error; 654 + } 653 655 rfkill_init_sw_state(bluetooth_rfkill, 654 656 hp_wmi_get_sw_state(HPWMI_BLUETOOTH)); 655 657 rfkill_set_hw_state(bluetooth_rfkill, ··· 668 662 RFKILL_TYPE_WWAN, 669 663 &hp_wmi_rfkill_ops, 670 664 (void *) HPWMI_WWAN); 665 + if (!wwan_rfkill) { 666 + err = -ENOMEM; 667 + goto register_bluetooth_error; 668 + } 671 669 rfkill_init_sw_state(wwan_rfkill, 672 670 hp_wmi_get_sw_state(HPWMI_WWAN)); 673 671 rfkill_set_hw_state(wwan_rfkill,
+6 -3
drivers/platform/x86/ideapad-laptop.c
··· 194 194 /* 195 195 * debugfs 196 196 */ 197 - #define DEBUGFS_EVENT_LEN (4096) 198 197 static int debugfs_status_show(struct seq_file *s, void *data) 199 198 { 200 199 unsigned long value; ··· 314 315 node = debugfs_create_file("status", S_IRUGO, priv->debug, NULL, 315 316 &debugfs_status_fops); 316 317 if (!node) { 317 - pr_err("failed to create event in debugfs"); 318 + pr_err("failed to create status in debugfs"); 318 319 goto errout; 319 320 } 320 321 ··· 784 785 case 9: 785 786 ideapad_sync_rfk_state(priv); 786 787 break; 788 + case 13: 789 + case 6: 790 + ideapad_input_report(priv, vpc_bit); 791 + break; 787 792 case 4: 788 793 ideapad_backlight_notify_brightness(priv); 789 794 break; ··· 798 795 ideapad_backlight_notify_power(priv); 799 796 break; 800 797 default: 801 - ideapad_input_report(priv, vpc_bit); 798 + pr_info("Unknown event: %lu\n", vpc_bit); 802 799 } 803 800 } 804 801 }
+1192 -306
drivers/platform/x86/sony-laptop.c
··· 141 141 "(default: 0)"); 142 142 143 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 166 enum sony_nc_rfkill { 146 167 SONY_WIFI, ··· 174 153 static int sony_rfkill_handle; 175 154 static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL]; 176 155 static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900}; 156 + static int sony_nc_rfkill_setup(struct acpi_device *device, 157 + unsigned int handle); 158 + static void sony_nc_rfkill_cleanup(void); 177 159 static void sony_nc_rfkill_update(void); 178 160 179 161 /*********** Input Devices ***********/ ··· 715 691 716 692 /* 717 693 * acpi_evaluate_object wrappers 694 + * all useful calls into SNC methods take one or zero parameters and return 695 + * integers or arrays. 718 696 */ 719 - static int acpi_callgetfunc(acpi_handle handle, char *name, int *result) 697 + static union acpi_object *__call_snc_method(acpi_handle handle, char *method, 698 + u64 *value) 720 699 { 721 - struct acpi_buffer output; 722 - union acpi_object out_obj; 700 + union acpi_object *result = NULL; 701 + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; 723 702 acpi_status status; 724 703 725 - output.length = sizeof(out_obj); 726 - output.pointer = &out_obj; 727 - 728 - status = acpi_evaluate_object(handle, name, NULL, &output); 729 - if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { 730 - *result = out_obj.integer.value; 731 - return 0; 704 + if (value) { 705 + struct acpi_object_list params; 706 + union acpi_object in; 707 + in.type = ACPI_TYPE_INTEGER; 708 + in.integer.value = *value; 709 + params.count = 1; 710 + params.pointer = &in; 711 + status = acpi_evaluate_object(handle, method, &params, &output); 712 + dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method, 713 + (unsigned int)(*value >> 32), 714 + (unsigned int)*value & 0xffffffff); 715 + } else { 716 + status = acpi_evaluate_object(handle, method, NULL, &output); 717 + dprintk("__call_snc_method: [%s]\n", method); 732 718 } 733 719 734 - pr_warn("acpi_callreadfunc failed\n"); 720 + if (ACPI_FAILURE(status)) { 721 + pr_err("Failed to evaluate [%s]\n", method); 722 + return NULL; 723 + } 735 724 736 - return -1; 725 + result = (union acpi_object *) output.pointer; 726 + if (!result) 727 + dprintk("No return object [%s]\n", method); 728 + 729 + return result; 737 730 } 738 731 739 - static int acpi_callsetfunc(acpi_handle handle, char *name, int value, 740 - int *result) 732 + static int sony_nc_int_call(acpi_handle handle, char *name, int *value, 733 + int *result) 741 734 { 742 - struct acpi_object_list params; 743 - union acpi_object in_obj; 744 - struct acpi_buffer output; 745 - union acpi_object out_obj; 746 - acpi_status status; 735 + union acpi_object *object = NULL; 736 + if (value) { 737 + u64 v = *value; 738 + object = __call_snc_method(handle, name, &v); 739 + } else 740 + object = __call_snc_method(handle, name, NULL); 747 741 748 - params.count = 1; 749 - params.pointer = &in_obj; 750 - in_obj.type = ACPI_TYPE_INTEGER; 751 - in_obj.integer.value = value; 742 + if (!object) 743 + return -EINVAL; 752 744 753 - output.length = sizeof(out_obj); 754 - output.pointer = &out_obj; 755 - 756 - status = acpi_evaluate_object(handle, name, &params, &output); 757 - if (status == AE_OK) { 758 - if (result != NULL) { 759 - if (out_obj.type != ACPI_TYPE_INTEGER) { 760 - pr_warn("acpi_evaluate_object bad return type\n"); 761 - return -1; 762 - } 763 - *result = out_obj.integer.value; 764 - } 765 - return 0; 745 + if (object->type != ACPI_TYPE_INTEGER) { 746 + pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", 747 + ACPI_TYPE_INTEGER, object->type); 748 + kfree(object); 749 + return -EINVAL; 766 750 } 767 751 768 - pr_warn("acpi_evaluate_object failed\n"); 752 + if (result) 753 + *result = object->integer.value; 769 754 770 - return -1; 755 + kfree(object); 756 + return 0; 757 + } 758 + 759 + #define MIN(a, b) (a > b ? b : a) 760 + static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value, 761 + void *buffer, size_t buflen) 762 + { 763 + size_t len = len; 764 + union acpi_object *object = __call_snc_method(handle, name, value); 765 + 766 + if (!object) 767 + return -EINVAL; 768 + 769 + if (object->type == ACPI_TYPE_BUFFER) 770 + len = MIN(buflen, object->buffer.length); 771 + 772 + else if (object->type == ACPI_TYPE_INTEGER) 773 + len = MIN(buflen, sizeof(object->integer.value)); 774 + 775 + else { 776 + pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n", 777 + ACPI_TYPE_BUFFER, object->type); 778 + kfree(object); 779 + return -EINVAL; 780 + } 781 + 782 + memcpy(buffer, object->buffer.pointer, len); 783 + kfree(object); 784 + return 0; 771 785 } 772 786 773 787 struct sony_nc_handles { ··· 832 770 833 771 static int sony_nc_handles_setup(struct platform_device *pd) 834 772 { 835 - int i; 836 - int result; 773 + int i, r, result, arg; 837 774 838 775 handles = kzalloc(sizeof(*handles), GFP_KERNEL); 839 776 if (!handles) 840 777 return -ENOMEM; 841 778 842 779 for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 843 - if (!acpi_callsetfunc(sony_nc_acpi_handle, 844 - "SN00", i + 0x20, &result)) { 780 + arg = i + 0x20; 781 + r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, 782 + &result); 783 + if (!r) { 845 784 dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n", 846 785 result, i); 847 786 handles->cap[i] = result; ··· 882 819 int i; 883 820 884 821 /* not initialized yet, return early */ 885 - if (!handles) 886 - return -1; 822 + if (!handles || !handle) 823 + return -EINVAL; 887 824 888 825 for (i = 0; i < 0x10; i++) { 889 826 if (handles->cap[i] == handle) { ··· 893 830 } 894 831 } 895 832 dprintk("handle 0x%.4x not found\n", handle); 896 - return -1; 833 + return -EINVAL; 897 834 } 898 835 899 836 static int sony_call_snc_handle(int handle, int argument, int *result) 900 837 { 901 - int ret = 0; 838 + int arg, ret = 0; 902 839 int offset = sony_find_snc_handle(handle); 903 840 904 841 if (offset < 0) 905 - return -1; 842 + return offset; 906 843 907 - ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument, 908 - result); 909 - dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument, 910 - *result); 844 + arg = offset | argument; 845 + ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result); 846 + dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result); 911 847 return ret; 912 848 } 913 849 ··· 951 889 static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, 952 890 char *buffer) 953 891 { 954 - int value; 892 + int value, ret = 0; 955 893 struct sony_nc_value *item = 956 894 container_of(attr, struct sony_nc_value, devattr); 957 895 958 896 if (!*item->acpiget) 959 897 return -EIO; 960 898 961 - if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) 899 + ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL, 900 + &value); 901 + if (ret < 0) 962 902 return -EIO; 963 903 964 904 if (item->validate) ··· 973 909 struct device_attribute *attr, 974 910 const char *buffer, size_t count) 975 911 { 976 - int value; 912 + unsigned long value = 0; 913 + int ret = 0; 977 914 struct sony_nc_value *item = 978 915 container_of(attr, struct sony_nc_value, devattr); 979 916 ··· 984 919 if (count > 31) 985 920 return -EINVAL; 986 921 987 - value = simple_strtoul(buffer, NULL, 10); 922 + if (kstrtoul(buffer, 10, &value)) 923 + return -EINVAL; 988 924 989 925 if (item->validate) 990 926 value = item->validate(SNC_VALIDATE_IN, value); ··· 993 927 if (value < 0) 994 928 return value; 995 929 996 - if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) 930 + ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, 931 + (int *)&value, NULL); 932 + if (ret < 0) 997 933 return -EIO; 934 + 998 935 item->value = value; 999 936 item->valid = 1; 1000 937 return count; ··· 1017 948 1018 949 static int sony_backlight_update_status(struct backlight_device *bd) 1019 950 { 1020 - return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", 1021 - bd->props.brightness + 1, NULL); 951 + int arg = bd->props.brightness + 1; 952 + return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL); 1022 953 } 1023 954 1024 955 static int sony_backlight_get_brightness(struct backlight_device *bd) 1025 956 { 1026 957 int value; 1027 958 1028 - if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) 959 + if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value)) 1029 960 return 0; 1030 961 /* brightness levels are 1-based, while backlight ones are 0-based */ 1031 962 return value - 1; ··· 1093 1024 { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, 1094 1025 { 0x87, SONYPI_EVENT_FNKEY_F7 }, 1095 1026 { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, 1027 + { 0x88, SONYPI_EVENT_FNKEY_F8 }, 1028 + { 0x08, SONYPI_EVENT_FNKEY_RELEASED }, 1096 1029 { 0x89, SONYPI_EVENT_FNKEY_F9 }, 1097 1030 { 0x09, SONYPI_EVENT_FNKEY_RELEASED }, 1098 1031 { 0x8A, SONYPI_EVENT_FNKEY_F10 }, 1099 1032 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, 1033 + { 0x8B, SONYPI_EVENT_FNKEY_F11 }, 1034 + { 0x0B, SONYPI_EVENT_FNKEY_RELEASED }, 1100 1035 { 0x8C, SONYPI_EVENT_FNKEY_F12 }, 1101 1036 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, 1102 1037 { 0x9d, SONYPI_EVENT_ZOOM_PRESSED }, ··· 1136 1063 { 0, 0 }, 1137 1064 }; 1138 1065 1066 + static int sony_nc_hotkeys_decode(u32 event, unsigned int handle) 1067 + { 1068 + int ret = -EINVAL; 1069 + unsigned int result = 0; 1070 + struct sony_nc_event *key_event; 1071 + 1072 + if (sony_call_snc_handle(handle, 0x200, &result)) { 1073 + dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle, 1074 + event); 1075 + return -EINVAL; 1076 + } 1077 + 1078 + result &= 0xFF; 1079 + 1080 + if (handle == 0x0100) 1081 + key_event = sony_100_events; 1082 + else 1083 + key_event = sony_127_events; 1084 + 1085 + for (; key_event->data; key_event++) { 1086 + if (key_event->data == result) { 1087 + ret = key_event->event; 1088 + break; 1089 + } 1090 + } 1091 + 1092 + if (!key_event->data) 1093 + pr_info("Unknown hotkey 0x%.2x/0x%.2x (handle 0x%.2x)\n", 1094 + event, result, handle); 1095 + 1096 + return ret; 1097 + } 1098 + 1139 1099 /* 1140 1100 * ACPI callbacks 1141 1101 */ 1142 1102 static void sony_nc_notify(struct acpi_device *device, u32 event) 1143 1103 { 1144 - u32 ev = event; 1104 + u32 real_ev = event; 1105 + u8 ev_type = 0; 1106 + dprintk("sony_nc_notify, event: 0x%.2x\n", event); 1145 1107 1146 - if (ev >= 0x90) { 1147 - /* New-style event */ 1148 - int result; 1149 - int key_handle = 0; 1150 - ev -= 0x90; 1108 + if (event >= 0x90) { 1109 + unsigned int result = 0; 1110 + unsigned int arg = 0; 1111 + unsigned int handle = 0; 1112 + unsigned int offset = event - 0x90; 1151 1113 1152 - if (sony_find_snc_handle(0x100) == ev) 1153 - key_handle = 0x100; 1154 - if (sony_find_snc_handle(0x127) == ev) 1155 - key_handle = 0x127; 1156 - 1157 - if (key_handle) { 1158 - struct sony_nc_event *key_event; 1159 - 1160 - if (sony_call_snc_handle(key_handle, 0x200, &result)) { 1161 - dprintk("sony_nc_notify, unable to decode" 1162 - " event 0x%.2x 0x%.2x\n", key_handle, 1163 - ev); 1164 - /* restore the original event */ 1165 - ev = event; 1166 - } else { 1167 - ev = result & 0xFF; 1168 - 1169 - if (key_handle == 0x100) 1170 - key_event = sony_100_events; 1171 - else 1172 - key_event = sony_127_events; 1173 - 1174 - for (; key_event->data; key_event++) { 1175 - if (key_event->data == ev) { 1176 - ev = key_event->event; 1177 - break; 1178 - } 1179 - } 1180 - 1181 - if (!key_event->data) 1182 - pr_info("Unknown event: 0x%x 0x%x\n", 1183 - key_handle, ev); 1184 - else 1185 - sony_laptop_report_input_event(ev); 1186 - } 1187 - } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) { 1188 - sony_nc_rfkill_update(); 1114 + if (offset >= ARRAY_SIZE(handles->cap)) { 1115 + pr_err("Event 0x%x outside of capabilities list\n", 1116 + event); 1189 1117 return; 1190 1118 } 1191 - } else 1192 - sony_laptop_report_input_event(ev); 1119 + handle = handles->cap[offset]; 1193 1120 1194 - dprintk("sony_nc_notify, event: 0x%.2x\n", ev); 1195 - acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev); 1121 + /* list of handles known for generating events */ 1122 + switch (handle) { 1123 + /* hotkey event */ 1124 + case 0x0100: 1125 + case 0x0127: 1126 + ev_type = 1; 1127 + real_ev = sony_nc_hotkeys_decode(event, handle); 1128 + 1129 + if (real_ev > 0) 1130 + sony_laptop_report_input_event(real_ev); 1131 + else 1132 + /* restore the original event for reporting */ 1133 + real_ev = event; 1134 + 1135 + break; 1136 + 1137 + /* wlan switch */ 1138 + case 0x0124: 1139 + case 0x0135: 1140 + /* events on this handle are reported when the 1141 + * switch changes position or for battery 1142 + * events. We'll notify both of them but only 1143 + * update the rfkill device status when the 1144 + * switch is moved. 1145 + */ 1146 + ev_type = 2; 1147 + sony_call_snc_handle(handle, 0x0100, &result); 1148 + real_ev = result & 0x03; 1149 + 1150 + /* hw switch event */ 1151 + if (real_ev == 1) 1152 + sony_nc_rfkill_update(); 1153 + 1154 + break; 1155 + 1156 + default: 1157 + dprintk("Unknown event 0x%x for handle 0x%x\n", 1158 + event, handle); 1159 + break; 1160 + } 1161 + 1162 + /* clear the event (and the event reason when present) */ 1163 + arg = 1 << offset; 1164 + sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result); 1165 + 1166 + } else { 1167 + /* old style event */ 1168 + ev_type = 1; 1169 + sony_laptop_report_input_event(real_ev); 1170 + } 1171 + 1172 + acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev); 1173 + 1174 + acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class, 1175 + dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev); 1196 1176 } 1197 1177 1198 1178 static acpi_status sony_walk_callback(acpi_handle handle, u32 level, ··· 1266 1140 /* 1267 1141 * ACPI device 1268 1142 */ 1269 - static int sony_nc_function_setup(struct acpi_device *device) 1143 + static void sony_nc_function_setup(struct acpi_device *device, 1144 + struct platform_device *pf_device) 1270 1145 { 1271 - int result; 1146 + unsigned int i, result, bitmask, arg; 1147 + 1148 + if (!handles) 1149 + return; 1150 + 1151 + /* setup found handles here */ 1152 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 1153 + unsigned int handle = handles->cap[i]; 1154 + 1155 + if (!handle) 1156 + continue; 1157 + 1158 + dprintk("setting up handle 0x%.4x\n", handle); 1159 + 1160 + switch (handle) { 1161 + case 0x0100: 1162 + case 0x0101: 1163 + case 0x0127: 1164 + /* setup hotkeys */ 1165 + sony_call_snc_handle(handle, 0, &result); 1166 + break; 1167 + case 0x0102: 1168 + /* setup hotkeys */ 1169 + sony_call_snc_handle(handle, 0x100, &result); 1170 + break; 1171 + case 0x0105: 1172 + case 0x0148: 1173 + /* touchpad enable/disable */ 1174 + result = sony_nc_touchpad_setup(pf_device, handle); 1175 + if (result) 1176 + pr_err("couldn't set up touchpad control function (%d)\n", 1177 + result); 1178 + break; 1179 + case 0x0115: 1180 + case 0x0136: 1181 + case 0x013f: 1182 + result = sony_nc_battery_care_setup(pf_device, handle); 1183 + if (result) 1184 + pr_err("couldn't set up battery care function (%d)\n", 1185 + result); 1186 + break; 1187 + case 0x0119: 1188 + result = sony_nc_lid_resume_setup(pf_device); 1189 + if (result) 1190 + pr_err("couldn't set up lid resume function (%d)\n", 1191 + result); 1192 + break; 1193 + case 0x0122: 1194 + result = sony_nc_thermal_setup(pf_device); 1195 + if (result) 1196 + pr_err("couldn't set up thermal profile function (%d)\n", 1197 + result); 1198 + break; 1199 + case 0x0131: 1200 + result = sony_nc_highspeed_charging_setup(pf_device); 1201 + if (result) 1202 + pr_err("couldn't set up high speed charging function (%d)\n", 1203 + result); 1204 + break; 1205 + case 0x0124: 1206 + case 0x0135: 1207 + result = sony_nc_rfkill_setup(device, handle); 1208 + if (result) 1209 + pr_err("couldn't set up rfkill support (%d)\n", 1210 + result); 1211 + break; 1212 + case 0x0137: 1213 + case 0x0143: 1214 + result = sony_nc_kbd_backlight_setup(pf_device, handle); 1215 + if (result) 1216 + pr_err("couldn't set up keyboard backlight function (%d)\n", 1217 + result); 1218 + break; 1219 + default: 1220 + continue; 1221 + } 1222 + } 1272 1223 1273 1224 /* Enable all events */ 1274 - acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result); 1225 + arg = 0x10; 1226 + if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask)) 1227 + sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask, 1228 + &result); 1229 + } 1275 1230 1276 - /* Setup hotkeys */ 1277 - sony_call_snc_handle(0x0100, 0, &result); 1278 - sony_call_snc_handle(0x0101, 0, &result); 1279 - sony_call_snc_handle(0x0102, 0x100, &result); 1280 - sony_call_snc_handle(0x0127, 0, &result); 1231 + static void sony_nc_function_cleanup(struct platform_device *pd) 1232 + { 1233 + unsigned int i, result, bitmask, handle; 1281 1234 1282 - return 0; 1235 + /* get enabled events and disable them */ 1236 + sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask); 1237 + sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result); 1238 + 1239 + /* cleanup handles here */ 1240 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 1241 + 1242 + handle = handles->cap[i]; 1243 + 1244 + if (!handle) 1245 + continue; 1246 + 1247 + switch (handle) { 1248 + case 0x0105: 1249 + case 0x0148: 1250 + sony_nc_touchpad_cleanup(pd); 1251 + break; 1252 + case 0x0115: 1253 + case 0x0136: 1254 + case 0x013f: 1255 + sony_nc_battery_care_cleanup(pd); 1256 + break; 1257 + case 0x0119: 1258 + sony_nc_lid_resume_cleanup(pd); 1259 + break; 1260 + case 0x0122: 1261 + sony_nc_thermal_cleanup(pd); 1262 + break; 1263 + case 0x0131: 1264 + sony_nc_highspeed_charging_cleanup(pd); 1265 + break; 1266 + case 0x0124: 1267 + case 0x0135: 1268 + sony_nc_rfkill_cleanup(); 1269 + break; 1270 + case 0x0137: 1271 + case 0x0143: 1272 + sony_nc_kbd_backlight_cleanup(pd); 1273 + break; 1274 + default: 1275 + continue; 1276 + } 1277 + } 1278 + 1279 + /* finally cleanup the handles list */ 1280 + sony_nc_handles_cleanup(pd); 1281 + } 1282 + 1283 + static void sony_nc_function_resume(void) 1284 + { 1285 + unsigned int i, result, bitmask, arg; 1286 + 1287 + dprintk("Resuming SNC device\n"); 1288 + 1289 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) { 1290 + unsigned int handle = handles->cap[i]; 1291 + 1292 + if (!handle) 1293 + continue; 1294 + 1295 + switch (handle) { 1296 + case 0x0100: 1297 + case 0x0101: 1298 + case 0x0127: 1299 + /* re-enable hotkeys */ 1300 + sony_call_snc_handle(handle, 0, &result); 1301 + break; 1302 + case 0x0102: 1303 + /* re-enable hotkeys */ 1304 + sony_call_snc_handle(handle, 0x100, &result); 1305 + break; 1306 + case 0x0122: 1307 + sony_nc_thermal_resume(); 1308 + break; 1309 + case 0x0124: 1310 + case 0x0135: 1311 + sony_nc_rfkill_update(); 1312 + break; 1313 + case 0x0137: 1314 + case 0x0143: 1315 + sony_nc_kbd_backlight_resume(); 1316 + break; 1317 + default: 1318 + continue; 1319 + } 1320 + } 1321 + 1322 + /* Enable all events */ 1323 + arg = 0x10; 1324 + if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask)) 1325 + sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask, 1326 + &result); 1283 1327 } 1284 1328 1285 1329 static int sony_nc_resume(struct acpi_device *device) ··· 1462 1166 1463 1167 if (!item->valid) 1464 1168 continue; 1465 - ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, 1466 - item->value, NULL); 1169 + ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, 1170 + &item->value, NULL); 1467 1171 if (ret < 0) { 1468 1172 pr_err("%s: %d\n", __func__, ret); 1469 1173 break; ··· 1472 1176 1473 1177 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", 1474 1178 &handle))) { 1475 - if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) 1179 + int arg = 1; 1180 + if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL)) 1476 1181 dprintk("ECON Method failed\n"); 1477 1182 } 1478 1183 1479 1184 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 1480 - &handle))) { 1481 - dprintk("Doing SNC setup\n"); 1482 - sony_nc_function_setup(device); 1483 - } 1484 - 1485 - /* re-read rfkill state */ 1486 - sony_nc_rfkill_update(); 1487 - 1488 - /* restore kbd backlight states */ 1489 - sony_nc_kbd_backlight_resume(); 1185 + &handle))) 1186 + sony_nc_function_resume(); 1490 1187 1491 1188 return 0; 1492 1189 } ··· 1502 1213 int argument = sony_rfkill_address[(long) data] + 0x100; 1503 1214 1504 1215 if (!blocked) 1505 - argument |= 0xff0000; 1216 + argument |= 0x030000; 1506 1217 1507 1218 return sony_call_snc_handle(sony_rfkill_handle, argument, &result); 1508 1219 } ··· 1519 1230 enum rfkill_type type; 1520 1231 const char *name; 1521 1232 int result; 1522 - bool hwblock; 1233 + bool hwblock, swblock; 1523 1234 1524 1235 switch (nc_type) { 1525 1236 case SONY_WIFI: ··· 1547 1258 if (!rfk) 1548 1259 return -ENOMEM; 1549 1260 1550 - sony_call_snc_handle(sony_rfkill_handle, 0x200, &result); 1261 + if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) { 1262 + rfkill_destroy(rfk); 1263 + return -1; 1264 + } 1551 1265 hwblock = !(result & 0x1); 1266 + 1267 + if (sony_call_snc_handle(sony_rfkill_handle, 1268 + sony_rfkill_address[nc_type], 1269 + &result) < 0) { 1270 + rfkill_destroy(rfk); 1271 + return -1; 1272 + } 1273 + swblock = !(result & 0x2); 1274 + 1275 + rfkill_init_sw_state(rfk, swblock); 1552 1276 rfkill_set_hw_state(rfk, hwblock); 1553 1277 1554 1278 err = rfkill_register(rfk); ··· 1597 1295 1598 1296 sony_call_snc_handle(sony_rfkill_handle, argument, &result); 1599 1297 rfkill_set_states(sony_rfkill_devices[i], 1600 - !(result & 0xf), false); 1298 + !(result & 0x2), false); 1601 1299 } 1602 1300 } 1603 1301 1604 - static void sony_nc_rfkill_setup(struct acpi_device *device) 1302 + static int sony_nc_rfkill_setup(struct acpi_device *device, 1303 + unsigned int handle) 1605 1304 { 1606 - int offset; 1607 - u8 dev_code, i; 1608 - acpi_status status; 1609 - struct acpi_object_list params; 1610 - union acpi_object in_obj; 1611 - union acpi_object *device_enum; 1612 - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 1305 + u64 offset; 1306 + int i; 1307 + unsigned char buffer[32] = { 0 }; 1613 1308 1614 - offset = sony_find_snc_handle(0x124); 1615 - if (offset == -1) { 1616 - offset = sony_find_snc_handle(0x135); 1617 - if (offset == -1) 1618 - return; 1619 - else 1620 - sony_rfkill_handle = 0x135; 1621 - } else 1622 - sony_rfkill_handle = 0x124; 1623 - dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle); 1309 + offset = sony_find_snc_handle(handle); 1310 + sony_rfkill_handle = handle; 1624 1311 1625 - /* need to read the whole buffer returned by the acpi call to SN06 1626 - * here otherwise we may miss some features 1312 + i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer, 1313 + 32); 1314 + if (i < 0) 1315 + return i; 1316 + 1317 + /* The buffer is filled with magic numbers describing the devices 1318 + * available, 0xff terminates the enumeration. 1319 + * Known codes: 1320 + * 0x00 WLAN 1321 + * 0x10 BLUETOOTH 1322 + * 0x20 WWAN GPRS-EDGE 1323 + * 0x21 WWAN HSDPA 1324 + * 0x22 WWAN EV-DO 1325 + * 0x23 WWAN GPS 1326 + * 0x25 Gobi WWAN no GPS 1327 + * 0x26 Gobi WWAN + GPS 1328 + * 0x28 Gobi WWAN no GPS 1329 + * 0x29 Gobi WWAN + GPS 1330 + * 0x30 WIMAX 1331 + * 0x50 Gobi WWAN no GPS 1332 + * 0x51 Gobi WWAN + GPS 1333 + * 0x70 no SIM card slot 1334 + * 0x71 SIM card slot 1627 1335 */ 1628 - params.count = 1; 1629 - params.pointer = &in_obj; 1630 - in_obj.type = ACPI_TYPE_INTEGER; 1631 - in_obj.integer.value = offset; 1632 - status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params, 1633 - &buffer); 1634 - if (ACPI_FAILURE(status)) { 1635 - dprintk("Radio device enumeration failed\n"); 1636 - return; 1637 - } 1336 + for (i = 0; i < ARRAY_SIZE(buffer); i++) { 1638 1337 1639 - device_enum = (union acpi_object *) buffer.pointer; 1640 - if (!device_enum) { 1641 - pr_err("No SN06 return object\n"); 1642 - goto out_no_enum; 1643 - } 1644 - if (device_enum->type != ACPI_TYPE_BUFFER) { 1645 - pr_err("Invalid SN06 return object 0x%.2x\n", 1646 - device_enum->type); 1647 - goto out_no_enum; 1648 - } 1649 - 1650 - /* the buffer is filled with magic numbers describing the devices 1651 - * available, 0xff terminates the enumeration 1652 - */ 1653 - for (i = 0; i < device_enum->buffer.length; i++) { 1654 - 1655 - dev_code = *(device_enum->buffer.pointer + i); 1656 - if (dev_code == 0xff) 1338 + if (buffer[i] == 0xff) 1657 1339 break; 1658 1340 1659 - dprintk("Radio devices, looking at 0x%.2x\n", dev_code); 1341 + dprintk("Radio devices, found 0x%.2x\n", buffer[i]); 1660 1342 1661 - if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI]) 1343 + if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI]) 1662 1344 sony_nc_setup_rfkill(device, SONY_WIFI); 1663 1345 1664 - if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) 1346 + if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH]) 1665 1347 sony_nc_setup_rfkill(device, SONY_BLUETOOTH); 1666 1348 1667 - if ((0xf0 & dev_code) == 0x20 && 1349 + if (((0xf0 & buffer[i]) == 0x20 || 1350 + (0xf0 & buffer[i]) == 0x50) && 1668 1351 !sony_rfkill_devices[SONY_WWAN]) 1669 1352 sony_nc_setup_rfkill(device, SONY_WWAN); 1670 1353 1671 - if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) 1354 + if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX]) 1672 1355 sony_nc_setup_rfkill(device, SONY_WIMAX); 1673 1356 } 1674 - 1675 - out_no_enum: 1676 - kfree(buffer.pointer); 1677 - return; 1357 + return 0; 1678 1358 } 1679 1359 1680 1360 /* Keyboard backlight feature */ 1681 - #define KBDBL_HANDLER 0x137 1682 - #define KBDBL_PRESENT 0xB00 1683 - #define SET_MODE 0xC00 1684 - #define SET_STATE 0xD00 1685 - #define SET_TIMEOUT 0xE00 1686 - 1687 1361 struct kbd_backlight { 1688 - int mode; 1689 - int timeout; 1362 + unsigned int handle; 1363 + unsigned int base; 1364 + unsigned int mode; 1365 + unsigned int timeout; 1690 1366 struct device_attribute mode_attr; 1691 1367 struct device_attribute timeout_attr; 1692 1368 }; 1693 1369 1694 - static struct kbd_backlight *kbdbl_handle; 1370 + static struct kbd_backlight *kbdbl_ctl; 1695 1371 1696 1372 static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value) 1697 1373 { ··· 1678 1398 if (value > 1) 1679 1399 return -EINVAL; 1680 1400 1681 - if (sony_call_snc_handle(KBDBL_HANDLER, 1682 - (value << 0x10) | SET_MODE, &result)) 1401 + if (sony_call_snc_handle(kbdbl_ctl->handle, 1402 + (value << 0x10) | (kbdbl_ctl->base), &result)) 1683 1403 return -EIO; 1684 1404 1685 1405 /* Try to turn the light on/off immediately */ 1686 - sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE, 1687 - &result); 1406 + sony_call_snc_handle(kbdbl_ctl->handle, 1407 + (value << 0x10) | (kbdbl_ctl->base + 0x100), &result); 1688 1408 1689 - kbdbl_handle->mode = value; 1409 + kbdbl_ctl->mode = value; 1690 1410 1691 1411 return 0; 1692 1412 } ··· 1701 1421 if (count > 31) 1702 1422 return -EINVAL; 1703 1423 1704 - if (strict_strtoul(buffer, 10, &value)) 1424 + if (kstrtoul(buffer, 10, &value)) 1705 1425 return -EINVAL; 1706 1426 1707 1427 ret = __sony_nc_kbd_backlight_mode_set(value); ··· 1715 1435 struct device_attribute *attr, char *buffer) 1716 1436 { 1717 1437 ssize_t count = 0; 1718 - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode); 1438 + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode); 1719 1439 return count; 1720 1440 } 1721 1441 ··· 1726 1446 if (value > 3) 1727 1447 return -EINVAL; 1728 1448 1729 - if (sony_call_snc_handle(KBDBL_HANDLER, 1730 - (value << 0x10) | SET_TIMEOUT, &result)) 1449 + if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) | 1450 + (kbdbl_ctl->base + 0x200), &result)) 1731 1451 return -EIO; 1732 1452 1733 - kbdbl_handle->timeout = value; 1453 + kbdbl_ctl->timeout = value; 1734 1454 1735 1455 return 0; 1736 1456 } ··· 1745 1465 if (count > 31) 1746 1466 return -EINVAL; 1747 1467 1748 - if (strict_strtoul(buffer, 10, &value)) 1468 + if (kstrtoul(buffer, 10, &value)) 1749 1469 return -EINVAL; 1750 1470 1751 1471 ret = __sony_nc_kbd_backlight_timeout_set(value); ··· 1759 1479 struct device_attribute *attr, char *buffer) 1760 1480 { 1761 1481 ssize_t count = 0; 1762 - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout); 1482 + count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout); 1763 1483 return count; 1764 1484 } 1765 1485 1766 - static int sony_nc_kbd_backlight_setup(struct platform_device *pd) 1486 + static int sony_nc_kbd_backlight_setup(struct platform_device *pd, 1487 + unsigned int handle) 1767 1488 { 1768 1489 int result; 1490 + int ret = 0; 1769 1491 1770 - if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result)) 1771 - return 0; 1772 - if (!(result & 0x02)) 1773 - return 0; 1492 + /* verify the kbd backlight presence, these handles are not used for 1493 + * keyboard backlight only 1494 + */ 1495 + ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100, 1496 + &result); 1497 + if (ret) 1498 + return ret; 1774 1499 1775 - kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL); 1776 - if (!kbdbl_handle) 1500 + if ((handle == 0x0137 && !(result & 0x02)) || 1501 + !(result & 0x01)) { 1502 + dprintk("no backlight keyboard found\n"); 1503 + return 0; 1504 + } 1505 + 1506 + kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL); 1507 + if (!kbdbl_ctl) 1777 1508 return -ENOMEM; 1778 1509 1779 - sysfs_attr_init(&kbdbl_handle->mode_attr.attr); 1780 - kbdbl_handle->mode_attr.attr.name = "kbd_backlight"; 1781 - kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; 1782 - kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show; 1783 - kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store; 1510 + kbdbl_ctl->handle = handle; 1511 + if (handle == 0x0137) 1512 + kbdbl_ctl->base = 0x0C00; 1513 + else 1514 + kbdbl_ctl->base = 0x4000; 1784 1515 1785 - sysfs_attr_init(&kbdbl_handle->timeout_attr.attr); 1786 - kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout"; 1787 - kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; 1788 - kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; 1789 - kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; 1516 + sysfs_attr_init(&kbdbl_ctl->mode_attr.attr); 1517 + kbdbl_ctl->mode_attr.attr.name = "kbd_backlight"; 1518 + kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR; 1519 + kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show; 1520 + kbdbl_ctl->mode_attr.store = sony_nc_kbd_backlight_mode_store; 1790 1521 1791 - if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr)) 1522 + sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr); 1523 + kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout"; 1524 + kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR; 1525 + kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show; 1526 + kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store; 1527 + 1528 + ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr); 1529 + if (ret) 1792 1530 goto outkzalloc; 1793 1531 1794 - if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr)) 1532 + ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr); 1533 + if (ret) 1795 1534 goto outmode; 1796 1535 1797 1536 __sony_nc_kbd_backlight_mode_set(kbd_backlight); ··· 1819 1520 return 0; 1820 1521 1821 1522 outmode: 1822 - device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1523 + device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); 1823 1524 outkzalloc: 1824 - kfree(kbdbl_handle); 1825 - kbdbl_handle = NULL; 1826 - return -1; 1525 + kfree(kbdbl_ctl); 1526 + kbdbl_ctl = NULL; 1527 + return ret; 1827 1528 } 1828 1529 1829 - static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd) 1530 + static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd) 1830 1531 { 1831 - if (kbdbl_handle) { 1532 + if (kbdbl_ctl) { 1832 1533 int result; 1833 1534 1834 - device_remove_file(&pd->dev, &kbdbl_handle->mode_attr); 1835 - device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr); 1535 + device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr); 1536 + device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr); 1836 1537 1837 1538 /* restore the default hw behaviour */ 1838 - sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result); 1839 - sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result); 1539 + sony_call_snc_handle(kbdbl_ctl->handle, 1540 + kbdbl_ctl->base | 0x10000, &result); 1541 + sony_call_snc_handle(kbdbl_ctl->handle, 1542 + kbdbl_ctl->base + 0x200, &result); 1840 1543 1841 - kfree(kbdbl_handle); 1544 + kfree(kbdbl_ctl); 1545 + kbdbl_ctl = NULL; 1842 1546 } 1843 - return 0; 1844 1547 } 1845 1548 1846 1549 static void sony_nc_kbd_backlight_resume(void) 1847 1550 { 1848 1551 int ignore = 0; 1849 1552 1850 - if (!kbdbl_handle) 1553 + if (!kbdbl_ctl) 1851 1554 return; 1852 1555 1853 - if (kbdbl_handle->mode == 0) 1854 - sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore); 1855 - 1856 - if (kbdbl_handle->timeout != 0) 1857 - sony_call_snc_handle(KBDBL_HANDLER, 1858 - (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT, 1556 + if (kbdbl_ctl->mode == 0) 1557 + sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base, 1859 1558 &ignore); 1559 + 1560 + if (kbdbl_ctl->timeout != 0) 1561 + sony_call_snc_handle(kbdbl_ctl->handle, 1562 + (kbdbl_ctl->base + 0x200) | 1563 + (kbdbl_ctl->timeout << 0x10), &ignore); 1564 + } 1565 + 1566 + struct battery_care_control { 1567 + struct device_attribute attrs[2]; 1568 + unsigned int handle; 1569 + }; 1570 + static struct battery_care_control *bcare_ctl; 1571 + 1572 + static ssize_t sony_nc_battery_care_limit_store(struct device *dev, 1573 + struct device_attribute *attr, 1574 + const char *buffer, size_t count) 1575 + { 1576 + unsigned int result, cmd; 1577 + unsigned long value; 1578 + 1579 + if (count > 31) 1580 + return -EINVAL; 1581 + 1582 + if (kstrtoul(buffer, 10, &value)) 1583 + return -EINVAL; 1584 + 1585 + /* limit values (2 bits): 1586 + * 00 - none 1587 + * 01 - 80% 1588 + * 10 - 50% 1589 + * 11 - 100% 1590 + * 1591 + * bit 0: 0 disable BCL, 1 enable BCL 1592 + * bit 1: 1 tell to store the battery limit (see bits 6,7) too 1593 + * bits 2,3: reserved 1594 + * bits 4,5: store the limit into the EC 1595 + * bits 6,7: store the limit into the battery 1596 + */ 1597 + 1598 + /* 1599 + * handle 0x0115 should allow storing on battery too; 1600 + * handle 0x0136 same as 0x0115 + health status; 1601 + * handle 0x013f, same as 0x0136 but no storing on the battery 1602 + * 1603 + * Store only inside the EC for now, regardless the handle number 1604 + */ 1605 + if (value == 0) 1606 + /* disable limits */ 1607 + cmd = 0x0; 1608 + 1609 + else if (value <= 50) 1610 + cmd = 0x21; 1611 + 1612 + else if (value <= 80) 1613 + cmd = 0x11; 1614 + 1615 + else if (value <= 100) 1616 + cmd = 0x31; 1617 + 1618 + else 1619 + return -EINVAL; 1620 + 1621 + if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100, 1622 + &result)) 1623 + return -EIO; 1624 + 1625 + return count; 1626 + } 1627 + 1628 + static ssize_t sony_nc_battery_care_limit_show(struct device *dev, 1629 + struct device_attribute *attr, char *buffer) 1630 + { 1631 + unsigned int result, status; 1632 + 1633 + if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result)) 1634 + return -EIO; 1635 + 1636 + status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0; 1637 + switch (status) { 1638 + case 1: 1639 + status = 80; 1640 + break; 1641 + case 2: 1642 + status = 50; 1643 + break; 1644 + case 3: 1645 + status = 100; 1646 + break; 1647 + default: 1648 + status = 0; 1649 + break; 1650 + } 1651 + 1652 + return snprintf(buffer, PAGE_SIZE, "%d\n", status); 1653 + } 1654 + 1655 + static ssize_t sony_nc_battery_care_health_show(struct device *dev, 1656 + struct device_attribute *attr, char *buffer) 1657 + { 1658 + ssize_t count = 0; 1659 + unsigned int health; 1660 + 1661 + if (sony_call_snc_handle(bcare_ctl->handle, 0x0200, &health)) 1662 + return -EIO; 1663 + 1664 + count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff); 1665 + 1666 + return count; 1667 + } 1668 + 1669 + static int sony_nc_battery_care_setup(struct platform_device *pd, 1670 + unsigned int handle) 1671 + { 1672 + int ret = 0; 1673 + 1674 + bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL); 1675 + if (!bcare_ctl) 1676 + return -ENOMEM; 1677 + 1678 + bcare_ctl->handle = handle; 1679 + 1680 + sysfs_attr_init(&bcare_ctl->attrs[0].attr); 1681 + bcare_ctl->attrs[0].attr.name = "battery_care_limiter"; 1682 + bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR; 1683 + bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show; 1684 + bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store; 1685 + 1686 + ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]); 1687 + if (ret) 1688 + goto outkzalloc; 1689 + 1690 + /* 0x0115 is for models with no health reporting capability */ 1691 + if (handle == 0x0115) 1692 + return 0; 1693 + 1694 + sysfs_attr_init(&bcare_ctl->attrs[1].attr); 1695 + bcare_ctl->attrs[1].attr.name = "battery_care_health"; 1696 + bcare_ctl->attrs[1].attr.mode = S_IRUGO; 1697 + bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show; 1698 + 1699 + ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]); 1700 + if (ret) 1701 + goto outlimiter; 1702 + 1703 + return 0; 1704 + 1705 + outlimiter: 1706 + device_remove_file(&pd->dev, &bcare_ctl->attrs[0]); 1707 + 1708 + outkzalloc: 1709 + kfree(bcare_ctl); 1710 + bcare_ctl = NULL; 1711 + 1712 + return ret; 1713 + } 1714 + 1715 + static void sony_nc_battery_care_cleanup(struct platform_device *pd) 1716 + { 1717 + if (bcare_ctl) { 1718 + device_remove_file(&pd->dev, &bcare_ctl->attrs[0]); 1719 + if (bcare_ctl->handle != 0x0115) 1720 + device_remove_file(&pd->dev, &bcare_ctl->attrs[1]); 1721 + 1722 + kfree(bcare_ctl); 1723 + bcare_ctl = NULL; 1724 + } 1725 + } 1726 + 1727 + struct snc_thermal_ctrl { 1728 + unsigned int mode; 1729 + unsigned int profiles; 1730 + struct device_attribute mode_attr; 1731 + struct device_attribute profiles_attr; 1732 + }; 1733 + static struct snc_thermal_ctrl *th_handle; 1734 + 1735 + #define THM_PROFILE_MAX 3 1736 + static const char * const snc_thermal_profiles[] = { 1737 + "balanced", 1738 + "silent", 1739 + "performance" 1740 + }; 1741 + 1742 + static int sony_nc_thermal_mode_set(unsigned short mode) 1743 + { 1744 + unsigned int result; 1745 + 1746 + /* the thermal profile seems to be a two bit bitmask: 1747 + * lsb -> silent 1748 + * msb -> performance 1749 + * no bit set is the normal operation and is always valid 1750 + * Some vaio models only have "balanced" and "performance" 1751 + */ 1752 + if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX) 1753 + return -EINVAL; 1754 + 1755 + if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result)) 1756 + return -EIO; 1757 + 1758 + th_handle->mode = mode; 1759 + 1760 + return 0; 1761 + } 1762 + 1763 + static int sony_nc_thermal_mode_get(void) 1764 + { 1765 + unsigned int result; 1766 + 1767 + if (sony_call_snc_handle(0x0122, 0x0100, &result)) 1768 + return -EIO; 1769 + 1770 + return result & 0xff; 1771 + } 1772 + 1773 + static ssize_t sony_nc_thermal_profiles_show(struct device *dev, 1774 + struct device_attribute *attr, char *buffer) 1775 + { 1776 + short cnt; 1777 + size_t idx = 0; 1778 + 1779 + for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) { 1780 + if (!cnt || (th_handle->profiles & cnt)) 1781 + idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ", 1782 + snc_thermal_profiles[cnt]); 1783 + } 1784 + idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n"); 1785 + 1786 + return idx; 1787 + } 1788 + 1789 + static ssize_t sony_nc_thermal_mode_store(struct device *dev, 1790 + struct device_attribute *attr, 1791 + const char *buffer, size_t count) 1792 + { 1793 + unsigned short cmd; 1794 + size_t len = count; 1795 + 1796 + if (count == 0) 1797 + return -EINVAL; 1798 + 1799 + /* skip the newline if present */ 1800 + if (buffer[len - 1] == '\n') 1801 + len--; 1802 + 1803 + for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++) 1804 + if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0) 1805 + break; 1806 + 1807 + if (sony_nc_thermal_mode_set(cmd)) 1808 + return -EIO; 1809 + 1810 + return count; 1811 + } 1812 + 1813 + static ssize_t sony_nc_thermal_mode_show(struct device *dev, 1814 + struct device_attribute *attr, char *buffer) 1815 + { 1816 + ssize_t count = 0; 1817 + unsigned int mode = sony_nc_thermal_mode_get(); 1818 + 1819 + if (mode < 0) 1820 + return mode; 1821 + 1822 + count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]); 1823 + 1824 + return count; 1825 + } 1826 + 1827 + static int sony_nc_thermal_setup(struct platform_device *pd) 1828 + { 1829 + int ret = 0; 1830 + th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL); 1831 + if (!th_handle) 1832 + return -ENOMEM; 1833 + 1834 + ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles); 1835 + if (ret) { 1836 + pr_warn("couldn't to read the thermal profiles\n"); 1837 + goto outkzalloc; 1838 + } 1839 + 1840 + ret = sony_nc_thermal_mode_get(); 1841 + if (ret < 0) { 1842 + pr_warn("couldn't to read the current thermal profile"); 1843 + goto outkzalloc; 1844 + } 1845 + th_handle->mode = ret; 1846 + 1847 + sysfs_attr_init(&th_handle->profiles_attr.attr); 1848 + th_handle->profiles_attr.attr.name = "thermal_profiles"; 1849 + th_handle->profiles_attr.attr.mode = S_IRUGO; 1850 + th_handle->profiles_attr.show = sony_nc_thermal_profiles_show; 1851 + 1852 + sysfs_attr_init(&th_handle->mode_attr.attr); 1853 + th_handle->mode_attr.attr.name = "thermal_control"; 1854 + th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR; 1855 + th_handle->mode_attr.show = sony_nc_thermal_mode_show; 1856 + th_handle->mode_attr.store = sony_nc_thermal_mode_store; 1857 + 1858 + ret = device_create_file(&pd->dev, &th_handle->profiles_attr); 1859 + if (ret) 1860 + goto outkzalloc; 1861 + 1862 + ret = device_create_file(&pd->dev, &th_handle->mode_attr); 1863 + if (ret) 1864 + goto outprofiles; 1865 + 1866 + return 0; 1867 + 1868 + outprofiles: 1869 + device_remove_file(&pd->dev, &th_handle->profiles_attr); 1870 + outkzalloc: 1871 + kfree(th_handle); 1872 + th_handle = NULL; 1873 + return ret; 1874 + } 1875 + 1876 + static void sony_nc_thermal_cleanup(struct platform_device *pd) 1877 + { 1878 + if (th_handle) { 1879 + device_remove_file(&pd->dev, &th_handle->profiles_attr); 1880 + device_remove_file(&pd->dev, &th_handle->mode_attr); 1881 + kfree(th_handle); 1882 + th_handle = NULL; 1883 + } 1884 + } 1885 + 1886 + static void sony_nc_thermal_resume(void) 1887 + { 1888 + unsigned int status = sony_nc_thermal_mode_get(); 1889 + 1890 + if (status != th_handle->mode) 1891 + sony_nc_thermal_mode_set(th_handle->mode); 1892 + } 1893 + 1894 + /* resume on LID open */ 1895 + struct snc_lid_resume_control { 1896 + struct device_attribute attrs[3]; 1897 + unsigned int status; 1898 + }; 1899 + static struct snc_lid_resume_control *lid_ctl; 1900 + 1901 + static ssize_t sony_nc_lid_resume_store(struct device *dev, 1902 + struct device_attribute *attr, 1903 + const char *buffer, size_t count) 1904 + { 1905 + unsigned int result, pos; 1906 + unsigned long value; 1907 + if (count > 31) 1908 + return -EINVAL; 1909 + 1910 + if (kstrtoul(buffer, 10, &value) || value > 1) 1911 + return -EINVAL; 1912 + 1913 + /* the value we have to write to SNC is a bitmask: 1914 + * +--------------+ 1915 + * | S3 | S4 | S5 | 1916 + * +--------------+ 1917 + * 2 1 0 1918 + */ 1919 + if (strcmp(attr->attr.name, "lid_resume_S3") == 0) 1920 + pos = 2; 1921 + else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) 1922 + pos = 1; 1923 + else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) 1924 + pos = 0; 1925 + else 1926 + return -EINVAL; 1927 + 1928 + if (value) 1929 + value = lid_ctl->status | (1 << pos); 1930 + else 1931 + value = lid_ctl->status & ~(1 << pos); 1932 + 1933 + if (sony_call_snc_handle(0x0119, value << 0x10 | 0x0100, &result)) 1934 + return -EIO; 1935 + 1936 + lid_ctl->status = value; 1937 + 1938 + return count; 1939 + } 1940 + 1941 + static ssize_t sony_nc_lid_resume_show(struct device *dev, 1942 + struct device_attribute *attr, char *buffer) 1943 + { 1944 + unsigned int pos; 1945 + 1946 + if (strcmp(attr->attr.name, "lid_resume_S3") == 0) 1947 + pos = 2; 1948 + else if (strcmp(attr->attr.name, "lid_resume_S4") == 0) 1949 + pos = 1; 1950 + else if (strcmp(attr->attr.name, "lid_resume_S5") == 0) 1951 + pos = 0; 1952 + else 1953 + return -EINVAL; 1954 + 1955 + return snprintf(buffer, PAGE_SIZE, "%d\n", 1956 + (lid_ctl->status >> pos) & 0x01); 1957 + } 1958 + 1959 + static int sony_nc_lid_resume_setup(struct platform_device *pd) 1960 + { 1961 + unsigned int result; 1962 + int i; 1963 + 1964 + if (sony_call_snc_handle(0x0119, 0x0000, &result)) 1965 + return -EIO; 1966 + 1967 + lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL); 1968 + if (!lid_ctl) 1969 + return -ENOMEM; 1970 + 1971 + lid_ctl->status = result & 0x7; 1972 + 1973 + sysfs_attr_init(&lid_ctl->attrs[0].attr); 1974 + lid_ctl->attrs[0].attr.name = "lid_resume_S3"; 1975 + lid_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR; 1976 + lid_ctl->attrs[0].show = sony_nc_lid_resume_show; 1977 + lid_ctl->attrs[0].store = sony_nc_lid_resume_store; 1978 + 1979 + sysfs_attr_init(&lid_ctl->attrs[1].attr); 1980 + lid_ctl->attrs[1].attr.name = "lid_resume_S4"; 1981 + lid_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR; 1982 + lid_ctl->attrs[1].show = sony_nc_lid_resume_show; 1983 + lid_ctl->attrs[1].store = sony_nc_lid_resume_store; 1984 + 1985 + sysfs_attr_init(&lid_ctl->attrs[2].attr); 1986 + lid_ctl->attrs[2].attr.name = "lid_resume_S5"; 1987 + lid_ctl->attrs[2].attr.mode = S_IRUGO | S_IWUSR; 1988 + lid_ctl->attrs[2].show = sony_nc_lid_resume_show; 1989 + lid_ctl->attrs[2].store = sony_nc_lid_resume_store; 1990 + 1991 + for (i = 0; i < 3; i++) { 1992 + result = device_create_file(&pd->dev, &lid_ctl->attrs[i]); 1993 + if (result) 1994 + goto liderror; 1995 + } 1996 + 1997 + return 0; 1998 + 1999 + liderror: 2000 + for (; i > 0; i--) 2001 + device_remove_file(&pd->dev, &lid_ctl->attrs[i]); 2002 + 2003 + kfree(lid_ctl); 2004 + lid_ctl = NULL; 2005 + 2006 + return result; 2007 + } 2008 + 2009 + static void sony_nc_lid_resume_cleanup(struct platform_device *pd) 2010 + { 2011 + int i; 2012 + 2013 + if (lid_ctl) { 2014 + for (i = 0; i < 3; i++) 2015 + device_remove_file(&pd->dev, &lid_ctl->attrs[i]); 2016 + 2017 + kfree(lid_ctl); 2018 + lid_ctl = NULL; 2019 + } 2020 + } 2021 + 2022 + /* High speed charging function */ 2023 + static struct device_attribute *hsc_handle; 2024 + 2025 + static ssize_t sony_nc_highspeed_charging_store(struct device *dev, 2026 + struct device_attribute *attr, 2027 + const char *buffer, size_t count) 2028 + { 2029 + unsigned int result; 2030 + unsigned long value; 2031 + 2032 + if (count > 31) 2033 + return -EINVAL; 2034 + 2035 + if (kstrtoul(buffer, 10, &value) || value > 1) 2036 + return -EINVAL; 2037 + 2038 + if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result)) 2039 + return -EIO; 2040 + 2041 + return count; 2042 + } 2043 + 2044 + static ssize_t sony_nc_highspeed_charging_show(struct device *dev, 2045 + struct device_attribute *attr, char *buffer) 2046 + { 2047 + unsigned int result; 2048 + 2049 + if (sony_call_snc_handle(0x0131, 0x0100, &result)) 2050 + return -EIO; 2051 + 2052 + return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01); 2053 + } 2054 + 2055 + static int sony_nc_highspeed_charging_setup(struct platform_device *pd) 2056 + { 2057 + unsigned int result; 2058 + 2059 + if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) { 2060 + /* some models advertise the handle but have no implementation 2061 + * for it 2062 + */ 2063 + pr_info("No High Speed Charging capability found\n"); 2064 + return 0; 2065 + } 2066 + 2067 + hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL); 2068 + if (!hsc_handle) 2069 + return -ENOMEM; 2070 + 2071 + sysfs_attr_init(&hsc_handle->attr); 2072 + hsc_handle->attr.name = "battery_highspeed_charging"; 2073 + hsc_handle->attr.mode = S_IRUGO | S_IWUSR; 2074 + hsc_handle->show = sony_nc_highspeed_charging_show; 2075 + hsc_handle->store = sony_nc_highspeed_charging_store; 2076 + 2077 + result = device_create_file(&pd->dev, hsc_handle); 2078 + if (result) { 2079 + kfree(hsc_handle); 2080 + hsc_handle = NULL; 2081 + return result; 2082 + } 2083 + 2084 + return 0; 2085 + } 2086 + 2087 + static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd) 2088 + { 2089 + if (hsc_handle) { 2090 + device_remove_file(&pd->dev, hsc_handle); 2091 + kfree(hsc_handle); 2092 + hsc_handle = NULL; 2093 + } 2094 + } 2095 + 2096 + /* Touchpad enable/disable */ 2097 + struct touchpad_control { 2098 + struct device_attribute attr; 2099 + int handle; 2100 + }; 2101 + static struct touchpad_control *tp_ctl; 2102 + 2103 + static ssize_t sony_nc_touchpad_store(struct device *dev, 2104 + struct device_attribute *attr, const char *buffer, size_t count) 2105 + { 2106 + unsigned int result; 2107 + unsigned long value; 2108 + 2109 + if (count > 31) 2110 + return -EINVAL; 2111 + 2112 + if (kstrtoul(buffer, 10, &value) || value > 1) 2113 + return -EINVAL; 2114 + 2115 + /* sysfs: 0 disabled, 1 enabled 2116 + * EC: 0 enabled, 1 disabled 2117 + */ 2118 + if (sony_call_snc_handle(tp_ctl->handle, 2119 + (!value << 0x10) | 0x100, &result)) 2120 + return -EIO; 2121 + 2122 + return count; 2123 + } 2124 + 2125 + static ssize_t sony_nc_touchpad_show(struct device *dev, 2126 + struct device_attribute *attr, char *buffer) 2127 + { 2128 + unsigned int result; 2129 + 2130 + if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result)) 2131 + return -EINVAL; 2132 + 2133 + return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01)); 2134 + } 2135 + 2136 + static int sony_nc_touchpad_setup(struct platform_device *pd, 2137 + unsigned int handle) 2138 + { 2139 + int ret = 0; 2140 + 2141 + tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL); 2142 + if (!tp_ctl) 2143 + return -ENOMEM; 2144 + 2145 + tp_ctl->handle = handle; 2146 + 2147 + sysfs_attr_init(&tp_ctl->attr.attr); 2148 + tp_ctl->attr.attr.name = "touchpad"; 2149 + tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR; 2150 + tp_ctl->attr.show = sony_nc_touchpad_show; 2151 + tp_ctl->attr.store = sony_nc_touchpad_store; 2152 + 2153 + ret = device_create_file(&pd->dev, &tp_ctl->attr); 2154 + if (ret) { 2155 + kfree(tp_ctl); 2156 + tp_ctl = NULL; 2157 + } 2158 + 2159 + return ret; 2160 + } 2161 + 2162 + static void sony_nc_touchpad_cleanup(struct platform_device *pd) 2163 + { 2164 + if (tp_ctl) { 2165 + device_remove_file(&pd->dev, &tp_ctl->attr); 2166 + kfree(tp_ctl); 2167 + tp_ctl = NULL; 2168 + } 1860 2169 } 1861 2170 1862 2171 static void sony_nc_backlight_ng_read_limits(int handle, 1863 2172 struct sony_backlight_props *props) 1864 2173 { 1865 - int offset; 1866 - acpi_status status; 1867 - u8 brlvl, i; 2174 + u64 offset; 2175 + int i; 1868 2176 u8 min = 0xff, max = 0x00; 1869 - struct acpi_object_list params; 1870 - union acpi_object in_obj; 1871 - union acpi_object *lvl_enum; 1872 - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; 2177 + unsigned char buffer[32] = { 0 }; 1873 2178 1874 2179 props->handle = handle; 1875 2180 props->offset = 0; ··· 2486 1583 /* try to read the boundaries from ACPI tables, if we fail the above 2487 1584 * defaults should be reasonable 2488 1585 */ 2489 - params.count = 1; 2490 - params.pointer = &in_obj; 2491 - in_obj.type = ACPI_TYPE_INTEGER; 2492 - in_obj.integer.value = offset; 2493 - status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params, 2494 - &buffer); 2495 - if (ACPI_FAILURE(status)) 1586 + i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer, 1587 + 32); 1588 + if (i < 0) 2496 1589 return; 2497 - 2498 - lvl_enum = (union acpi_object *) buffer.pointer; 2499 - if (!lvl_enum) { 2500 - pr_err("No SN06 return object."); 2501 - return; 2502 - } 2503 - if (lvl_enum->type != ACPI_TYPE_BUFFER) { 2504 - pr_err("Invalid SN06 return object 0x%.2x\n", 2505 - lvl_enum->type); 2506 - goto out_invalid; 2507 - } 2508 1590 2509 1591 /* the buffer lists brightness levels available, brightness levels are 2510 - * from 0 to 8 in the array, other values are used by ALS control. 1592 + * from position 0 to 8 in the array, other values are used by ALS 1593 + * control. 2511 1594 */ 2512 - for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) { 1595 + for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) { 2513 1596 2514 - brlvl = *(lvl_enum->buffer.pointer + i); 2515 - dprintk("Brightness level: %d\n", brlvl); 1597 + dprintk("Brightness level: %d\n", buffer[i]); 2516 1598 2517 - if (!brlvl) 1599 + if (!buffer[i]) 2518 1600 break; 2519 1601 2520 - if (brlvl > max) 2521 - max = brlvl; 2522 - if (brlvl < min) 2523 - min = brlvl; 1602 + if (buffer[i] > max) 1603 + max = buffer[i]; 1604 + if (buffer[i] < min) 1605 + min = buffer[i]; 2524 1606 } 2525 1607 props->offset = min; 2526 1608 props->maxlvl = max; 2527 1609 dprintk("Brightness levels: min=%d max=%d\n", props->offset, 2528 1610 props->maxlvl); 2529 - 2530 - out_invalid: 2531 - kfree(buffer.pointer); 2532 - return; 2533 1611 } 2534 1612 2535 1613 static void sony_nc_backlight_setup(void) ··· 2599 1715 2600 1716 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON", 2601 1717 &handle))) { 2602 - if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL)) 1718 + int arg = 1; 1719 + if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL)) 2603 1720 dprintk("ECON Method failed\n"); 2604 1721 } 2605 1722 2606 1723 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00", 2607 1724 &handle))) { 2608 1725 dprintk("Doing SNC setup\n"); 1726 + /* retrieve the available handles */ 2609 1727 result = sony_nc_handles_setup(sony_pf_device); 2610 - if (result) 2611 - goto outpresent; 2612 - result = sony_nc_kbd_backlight_setup(sony_pf_device); 2613 - if (result) 2614 - goto outsnc; 2615 - sony_nc_function_setup(device); 2616 - sony_nc_rfkill_setup(device); 1728 + if (!result) 1729 + sony_nc_function_setup(device, sony_pf_device); 2617 1730 } 2618 1731 2619 1732 /* setup input devices and helper fifo */ 2620 1733 result = sony_laptop_setup_input(device); 2621 1734 if (result) { 2622 1735 pr_err("Unable to create input devices\n"); 2623 - goto outkbdbacklight; 1736 + goto outsnc; 2624 1737 } 2625 1738 2626 1739 if (acpi_video_backlight_support()) { ··· 2675 1794 2676 1795 sony_laptop_remove_input(); 2677 1796 2678 - outkbdbacklight: 2679 - sony_nc_kbd_backlight_cleanup(sony_pf_device); 2680 - 2681 1797 outsnc: 1798 + sony_nc_function_cleanup(sony_pf_device); 2682 1799 sony_nc_handles_cleanup(sony_pf_device); 2683 1800 2684 1801 outpresent: ··· 2699 1820 device_remove_file(&sony_pf_device->dev, &item->devattr); 2700 1821 } 2701 1822 2702 - sony_nc_kbd_backlight_cleanup(sony_pf_device); 1823 + sony_nc_function_cleanup(sony_pf_device); 2703 1824 sony_nc_handles_cleanup(sony_pf_device); 2704 1825 sony_pf_remove(); 2705 1826 sony_laptop_remove_input(); 2706 - sony_nc_rfkill_cleanup(); 2707 1827 dprintk(SONY_NC_DRIVER_NAME " removed.\n"); 2708 1828 2709 1829 return 0; ··· 3315 2437 if (count > 31) 3316 2438 return -EINVAL; 3317 2439 3318 - value = simple_strtoul(buffer, NULL, 10); 2440 + if (kstrtoul(buffer, 10, &value)) 2441 + return -EINVAL; 2442 + 3319 2443 mutex_lock(&spic_dev.lock); 3320 2444 __sony_pic_set_wwanpower(value); 3321 2445 mutex_unlock(&spic_dev.lock); ··· 3354 2474 if (count > 31) 3355 2475 return -EINVAL; 3356 2476 3357 - value = simple_strtoul(buffer, NULL, 10); 2477 + if (kstrtoul(buffer, 10, &value)) 2478 + return -EINVAL; 2479 + 3358 2480 mutex_lock(&spic_dev.lock); 3359 2481 __sony_pic_set_bluetoothpower(value); 3360 2482 mutex_unlock(&spic_dev.lock); ··· 3395 2513 if (count > 31) 3396 2514 return -EINVAL; 3397 2515 3398 - value = simple_strtoul(buffer, NULL, 10); 2516 + if (kstrtoul(buffer, 10, &value)) 2517 + return -EINVAL; 2518 + 3399 2519 if (sony_pic_set_fanspeed(value)) 3400 2520 return -EIO; 3401 2521 ··· 3555 2671 ret = -EIO; 3556 2672 break; 3557 2673 } 3558 - if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) { 2674 + if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, 2675 + &value)) { 3559 2676 ret = -EIO; 3560 2677 break; 3561 2678 } ··· 3573 2688 ret = -EFAULT; 3574 2689 break; 3575 2690 } 3576 - if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", 3577 - (val8 >> 5) + 1, NULL)) { 2691 + value = (val8 >> 5) + 1; 2692 + if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value, 2693 + NULL)) { 3578 2694 ret = -EIO; 3579 2695 break; 3580 2696 }
+1 -1
drivers/platform/x86/thinkpad_acpi.c
··· 3402 3402 /* Do not issue duplicate brightness change events to 3403 3403 * userspace. tpacpi_detect_brightness_capabilities() must have 3404 3404 * been called before this point */ 3405 - if (tp_features.bright_acpimode && acpi_video_backlight_support()) { 3405 + if (acpi_video_backlight_support()) { 3406 3406 pr_info("This ThinkPad has standard ACPI backlight " 3407 3407 "brightness control, supported by the ACPI " 3408 3408 "video driver\n");
+113 -28
drivers/platform/x86/toshiba_acpi.c
··· 95 95 96 96 /* registers */ 97 97 #define HCI_FAN 0x0004 98 + #define HCI_TR_BACKLIGHT 0x0005 98 99 #define HCI_SYSTEM_EVENT 0x0016 99 100 #define HCI_VIDEO_OUT 0x001c 100 101 #define HCI_HOTKEY_EVENT 0x001e ··· 135 134 unsigned int system_event_supported:1; 136 135 unsigned int ntfy_supported:1; 137 136 unsigned int info_supported:1; 137 + unsigned int tr_backlight_supported:1; 138 138 139 139 struct mutex mutex; 140 140 }; ··· 480 478 .poll = bt_rfkill_poll, 481 479 }; 482 480 481 + static int get_tr_backlight_status(struct toshiba_acpi_dev *dev, bool *enabled) 482 + { 483 + u32 hci_result; 484 + u32 status; 485 + 486 + hci_read1(dev, HCI_TR_BACKLIGHT, &status, &hci_result); 487 + *enabled = !status; 488 + return hci_result == HCI_SUCCESS ? 0 : -EIO; 489 + } 490 + 491 + static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable) 492 + { 493 + u32 hci_result; 494 + u32 value = !enable; 495 + 496 + hci_write1(dev, HCI_TR_BACKLIGHT, value, &hci_result); 497 + return hci_result == HCI_SUCCESS ? 0 : -EIO; 498 + } 499 + 483 500 static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ; 484 501 485 - static int get_lcd(struct backlight_device *bd) 502 + static int __get_lcd_brightness(struct toshiba_acpi_dev *dev) 486 503 { 487 - struct toshiba_acpi_dev *dev = bl_get_data(bd); 488 504 u32 hci_result; 489 505 u32 value; 506 + int brightness = 0; 507 + 508 + if (dev->tr_backlight_supported) { 509 + bool enabled; 510 + int ret = get_tr_backlight_status(dev, &enabled); 511 + if (ret) 512 + return ret; 513 + if (enabled) 514 + return 0; 515 + brightness++; 516 + } 490 517 491 518 hci_read1(dev, HCI_LCD_BRIGHTNESS, &value, &hci_result); 492 519 if (hci_result == HCI_SUCCESS) 493 - return (value >> HCI_LCD_BRIGHTNESS_SHIFT); 520 + return brightness + (value >> HCI_LCD_BRIGHTNESS_SHIFT); 494 521 495 522 return -EIO; 523 + } 524 + 525 + static int get_lcd_brightness(struct backlight_device *bd) 526 + { 527 + struct toshiba_acpi_dev *dev = bl_get_data(bd); 528 + return __get_lcd_brightness(dev); 496 529 } 497 530 498 531 static int lcd_proc_show(struct seq_file *m, void *v) 499 532 { 500 533 struct toshiba_acpi_dev *dev = m->private; 501 534 int value; 535 + int levels; 502 536 503 537 if (!dev->backlight_dev) 504 538 return -ENODEV; 505 539 506 - value = get_lcd(dev->backlight_dev); 540 + levels = dev->backlight_dev->props.max_brightness + 1; 541 + value = get_lcd_brightness(dev->backlight_dev); 507 542 if (value >= 0) { 508 543 seq_printf(m, "brightness: %d\n", value); 509 - seq_printf(m, "brightness_levels: %d\n", 510 - HCI_LCD_BRIGHTNESS_LEVELS); 544 + seq_printf(m, "brightness_levels: %d\n", levels); 511 545 return 0; 512 546 } 513 547 ··· 556 518 return single_open(file, lcd_proc_show, PDE(inode)->data); 557 519 } 558 520 559 - static int set_lcd(struct toshiba_acpi_dev *dev, int value) 521 + static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value) 560 522 { 561 523 u32 hci_result; 524 + 525 + if (dev->tr_backlight_supported) { 526 + bool enable = !value; 527 + int ret = set_tr_backlight_status(dev, enable); 528 + if (ret) 529 + return ret; 530 + if (value) 531 + value--; 532 + } 562 533 563 534 value = value << HCI_LCD_BRIGHTNESS_SHIFT; 564 535 hci_write1(dev, HCI_LCD_BRIGHTNESS, value, &hci_result); ··· 577 530 static int set_lcd_status(struct backlight_device *bd) 578 531 { 579 532 struct toshiba_acpi_dev *dev = bl_get_data(bd); 580 - return set_lcd(dev, bd->props.brightness); 533 + return set_lcd_brightness(dev, bd->props.brightness); 581 534 } 582 535 583 536 static ssize_t lcd_proc_write(struct file *file, const char __user *buf, ··· 588 541 size_t len; 589 542 int value; 590 543 int ret; 544 + int levels = dev->backlight_dev->props.max_brightness + 1; 591 545 592 546 len = min(count, sizeof(cmd) - 1); 593 547 if (copy_from_user(cmd, buf, len)) ··· 596 548 cmd[len] = '\0'; 597 549 598 550 if (sscanf(cmd, " brightness : %i", &value) == 1 && 599 - value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) { 600 - ret = set_lcd(dev, value); 551 + value >= 0 && value < levels) { 552 + ret = set_lcd_brightness(dev, value); 601 553 if (ret == 0) 602 554 ret = count; 603 555 } else { ··· 908 860 } 909 861 910 862 static const struct backlight_ops toshiba_backlight_data = { 911 - .get_brightness = get_lcd, 912 - .update_status = set_lcd_status, 863 + .options = BL_CORE_SUSPENDRESUME, 864 + .get_brightness = get_lcd_brightness, 865 + .update_status = set_lcd_status, 913 866 }; 914 867 915 868 static bool toshiba_acpi_i8042_filter(unsigned char data, unsigned char str, ··· 1069 1020 return error; 1070 1021 } 1071 1022 1023 + static int __devinit toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev) 1024 + { 1025 + struct backlight_properties props; 1026 + int brightness; 1027 + int ret; 1028 + bool enabled; 1029 + 1030 + /* 1031 + * Some machines don't support the backlight methods at all, and 1032 + * others support it read-only. Either of these is pretty useless, 1033 + * so only register the backlight device if the backlight method 1034 + * supports both reads and writes. 1035 + */ 1036 + brightness = __get_lcd_brightness(dev); 1037 + if (brightness < 0) 1038 + return 0; 1039 + ret = set_lcd_brightness(dev, brightness); 1040 + if (ret) { 1041 + pr_debug("Backlight method is read-only, disabling backlight support\n"); 1042 + return 0; 1043 + } 1044 + 1045 + /* Determine whether or not BIOS supports transflective backlight */ 1046 + ret = get_tr_backlight_status(dev, &enabled); 1047 + dev->tr_backlight_supported = !ret; 1048 + 1049 + memset(&props, 0, sizeof(props)); 1050 + props.type = BACKLIGHT_PLATFORM; 1051 + props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 1052 + 1053 + /* adding an extra level and having 0 change to transflective mode */ 1054 + if (dev->tr_backlight_supported) 1055 + props.max_brightness++; 1056 + 1057 + dev->backlight_dev = backlight_device_register("toshiba", 1058 + &dev->acpi_dev->dev, 1059 + dev, 1060 + &toshiba_backlight_data, 1061 + &props); 1062 + if (IS_ERR(dev->backlight_dev)) { 1063 + ret = PTR_ERR(dev->backlight_dev); 1064 + pr_err("Could not register toshiba backlight device\n"); 1065 + dev->backlight_dev = NULL; 1066 + return ret; 1067 + } 1068 + 1069 + dev->backlight_dev->props.brightness = brightness; 1070 + return 0; 1071 + } 1072 + 1072 1073 static int toshiba_acpi_remove(struct acpi_device *acpi_dev, int type) 1073 1074 { 1074 1075 struct toshiba_acpi_dev *dev = acpi_driver_data(acpi_dev); ··· 1177 1078 u32 dummy; 1178 1079 bool bt_present; 1179 1080 int ret = 0; 1180 - struct backlight_properties props; 1181 1081 1182 1082 if (toshiba_acpi) 1183 1083 return -EBUSY; ··· 1202 1104 1203 1105 mutex_init(&dev->mutex); 1204 1106 1205 - memset(&props, 0, sizeof(props)); 1206 - props.type = BACKLIGHT_PLATFORM; 1207 - props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1; 1208 - dev->backlight_dev = backlight_device_register("toshiba", 1209 - &acpi_dev->dev, 1210 - dev, 1211 - &toshiba_backlight_data, 1212 - &props); 1213 - if (IS_ERR(dev->backlight_dev)) { 1214 - ret = PTR_ERR(dev->backlight_dev); 1215 - 1216 - pr_err("Could not register toshiba backlight device\n"); 1217 - dev->backlight_dev = NULL; 1107 + ret = toshiba_acpi_setup_backlight(dev); 1108 + if (ret) 1218 1109 goto error; 1219 - } 1220 - dev->backlight_dev->props.brightness = get_lcd(dev->backlight_dev); 1221 1110 1222 1111 /* Register rfkill switch for Bluetooth */ 1223 1112 if (hci_get_bt_present(dev, &bt_present) == HCI_SUCCESS && bt_present) {
+12 -1
drivers/platform/x86/xo1-rfkill.c
··· 15 15 16 16 #include <asm/olpc.h> 17 17 18 + static bool card_blocked; 19 + 18 20 static int rfkill_set_block(void *data, bool blocked) 19 21 { 20 22 unsigned char cmd; 23 + int r; 24 + 25 + if (blocked == card_blocked) 26 + return 0; 27 + 21 28 if (blocked) 22 29 cmd = EC_WLAN_ENTER_RESET; 23 30 else 24 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 40 static const struct rfkill_ops rfkill_ops = {