1 /*-*-linux-c-*-*/ 2 3 /* 4 Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net> 5 Copyright (C) 2008 Peter Gruber <nokos@gmx.net> 6 Copyright (C) 2008 Tony Vroon <tony@linx.net> 7 Based on earlier work: 8 Copyright (C) 2003 Shane Spencer <shane@bogomip.com> 9 Adrian Yee <brewt-fujitsu@brewt.org> 10 11 Templated from msi-laptop.c and thinkpad_acpi.c which is copyright 12 by its respective authors. 13 14 This program is free software; you can redistribute it and/or modify 15 it under the terms of the GNU General Public License as published by 16 the Free Software Foundation; either version 2 of the License, or 17 (at your option) any later version. 18 19 This program is distributed in the hope that it will be useful, but 20 WITHOUT ANY WARRANTY; without even the implied warranty of 21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 22 General Public License for more details. 23 24 You should have received a copy of the GNU General Public License 25 along with this program; if not, write to the Free Software 26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 27 02110-1301, USA. 28 */ 29 30 /* 31 * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional 32 * features made available on a range of Fujitsu laptops including the 33 * P2xxx/P5xxx/S6xxx/S7xxx series. 34 * 35 * This driver exports a few files in /sys/devices/platform/fujitsu-laptop/; 36 * others may be added at a later date. 37 * 38 * lcd_level - Screen brightness: contains a single integer in the 39 * range 0..7. (rw) 40 * 41 * In addition to these platform device attributes the driver 42 * registers itself in the Linux backlight control subsystem and is 43 * available to userspace under /sys/class/backlight/fujitsu-laptop/. 44 * 45 * Hotkeys present on certain Fujitsu laptops (eg: the S6xxx series) are 46 * also supported by this driver. 47 * 48 * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and 49 * P8010. It should work on most P-series and S-series Lifebooks, but 50 * YMMV. 51 * 52 * The module parameter use_alt_lcd_levels switches between different ACPI 53 * brightness controls which are used by different Fujitsu laptops. In most 54 * cases the correct method is automatically detected. "use_alt_lcd_levels=1" 55 * is applicable for a Fujitsu Lifebook S6410 if autodetection fails. 56 * 57 */ 58 59 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 60 61 #include <linux/module.h> 62 #include <linux/kernel.h> 63 #include <linux/init.h> 64 #include <linux/acpi.h> 65 #include <linux/dmi.h> 66 #include <linux/backlight.h> 67 #include <linux/fb.h> 68 #include <linux/input.h> 69 #include <linux/kfifo.h> 70 #include <linux/platform_device.h> 71 #include <linux/slab.h> 72 #if IS_ENABLED(CONFIG_LEDS_CLASS) 73 #include <linux/leds.h> 74 #endif 75 #include <acpi/video.h> 76 77 #define FUJITSU_DRIVER_VERSION "0.6.0" 78 79 #define FUJITSU_LCD_N_LEVELS 8 80 81 #define ACPI_FUJITSU_CLASS "fujitsu" 82 #define ACPI_FUJITSU_HID "FUJ02B1" 83 #define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver" 84 #define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1" 85 #define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3" 86 #define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver" 87 #define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3" 88 89 #define ACPI_FUJITSU_NOTIFY_CODE1 0x80 90 91 #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86 92 #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87 93 94 /* FUNC interface - command values */ 95 #define FUNC_RFKILL 0x1000 96 #define FUNC_LEDS 0x1001 97 #define FUNC_BUTTONS 0x1002 98 #define FUNC_BACKLIGHT 0x1004 99 100 /* FUNC interface - responses */ 101 #define UNSUPPORTED_CMD 0x80000000 102 103 #if IS_ENABLED(CONFIG_LEDS_CLASS) 104 /* FUNC interface - LED control */ 105 #define FUNC_LED_OFF 0x1 106 #define FUNC_LED_ON 0x30001 107 #define KEYBOARD_LAMPS 0x100 108 #define LOGOLAMP_POWERON 0x2000 109 #define LOGOLAMP_ALWAYS 0x4000 110 #define RADIO_LED_ON 0x20 111 #endif 112 113 /* Hotkey details */ 114 #define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ 115 #define KEY2_CODE 0x411 116 #define KEY3_CODE 0x412 117 #define KEY4_CODE 0x413 118 #define KEY5_CODE 0x420 119 120 #define MAX_HOTKEY_RINGBUFFER_SIZE 100 121 #define RINGBUFFERSIZE 40 122 123 /* Debugging */ 124 #define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": " 125 #define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG 126 #define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG 127 #define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG 128 #define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG 129 130 #define FUJLAPTOP_DBG_ALL 0xffff 131 #define FUJLAPTOP_DBG_ERROR 0x0001 132 #define FUJLAPTOP_DBG_WARN 0x0002 133 #define FUJLAPTOP_DBG_INFO 0x0004 134 #define FUJLAPTOP_DBG_TRACE 0x0008 135 136 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG 137 #define vdbg_printk(a_dbg_level, format, arg...) \ 138 do { if (dbg_level & a_dbg_level) \ 139 printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \ 140 } while (0) 141 #else 142 #define vdbg_printk(a_dbg_level, format, arg...) \ 143 do { } while (0) 144 #endif 145 146 /* Device controlling the backlight and associated keys */ 147 struct fujitsu_t { 148 acpi_handle acpi_handle; 149 struct acpi_device *dev; 150 struct input_dev *input; 151 char phys[32]; 152 struct backlight_device *bl_device; 153 struct platform_device *pf_device; 154 int keycode1, keycode2, keycode3, keycode4, keycode5; 155 156 unsigned int max_brightness; 157 unsigned int brightness_changed; 158 unsigned int brightness_level; 159 }; 160 161 static struct fujitsu_t *fujitsu; 162 static int use_alt_lcd_levels = -1; 163 static int disable_brightness_adjust = -1; 164 165 /* Device used to access other hotkeys on the laptop */ 166 struct fujitsu_hotkey_t { 167 acpi_handle acpi_handle; 168 struct acpi_device *dev; 169 struct input_dev *input; 170 char phys[32]; 171 struct platform_device *pf_device; 172 struct kfifo fifo; 173 spinlock_t fifo_lock; 174 int rfkill_supported; 175 int rfkill_state; 176 int logolamp_registered; 177 int kblamps_registered; 178 int radio_led_registered; 179 }; 180 181 static struct fujitsu_hotkey_t *fujitsu_hotkey; 182 183 static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event); 184 185 #if IS_ENABLED(CONFIG_LEDS_CLASS) 186 static enum led_brightness logolamp_get(struct led_classdev *cdev); 187 static void logolamp_set(struct led_classdev *cdev, 188 enum led_brightness brightness); 189 190 static struct led_classdev logolamp_led = { 191 .name = "fujitsu::logolamp", 192 .brightness_get = logolamp_get, 193 .brightness_set = logolamp_set 194 }; 195 196 static enum led_brightness kblamps_get(struct led_classdev *cdev); 197 static void kblamps_set(struct led_classdev *cdev, 198 enum led_brightness brightness); 199 200 static struct led_classdev kblamps_led = { 201 .name = "fujitsu::kblamps", 202 .brightness_get = kblamps_get, 203 .brightness_set = kblamps_set 204 }; 205 206 static enum led_brightness radio_led_get(struct led_classdev *cdev); 207 static void radio_led_set(struct led_classdev *cdev, 208 enum led_brightness brightness); 209 210 static struct led_classdev radio_led = { 211 .name = "fujitsu::radio_led", 212 .brightness_get = radio_led_get, 213 .brightness_set = radio_led_set 214 }; 215 #endif 216 217 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG 218 static u32 dbg_level = 0x03; 219 #endif 220 221 static void acpi_fujitsu_notify(struct acpi_device *device, u32 event); 222 223 /* Fujitsu ACPI interface function */ 224 225 static int call_fext_func(int cmd, int arg0, int arg1, int arg2) 226 { 227 acpi_status status = AE_OK; 228 union acpi_object params[4] = { 229 { .type = ACPI_TYPE_INTEGER }, 230 { .type = ACPI_TYPE_INTEGER }, 231 { .type = ACPI_TYPE_INTEGER }, 232 { .type = ACPI_TYPE_INTEGER } 233 }; 234 struct acpi_object_list arg_list = { 4, ¶ms[0] }; 235 unsigned long long value; 236 acpi_handle handle = NULL; 237 238 status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle); 239 if (ACPI_FAILURE(status)) { 240 vdbg_printk(FUJLAPTOP_DBG_ERROR, 241 "FUNC interface is not present\n"); 242 return -ENODEV; 243 } 244 245 params[0].integer.value = cmd; 246 params[1].integer.value = arg0; 247 params[2].integer.value = arg1; 248 params[3].integer.value = arg2; 249 250 status = acpi_evaluate_integer(handle, NULL, &arg_list, &value); 251 if (ACPI_FAILURE(status)) { 252 vdbg_printk(FUJLAPTOP_DBG_WARN, 253 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n", 254 cmd, arg0, arg1, arg2); 255 return -ENODEV; 256 } 257 258 vdbg_printk(FUJLAPTOP_DBG_TRACE, 259 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", 260 cmd, arg0, arg1, arg2, (int)value); 261 return value; 262 } 263 264 #if IS_ENABLED(CONFIG_LEDS_CLASS) 265 /* LED class callbacks */ 266 267 static void logolamp_set(struct led_classdev *cdev, 268 enum led_brightness brightness) 269 { 270 if (brightness >= LED_FULL) { 271 call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); 272 call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON); 273 } else if (brightness >= LED_HALF) { 274 call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON); 275 call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF); 276 } else { 277 call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF); 278 } 279 } 280 281 static void kblamps_set(struct led_classdev *cdev, 282 enum led_brightness brightness) 283 { 284 if (brightness >= LED_FULL) 285 call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON); 286 else 287 call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF); 288 } 289 290 static void radio_led_set(struct led_classdev *cdev, 291 enum led_brightness brightness) 292 { 293 if (brightness >= LED_FULL) 294 call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, RADIO_LED_ON); 295 else 296 call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0); 297 } 298 299 static enum led_brightness logolamp_get(struct led_classdev *cdev) 300 { 301 enum led_brightness brightness = LED_OFF; 302 int poweron, always; 303 304 poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); 305 if (poweron == FUNC_LED_ON) { 306 brightness = LED_HALF; 307 always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); 308 if (always == FUNC_LED_ON) 309 brightness = LED_FULL; 310 } 311 return brightness; 312 } 313 314 static enum led_brightness kblamps_get(struct led_classdev *cdev) 315 { 316 enum led_brightness brightness = LED_OFF; 317 318 if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) 319 brightness = LED_FULL; 320 321 return brightness; 322 } 323 324 static enum led_brightness radio_led_get(struct led_classdev *cdev) 325 { 326 enum led_brightness brightness = LED_OFF; 327 328 if (call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0) & RADIO_LED_ON) 329 brightness = LED_FULL; 330 331 return brightness; 332 } 333 #endif 334 335 /* Hardware access for LCD brightness control */ 336 337 static int set_lcd_level(int level) 338 { 339 acpi_status status = AE_OK; 340 acpi_handle handle = NULL; 341 342 vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBLL [%d]\n", 343 level); 344 345 if (level < 0 || level >= fujitsu->max_brightness) 346 return -EINVAL; 347 348 status = acpi_get_handle(fujitsu->acpi_handle, "SBLL", &handle); 349 if (ACPI_FAILURE(status)) { 350 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBLL not present\n"); 351 return -ENODEV; 352 } 353 354 355 status = acpi_execute_simple_method(handle, NULL, level); 356 if (ACPI_FAILURE(status)) 357 return -ENODEV; 358 359 return 0; 360 } 361 362 static int set_lcd_level_alt(int level) 363 { 364 acpi_status status = AE_OK; 365 acpi_handle handle = NULL; 366 367 vdbg_printk(FUJLAPTOP_DBG_TRACE, "set lcd level via SBL2 [%d]\n", 368 level); 369 370 if (level < 0 || level >= fujitsu->max_brightness) 371 return -EINVAL; 372 373 status = acpi_get_handle(fujitsu->acpi_handle, "SBL2", &handle); 374 if (ACPI_FAILURE(status)) { 375 vdbg_printk(FUJLAPTOP_DBG_ERROR, "SBL2 not present\n"); 376 return -ENODEV; 377 } 378 379 status = acpi_execute_simple_method(handle, NULL, level); 380 if (ACPI_FAILURE(status)) 381 return -ENODEV; 382 383 return 0; 384 } 385 386 static int get_lcd_level(void) 387 { 388 unsigned long long state = 0; 389 acpi_status status = AE_OK; 390 391 vdbg_printk(FUJLAPTOP_DBG_TRACE, "get lcd level via GBLL\n"); 392 393 status = 394 acpi_evaluate_integer(fujitsu->acpi_handle, "GBLL", NULL, &state); 395 if (ACPI_FAILURE(status)) 396 return 0; 397 398 fujitsu->brightness_level = state & 0x0fffffff; 399 400 if (state & 0x80000000) 401 fujitsu->brightness_changed = 1; 402 else 403 fujitsu->brightness_changed = 0; 404 405 return fujitsu->brightness_level; 406 } 407 408 static int get_max_brightness(void) 409 { 410 unsigned long long state = 0; 411 acpi_status status = AE_OK; 412 413 vdbg_printk(FUJLAPTOP_DBG_TRACE, "get max lcd level via RBLL\n"); 414 415 status = 416 acpi_evaluate_integer(fujitsu->acpi_handle, "RBLL", NULL, &state); 417 if (ACPI_FAILURE(status)) 418 return -1; 419 420 fujitsu->max_brightness = state; 421 422 return fujitsu->max_brightness; 423 } 424 425 /* Backlight device stuff */ 426 427 static int bl_get_brightness(struct backlight_device *b) 428 { 429 return get_lcd_level(); 430 } 431 432 static int bl_update_status(struct backlight_device *b) 433 { 434 int ret; 435 if (b->props.power == FB_BLANK_POWERDOWN) 436 ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3); 437 else 438 ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0); 439 if (ret != 0) 440 vdbg_printk(FUJLAPTOP_DBG_ERROR, 441 "Unable to adjust backlight power, error code %i\n", 442 ret); 443 444 if (use_alt_lcd_levels) 445 ret = set_lcd_level_alt(b->props.brightness); 446 else 447 ret = set_lcd_level(b->props.brightness); 448 if (ret != 0) 449 vdbg_printk(FUJLAPTOP_DBG_ERROR, 450 "Unable to adjust LCD brightness, error code %i\n", 451 ret); 452 return ret; 453 } 454 455 static const struct backlight_ops fujitsubl_ops = { 456 .get_brightness = bl_get_brightness, 457 .update_status = bl_update_status, 458 }; 459 460 /* Platform LCD brightness device */ 461 462 static ssize_t 463 show_max_brightness(struct device *dev, 464 struct device_attribute *attr, char *buf) 465 { 466 467 int ret; 468 469 ret = get_max_brightness(); 470 if (ret < 0) 471 return ret; 472 473 return sprintf(buf, "%i\n", ret); 474 } 475 476 static ssize_t 477 show_brightness_changed(struct device *dev, 478 struct device_attribute *attr, char *buf) 479 { 480 481 int ret; 482 483 ret = fujitsu->brightness_changed; 484 if (ret < 0) 485 return ret; 486 487 return sprintf(buf, "%i\n", ret); 488 } 489 490 static ssize_t show_lcd_level(struct device *dev, 491 struct device_attribute *attr, char *buf) 492 { 493 494 int ret; 495 496 ret = get_lcd_level(); 497 if (ret < 0) 498 return ret; 499 500 return sprintf(buf, "%i\n", ret); 501 } 502 503 static ssize_t store_lcd_level(struct device *dev, 504 struct device_attribute *attr, const char *buf, 505 size_t count) 506 { 507 508 int level, ret; 509 510 if (sscanf(buf, "%i", &level) != 1 511 || (level < 0 || level >= fujitsu->max_brightness)) 512 return -EINVAL; 513 514 if (use_alt_lcd_levels) 515 ret = set_lcd_level_alt(level); 516 else 517 ret = set_lcd_level(level); 518 if (ret < 0) 519 return ret; 520 521 ret = get_lcd_level(); 522 if (ret < 0) 523 return ret; 524 525 return count; 526 } 527 528 static ssize_t 529 ignore_store(struct device *dev, 530 struct device_attribute *attr, const char *buf, size_t count) 531 { 532 return count; 533 } 534 535 static ssize_t 536 show_lid_state(struct device *dev, 537 struct device_attribute *attr, char *buf) 538 { 539 if (!(fujitsu_hotkey->rfkill_supported & 0x100)) 540 return sprintf(buf, "unknown\n"); 541 if (fujitsu_hotkey->rfkill_state & 0x100) 542 return sprintf(buf, "open\n"); 543 else 544 return sprintf(buf, "closed\n"); 545 } 546 547 static ssize_t 548 show_dock_state(struct device *dev, 549 struct device_attribute *attr, char *buf) 550 { 551 if (!(fujitsu_hotkey->rfkill_supported & 0x200)) 552 return sprintf(buf, "unknown\n"); 553 if (fujitsu_hotkey->rfkill_state & 0x200) 554 return sprintf(buf, "docked\n"); 555 else 556 return sprintf(buf, "undocked\n"); 557 } 558 559 static ssize_t 560 show_radios_state(struct device *dev, 561 struct device_attribute *attr, char *buf) 562 { 563 if (!(fujitsu_hotkey->rfkill_supported & 0x20)) 564 return sprintf(buf, "unknown\n"); 565 if (fujitsu_hotkey->rfkill_state & 0x20) 566 return sprintf(buf, "on\n"); 567 else 568 return sprintf(buf, "killed\n"); 569 } 570 571 static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store); 572 static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed, 573 ignore_store); 574 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level); 575 static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store); 576 static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store); 577 static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store); 578 579 static struct attribute *fujitsupf_attributes[] = { 580 &dev_attr_brightness_changed.attr, 581 &dev_attr_max_brightness.attr, 582 &dev_attr_lcd_level.attr, 583 &dev_attr_lid.attr, 584 &dev_attr_dock.attr, 585 &dev_attr_radios.attr, 586 NULL 587 }; 588 589 static struct attribute_group fujitsupf_attribute_group = { 590 .attrs = fujitsupf_attributes 591 }; 592 593 static struct platform_driver fujitsupf_driver = { 594 .driver = { 595 .name = "fujitsu-laptop", 596 } 597 }; 598 599 static void __init dmi_check_cb_common(const struct dmi_system_id *id) 600 { 601 pr_info("Identified laptop model '%s'\n", id->ident); 602 if (use_alt_lcd_levels == -1) { 603 if (acpi_has_method(NULL, 604 "\\_SB.PCI0.LPCB.FJEX.SBL2")) 605 use_alt_lcd_levels = 1; 606 else 607 use_alt_lcd_levels = 0; 608 vdbg_printk(FUJLAPTOP_DBG_TRACE, "auto-detected usealt as " 609 "%i\n", use_alt_lcd_levels); 610 } 611 } 612 613 static int __init dmi_check_cb_s6410(const struct dmi_system_id *id) 614 { 615 dmi_check_cb_common(id); 616 fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ 617 fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ 618 return 1; 619 } 620 621 static int __init dmi_check_cb_s6420(const struct dmi_system_id *id) 622 { 623 dmi_check_cb_common(id); 624 fujitsu->keycode1 = KEY_SCREENLOCK; /* "Lock" */ 625 fujitsu->keycode2 = KEY_HELP; /* "Mobility Center" */ 626 return 1; 627 } 628 629 static int __init dmi_check_cb_p8010(const struct dmi_system_id *id) 630 { 631 dmi_check_cb_common(id); 632 fujitsu->keycode1 = KEY_HELP; /* "Support" */ 633 fujitsu->keycode3 = KEY_SWITCHVIDEOMODE; /* "Presentation" */ 634 fujitsu->keycode4 = KEY_WWW; /* "Internet" */ 635 return 1; 636 } 637 638 static const struct dmi_system_id fujitsu_dmi_table[] __initconst = { 639 { 640 .ident = "Fujitsu Siemens S6410", 641 .matches = { 642 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 643 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), 644 }, 645 .callback = dmi_check_cb_s6410}, 646 { 647 .ident = "Fujitsu Siemens S6420", 648 .matches = { 649 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 650 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"), 651 }, 652 .callback = dmi_check_cb_s6420}, 653 { 654 .ident = "Fujitsu LifeBook P8010", 655 .matches = { 656 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 657 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), 658 }, 659 .callback = dmi_check_cb_p8010}, 660 {} 661 }; 662 663 /* ACPI device for LCD brightness control */ 664 665 static int acpi_fujitsu_add(struct acpi_device *device) 666 { 667 int state = 0; 668 struct input_dev *input; 669 int error; 670 671 if (!device) 672 return -EINVAL; 673 674 fujitsu->acpi_handle = device->handle; 675 sprintf(acpi_device_name(device), "%s", ACPI_FUJITSU_DEVICE_NAME); 676 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); 677 device->driver_data = fujitsu; 678 679 fujitsu->input = input = input_allocate_device(); 680 if (!input) { 681 error = -ENOMEM; 682 goto err_stop; 683 } 684 685 snprintf(fujitsu->phys, sizeof(fujitsu->phys), 686 "%s/video/input0", acpi_device_hid(device)); 687 688 input->name = acpi_device_name(device); 689 input->phys = fujitsu->phys; 690 input->id.bustype = BUS_HOST; 691 input->id.product = 0x06; 692 input->dev.parent = &device->dev; 693 input->evbit[0] = BIT(EV_KEY); 694 set_bit(KEY_BRIGHTNESSUP, input->keybit); 695 set_bit(KEY_BRIGHTNESSDOWN, input->keybit); 696 set_bit(KEY_UNKNOWN, input->keybit); 697 698 error = input_register_device(input); 699 if (error) 700 goto err_free_input_dev; 701 702 error = acpi_bus_update_power(fujitsu->acpi_handle, &state); 703 if (error) { 704 pr_err("Error reading power state\n"); 705 goto err_unregister_input_dev; 706 } 707 708 pr_info("ACPI: %s [%s] (%s)\n", 709 acpi_device_name(device), acpi_device_bid(device), 710 !device->power.state ? "on" : "off"); 711 712 fujitsu->dev = device; 713 714 if (acpi_has_method(device->handle, METHOD_NAME__INI)) { 715 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); 716 if (ACPI_FAILURE 717 (acpi_evaluate_object 718 (device->handle, METHOD_NAME__INI, NULL, NULL))) 719 pr_err("_INI Method failed\n"); 720 } 721 722 /* do config (detect defaults) */ 723 use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0; 724 disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0; 725 vdbg_printk(FUJLAPTOP_DBG_INFO, 726 "config: [alt interface: %d], [adjust disable: %d]\n", 727 use_alt_lcd_levels, disable_brightness_adjust); 728 729 if (get_max_brightness() <= 0) 730 fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS; 731 get_lcd_level(); 732 733 return 0; 734 735 err_unregister_input_dev: 736 input_unregister_device(input); 737 input = NULL; 738 err_free_input_dev: 739 input_free_device(input); 740 err_stop: 741 return error; 742 } 743 744 static int acpi_fujitsu_remove(struct acpi_device *device) 745 { 746 struct fujitsu_t *fujitsu = acpi_driver_data(device); 747 struct input_dev *input = fujitsu->input; 748 749 input_unregister_device(input); 750 751 fujitsu->acpi_handle = NULL; 752 753 return 0; 754 } 755 756 /* Brightness notify */ 757 758 static void acpi_fujitsu_notify(struct acpi_device *device, u32 event) 759 { 760 struct input_dev *input; 761 int keycode; 762 int oldb, newb; 763 764 input = fujitsu->input; 765 766 switch (event) { 767 case ACPI_FUJITSU_NOTIFY_CODE1: 768 keycode = 0; 769 oldb = fujitsu->brightness_level; 770 get_lcd_level(); 771 newb = fujitsu->brightness_level; 772 773 vdbg_printk(FUJLAPTOP_DBG_TRACE, 774 "brightness button event [%i -> %i (%i)]\n", 775 oldb, newb, fujitsu->brightness_changed); 776 777 if (oldb < newb) { 778 if (disable_brightness_adjust != 1) { 779 if (use_alt_lcd_levels) 780 set_lcd_level_alt(newb); 781 else 782 set_lcd_level(newb); 783 } 784 keycode = KEY_BRIGHTNESSUP; 785 } else if (oldb > newb) { 786 if (disable_brightness_adjust != 1) { 787 if (use_alt_lcd_levels) 788 set_lcd_level_alt(newb); 789 else 790 set_lcd_level(newb); 791 } 792 keycode = KEY_BRIGHTNESSDOWN; 793 } 794 break; 795 default: 796 keycode = KEY_UNKNOWN; 797 vdbg_printk(FUJLAPTOP_DBG_WARN, 798 "unsupported event [0x%x]\n", event); 799 break; 800 } 801 802 if (keycode != 0) { 803 input_report_key(input, keycode, 1); 804 input_sync(input); 805 input_report_key(input, keycode, 0); 806 input_sync(input); 807 } 808 } 809 810 /* ACPI device for hotkey handling */ 811 812 static int acpi_fujitsu_hotkey_add(struct acpi_device *device) 813 { 814 int result = 0; 815 int state = 0; 816 struct input_dev *input; 817 int error; 818 int i; 819 820 if (!device) 821 return -EINVAL; 822 823 fujitsu_hotkey->acpi_handle = device->handle; 824 sprintf(acpi_device_name(device), "%s", 825 ACPI_FUJITSU_HOTKEY_DEVICE_NAME); 826 sprintf(acpi_device_class(device), "%s", ACPI_FUJITSU_CLASS); 827 device->driver_data = fujitsu_hotkey; 828 829 /* kfifo */ 830 spin_lock_init(&fujitsu_hotkey->fifo_lock); 831 error = kfifo_alloc(&fujitsu_hotkey->fifo, RINGBUFFERSIZE * sizeof(int), 832 GFP_KERNEL); 833 if (error) { 834 pr_err("kfifo_alloc failed\n"); 835 goto err_stop; 836 } 837 838 fujitsu_hotkey->input = input = input_allocate_device(); 839 if (!input) { 840 error = -ENOMEM; 841 goto err_free_fifo; 842 } 843 844 snprintf(fujitsu_hotkey->phys, sizeof(fujitsu_hotkey->phys), 845 "%s/video/input0", acpi_device_hid(device)); 846 847 input->name = acpi_device_name(device); 848 input->phys = fujitsu_hotkey->phys; 849 input->id.bustype = BUS_HOST; 850 input->id.product = 0x06; 851 input->dev.parent = &device->dev; 852 853 set_bit(EV_KEY, input->evbit); 854 set_bit(fujitsu->keycode1, input->keybit); 855 set_bit(fujitsu->keycode2, input->keybit); 856 set_bit(fujitsu->keycode3, input->keybit); 857 set_bit(fujitsu->keycode4, input->keybit); 858 set_bit(fujitsu->keycode5, input->keybit); 859 set_bit(KEY_UNKNOWN, input->keybit); 860 861 error = input_register_device(input); 862 if (error) 863 goto err_free_input_dev; 864 865 error = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state); 866 if (error) { 867 pr_err("Error reading power state\n"); 868 goto err_unregister_input_dev; 869 } 870 871 pr_info("ACPI: %s [%s] (%s)\n", 872 acpi_device_name(device), acpi_device_bid(device), 873 !device->power.state ? "on" : "off"); 874 875 fujitsu_hotkey->dev = device; 876 877 if (acpi_has_method(device->handle, METHOD_NAME__INI)) { 878 vdbg_printk(FUJLAPTOP_DBG_INFO, "Invoking _INI\n"); 879 if (ACPI_FAILURE 880 (acpi_evaluate_object 881 (device->handle, METHOD_NAME__INI, NULL, NULL))) 882 pr_err("_INI Method failed\n"); 883 } 884 885 i = 0; 886 while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 887 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) 888 ; /* No action, result is discarded */ 889 vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i); 890 891 fujitsu_hotkey->rfkill_supported = 892 call_fext_func(FUNC_RFKILL, 0x0, 0x0, 0x0); 893 894 /* Make sure our bitmask of supported functions is cleared if the 895 RFKILL function block is not implemented, like on the S7020. */ 896 if (fujitsu_hotkey->rfkill_supported == UNSUPPORTED_CMD) 897 fujitsu_hotkey->rfkill_supported = 0; 898 899 if (fujitsu_hotkey->rfkill_supported) 900 fujitsu_hotkey->rfkill_state = 901 call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); 902 903 /* Suspect this is a keymap of the application panel, print it */ 904 pr_info("BTNI: [0x%x]\n", call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0)); 905 906 #if IS_ENABLED(CONFIG_LEDS_CLASS) 907 if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { 908 result = led_classdev_register(&fujitsu->pf_device->dev, 909 &logolamp_led); 910 if (result == 0) { 911 fujitsu_hotkey->logolamp_registered = 1; 912 } else { 913 pr_err("Could not register LED handler for logo lamp, error %i\n", 914 result); 915 } 916 } 917 918 if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && 919 (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { 920 result = led_classdev_register(&fujitsu->pf_device->dev, 921 &kblamps_led); 922 if (result == 0) { 923 fujitsu_hotkey->kblamps_registered = 1; 924 } else { 925 pr_err("Could not register LED handler for keyboard lamps, error %i\n", 926 result); 927 } 928 } 929 930 /* 931 * BTNI bit 24 seems to indicate the presence of a radio toggle 932 * button in place of a slide switch, and all such machines appear 933 * to also have an RF LED. Therefore use bit 24 as an indicator 934 * that an RF LED is present. 935 */ 936 if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) { 937 result = led_classdev_register(&fujitsu->pf_device->dev, 938 &radio_led); 939 if (result == 0) { 940 fujitsu_hotkey->radio_led_registered = 1; 941 } else { 942 pr_err("Could not register LED handler for radio LED, error %i\n", 943 result); 944 } 945 } 946 #endif 947 948 return result; 949 950 err_unregister_input_dev: 951 input_unregister_device(input); 952 input = NULL; 953 err_free_input_dev: 954 input_free_device(input); 955 err_free_fifo: 956 kfifo_free(&fujitsu_hotkey->fifo); 957 err_stop: 958 return error; 959 } 960 961 static int acpi_fujitsu_hotkey_remove(struct acpi_device *device) 962 { 963 struct fujitsu_hotkey_t *fujitsu_hotkey = acpi_driver_data(device); 964 struct input_dev *input = fujitsu_hotkey->input; 965 966 #if IS_ENABLED(CONFIG_LEDS_CLASS) 967 if (fujitsu_hotkey->logolamp_registered) 968 led_classdev_unregister(&logolamp_led); 969 970 if (fujitsu_hotkey->kblamps_registered) 971 led_classdev_unregister(&kblamps_led); 972 973 if (fujitsu_hotkey->radio_led_registered) 974 led_classdev_unregister(&radio_led); 975 #endif 976 977 input_unregister_device(input); 978 979 kfifo_free(&fujitsu_hotkey->fifo); 980 981 fujitsu_hotkey->acpi_handle = NULL; 982 983 return 0; 984 } 985 986 static void acpi_fujitsu_hotkey_notify(struct acpi_device *device, u32 event) 987 { 988 struct input_dev *input; 989 int keycode, keycode_r; 990 unsigned int irb = 1; 991 int i, status; 992 993 input = fujitsu_hotkey->input; 994 995 if (fujitsu_hotkey->rfkill_supported) 996 fujitsu_hotkey->rfkill_state = 997 call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0); 998 999 switch (event) { 1000 case ACPI_FUJITSU_NOTIFY_CODE1: 1001 i = 0; 1002 while ((irb = 1003 call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 1004 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) { 1005 switch (irb & 0x4ff) { 1006 case KEY1_CODE: 1007 keycode = fujitsu->keycode1; 1008 break; 1009 case KEY2_CODE: 1010 keycode = fujitsu->keycode2; 1011 break; 1012 case KEY3_CODE: 1013 keycode = fujitsu->keycode3; 1014 break; 1015 case KEY4_CODE: 1016 keycode = fujitsu->keycode4; 1017 break; 1018 case KEY5_CODE: 1019 keycode = fujitsu->keycode5; 1020 break; 1021 case 0: 1022 keycode = 0; 1023 break; 1024 default: 1025 vdbg_printk(FUJLAPTOP_DBG_WARN, 1026 "Unknown GIRB result [%x]\n", irb); 1027 keycode = -1; 1028 break; 1029 } 1030 if (keycode > 0) { 1031 vdbg_printk(FUJLAPTOP_DBG_TRACE, 1032 "Push keycode into ringbuffer [%d]\n", 1033 keycode); 1034 status = kfifo_in_locked(&fujitsu_hotkey->fifo, 1035 (unsigned char *)&keycode, 1036 sizeof(keycode), 1037 &fujitsu_hotkey->fifo_lock); 1038 if (status != sizeof(keycode)) { 1039 vdbg_printk(FUJLAPTOP_DBG_WARN, 1040 "Could not push keycode [0x%x]\n", 1041 keycode); 1042 } else { 1043 input_report_key(input, keycode, 1); 1044 input_sync(input); 1045 } 1046 } else if (keycode == 0) { 1047 while ((status = 1048 kfifo_out_locked( 1049 &fujitsu_hotkey->fifo, 1050 (unsigned char *) &keycode_r, 1051 sizeof(keycode_r), 1052 &fujitsu_hotkey->fifo_lock)) 1053 == sizeof(keycode_r)) { 1054 input_report_key(input, keycode_r, 0); 1055 input_sync(input); 1056 vdbg_printk(FUJLAPTOP_DBG_TRACE, 1057 "Pop keycode from ringbuffer [%d]\n", 1058 keycode_r); 1059 } 1060 } 1061 } 1062 1063 break; 1064 default: 1065 keycode = KEY_UNKNOWN; 1066 vdbg_printk(FUJLAPTOP_DBG_WARN, 1067 "Unsupported event [0x%x]\n", event); 1068 input_report_key(input, keycode, 1); 1069 input_sync(input); 1070 input_report_key(input, keycode, 0); 1071 input_sync(input); 1072 break; 1073 } 1074 } 1075 1076 /* Initialization */ 1077 1078 static const struct acpi_device_id fujitsu_device_ids[] = { 1079 {ACPI_FUJITSU_HID, 0}, 1080 {"", 0}, 1081 }; 1082 1083 static struct acpi_driver acpi_fujitsu_driver = { 1084 .name = ACPI_FUJITSU_DRIVER_NAME, 1085 .class = ACPI_FUJITSU_CLASS, 1086 .ids = fujitsu_device_ids, 1087 .ops = { 1088 .add = acpi_fujitsu_add, 1089 .remove = acpi_fujitsu_remove, 1090 .notify = acpi_fujitsu_notify, 1091 }, 1092 }; 1093 1094 static const struct acpi_device_id fujitsu_hotkey_device_ids[] = { 1095 {ACPI_FUJITSU_HOTKEY_HID, 0}, 1096 {"", 0}, 1097 }; 1098 1099 static struct acpi_driver acpi_fujitsu_hotkey_driver = { 1100 .name = ACPI_FUJITSU_HOTKEY_DRIVER_NAME, 1101 .class = ACPI_FUJITSU_CLASS, 1102 .ids = fujitsu_hotkey_device_ids, 1103 .ops = { 1104 .add = acpi_fujitsu_hotkey_add, 1105 .remove = acpi_fujitsu_hotkey_remove, 1106 .notify = acpi_fujitsu_hotkey_notify, 1107 }, 1108 }; 1109 1110 static const struct acpi_device_id fujitsu_ids[] __used = { 1111 {ACPI_FUJITSU_HID, 0}, 1112 {ACPI_FUJITSU_HOTKEY_HID, 0}, 1113 {"", 0} 1114 }; 1115 MODULE_DEVICE_TABLE(acpi, fujitsu_ids); 1116 1117 static int __init fujitsu_init(void) 1118 { 1119 int ret, result, max_brightness; 1120 1121 if (acpi_disabled) 1122 return -ENODEV; 1123 1124 fujitsu = kzalloc(sizeof(struct fujitsu_t), GFP_KERNEL); 1125 if (!fujitsu) 1126 return -ENOMEM; 1127 fujitsu->keycode1 = KEY_PROG1; 1128 fujitsu->keycode2 = KEY_PROG2; 1129 fujitsu->keycode3 = KEY_PROG3; 1130 fujitsu->keycode4 = KEY_PROG4; 1131 fujitsu->keycode5 = KEY_RFKILL; 1132 dmi_check_system(fujitsu_dmi_table); 1133 1134 result = acpi_bus_register_driver(&acpi_fujitsu_driver); 1135 if (result < 0) { 1136 ret = -ENODEV; 1137 goto fail_acpi; 1138 } 1139 1140 /* Register platform stuff */ 1141 1142 fujitsu->pf_device = platform_device_alloc("fujitsu-laptop", -1); 1143 if (!fujitsu->pf_device) { 1144 ret = -ENOMEM; 1145 goto fail_platform_driver; 1146 } 1147 1148 ret = platform_device_add(fujitsu->pf_device); 1149 if (ret) 1150 goto fail_platform_device1; 1151 1152 ret = 1153 sysfs_create_group(&fujitsu->pf_device->dev.kobj, 1154 &fujitsupf_attribute_group); 1155 if (ret) 1156 goto fail_platform_device2; 1157 1158 /* Register backlight stuff */ 1159 1160 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { 1161 struct backlight_properties props; 1162 1163 memset(&props, 0, sizeof(struct backlight_properties)); 1164 max_brightness = fujitsu->max_brightness; 1165 props.type = BACKLIGHT_PLATFORM; 1166 props.max_brightness = max_brightness - 1; 1167 fujitsu->bl_device = backlight_device_register("fujitsu-laptop", 1168 NULL, NULL, 1169 &fujitsubl_ops, 1170 &props); 1171 if (IS_ERR(fujitsu->bl_device)) { 1172 ret = PTR_ERR(fujitsu->bl_device); 1173 fujitsu->bl_device = NULL; 1174 goto fail_sysfs_group; 1175 } 1176 fujitsu->bl_device->props.brightness = fujitsu->brightness_level; 1177 } 1178 1179 ret = platform_driver_register(&fujitsupf_driver); 1180 if (ret) 1181 goto fail_backlight; 1182 1183 /* Register hotkey driver */ 1184 1185 fujitsu_hotkey = kzalloc(sizeof(struct fujitsu_hotkey_t), GFP_KERNEL); 1186 if (!fujitsu_hotkey) { 1187 ret = -ENOMEM; 1188 goto fail_hotkey; 1189 } 1190 1191 result = acpi_bus_register_driver(&acpi_fujitsu_hotkey_driver); 1192 if (result < 0) { 1193 ret = -ENODEV; 1194 goto fail_hotkey1; 1195 } 1196 1197 /* Sync backlight power status (needs FUJ02E3 device, hence deferred) */ 1198 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { 1199 if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) 1200 fujitsu->bl_device->props.power = FB_BLANK_POWERDOWN; 1201 else 1202 fujitsu->bl_device->props.power = FB_BLANK_UNBLANK; 1203 } 1204 1205 pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n"); 1206 1207 return 0; 1208 1209 fail_hotkey1: 1210 kfree(fujitsu_hotkey); 1211 fail_hotkey: 1212 platform_driver_unregister(&fujitsupf_driver); 1213 fail_backlight: 1214 backlight_device_unregister(fujitsu->bl_device); 1215 fail_sysfs_group: 1216 sysfs_remove_group(&fujitsu->pf_device->dev.kobj, 1217 &fujitsupf_attribute_group); 1218 fail_platform_device2: 1219 platform_device_del(fujitsu->pf_device); 1220 fail_platform_device1: 1221 platform_device_put(fujitsu->pf_device); 1222 fail_platform_driver: 1223 acpi_bus_unregister_driver(&acpi_fujitsu_driver); 1224 fail_acpi: 1225 kfree(fujitsu); 1226 1227 return ret; 1228 } 1229 1230 static void __exit fujitsu_cleanup(void) 1231 { 1232 acpi_bus_unregister_driver(&acpi_fujitsu_hotkey_driver); 1233 1234 kfree(fujitsu_hotkey); 1235 1236 platform_driver_unregister(&fujitsupf_driver); 1237 1238 backlight_device_unregister(fujitsu->bl_device); 1239 1240 sysfs_remove_group(&fujitsu->pf_device->dev.kobj, 1241 &fujitsupf_attribute_group); 1242 1243 platform_device_unregister(fujitsu->pf_device); 1244 1245 acpi_bus_unregister_driver(&acpi_fujitsu_driver); 1246 1247 kfree(fujitsu); 1248 1249 pr_info("driver unloaded\n"); 1250 } 1251 1252 module_init(fujitsu_init); 1253 module_exit(fujitsu_cleanup); 1254 1255 module_param(use_alt_lcd_levels, uint, 0644); 1256 MODULE_PARM_DESC(use_alt_lcd_levels, 1257 "Use alternative interface for lcd_levels (needed for Lifebook s6410)."); 1258 module_param(disable_brightness_adjust, uint, 0644); 1259 MODULE_PARM_DESC(disable_brightness_adjust, "Disable brightness adjustment ."); 1260 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG 1261 module_param_named(debug, dbg_level, uint, 0644); 1262 MODULE_PARM_DESC(debug, "Sets debug level bit-mask"); 1263 #endif 1264 1265 MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); 1266 MODULE_DESCRIPTION("Fujitsu laptop extras support"); 1267 MODULE_VERSION(FUJITSU_DRIVER_VERSION); 1268 MODULE_LICENSE("GPL"); 1269 1270 MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*"); 1271 MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*"); 1272 MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*"); 1273