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 implements a vendor-specific backlight control interface for 36 * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu 37 * laptops. 38 * 39 * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and 40 * P8010. It should work on most P-series and S-series Lifebooks, but 41 * YMMV. 42 * 43 * The module parameter use_alt_lcd_levels switches between different ACPI 44 * brightness controls which are used by different Fujitsu laptops. In most 45 * cases the correct method is automatically detected. "use_alt_lcd_levels=1" 46 * is applicable for a Fujitsu Lifebook S6410 if autodetection fails. 47 * 48 */ 49 50 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 51 52 #include <linux/module.h> 53 #include <linux/kernel.h> 54 #include <linux/init.h> 55 #include <linux/acpi.h> 56 #include <linux/bitops.h> 57 #include <linux/dmi.h> 58 #include <linux/backlight.h> 59 #include <linux/fb.h> 60 #include <linux/input.h> 61 #include <linux/input/sparse-keymap.h> 62 #include <linux/kfifo.h> 63 #include <linux/leds.h> 64 #include <linux/platform_device.h> 65 #include <acpi/video.h> 66 67 #define FUJITSU_DRIVER_VERSION "0.6.0" 68 69 #define FUJITSU_LCD_N_LEVELS 8 70 71 #define ACPI_FUJITSU_CLASS "fujitsu" 72 #define ACPI_FUJITSU_BL_HID "FUJ02B1" 73 #define ACPI_FUJITSU_BL_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver" 74 #define ACPI_FUJITSU_BL_DEVICE_NAME "Fujitsu FUJ02B1" 75 #define ACPI_FUJITSU_LAPTOP_HID "FUJ02E3" 76 #define ACPI_FUJITSU_LAPTOP_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver" 77 #define ACPI_FUJITSU_LAPTOP_DEVICE_NAME "Fujitsu FUJ02E3" 78 79 #define ACPI_FUJITSU_NOTIFY_CODE 0x80 80 81 /* FUNC interface - command values */ 82 #define FUNC_FLAGS BIT(12) 83 #define FUNC_LEDS (BIT(12) | BIT(0)) 84 #define FUNC_BUTTONS (BIT(12) | BIT(1)) 85 #define FUNC_BACKLIGHT (BIT(12) | BIT(2)) 86 87 /* FUNC interface - responses */ 88 #define UNSUPPORTED_CMD 0x80000000 89 90 /* FUNC interface - status flags */ 91 #define FLAG_RFKILL BIT(5) 92 #define FLAG_LID BIT(8) 93 #define FLAG_DOCK BIT(9) 94 95 /* FUNC interface - LED control */ 96 #define FUNC_LED_OFF BIT(0) 97 #define FUNC_LED_ON (BIT(0) | BIT(16) | BIT(17)) 98 #define LOGOLAMP_POWERON BIT(13) 99 #define LOGOLAMP_ALWAYS BIT(14) 100 #define KEYBOARD_LAMPS BIT(8) 101 #define RADIO_LED_ON BIT(5) 102 #define ECO_LED BIT(16) 103 #define ECO_LED_ON BIT(19) 104 105 /* FUNC interface - backlight power control */ 106 #define BACKLIGHT_PARAM_POWER BIT(2) 107 #define BACKLIGHT_OFF (BIT(0) | BIT(1)) 108 #define BACKLIGHT_ON 0 109 110 /* Scancodes read from the GIRB register */ 111 #define KEY1_CODE 0x410 112 #define KEY2_CODE 0x411 113 #define KEY3_CODE 0x412 114 #define KEY4_CODE 0x413 115 #define KEY5_CODE 0x420 116 117 /* Hotkey ringbuffer limits */ 118 #define MAX_HOTKEY_RINGBUFFER_SIZE 100 119 #define RINGBUFFERSIZE 40 120 121 /* Module parameters */ 122 static int use_alt_lcd_levels = -1; 123 static bool disable_brightness_adjust; 124 125 /* Device controlling the backlight and associated keys */ 126 struct fujitsu_bl { 127 struct input_dev *input; 128 char phys[32]; 129 struct backlight_device *bl_device; 130 unsigned int max_brightness; 131 unsigned int brightness_level; 132 }; 133 134 static struct fujitsu_bl *fujitsu_bl; 135 136 /* Device used to access hotkeys and other features on the laptop */ 137 struct fujitsu_laptop { 138 struct input_dev *input; 139 char phys[32]; 140 struct platform_device *pf_device; 141 struct kfifo fifo; 142 spinlock_t fifo_lock; 143 int flags_supported; 144 int flags_state; 145 }; 146 147 static struct acpi_device *fext; 148 149 /* Fujitsu ACPI interface function */ 150 151 static int call_fext_func(struct acpi_device *device, 152 int func, int op, int feature, int state) 153 { 154 union acpi_object params[4] = { 155 { .integer.type = ACPI_TYPE_INTEGER, .integer.value = func }, 156 { .integer.type = ACPI_TYPE_INTEGER, .integer.value = op }, 157 { .integer.type = ACPI_TYPE_INTEGER, .integer.value = feature }, 158 { .integer.type = ACPI_TYPE_INTEGER, .integer.value = state } 159 }; 160 struct acpi_object_list arg_list = { 4, params }; 161 unsigned long long value; 162 acpi_status status; 163 164 status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list, 165 &value); 166 if (ACPI_FAILURE(status)) { 167 acpi_handle_err(device->handle, "Failed to evaluate FUNC\n"); 168 return -ENODEV; 169 } 170 171 acpi_handle_debug(device->handle, 172 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n", 173 func, op, feature, state, (int)value); 174 return value; 175 } 176 177 /* Hardware access for LCD brightness control */ 178 179 static int set_lcd_level(struct acpi_device *device, int level) 180 { 181 struct fujitsu_bl *priv = acpi_driver_data(device); 182 acpi_status status; 183 char *method; 184 185 switch (use_alt_lcd_levels) { 186 case -1: 187 if (acpi_has_method(device->handle, "SBL2")) 188 method = "SBL2"; 189 else 190 method = "SBLL"; 191 break; 192 case 1: 193 method = "SBL2"; 194 break; 195 default: 196 method = "SBLL"; 197 break; 198 } 199 200 acpi_handle_debug(device->handle, "set lcd level via %s [%d]\n", method, 201 level); 202 203 if (level < 0 || level >= priv->max_brightness) 204 return -EINVAL; 205 206 status = acpi_execute_simple_method(device->handle, method, level); 207 if (ACPI_FAILURE(status)) { 208 acpi_handle_err(device->handle, "Failed to evaluate %s\n", 209 method); 210 return -ENODEV; 211 } 212 213 priv->brightness_level = level; 214 215 return 0; 216 } 217 218 static int get_lcd_level(struct acpi_device *device) 219 { 220 struct fujitsu_bl *priv = acpi_driver_data(device); 221 unsigned long long state = 0; 222 acpi_status status = AE_OK; 223 224 acpi_handle_debug(device->handle, "get lcd level via GBLL\n"); 225 226 status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state); 227 if (ACPI_FAILURE(status)) 228 return 0; 229 230 priv->brightness_level = state & 0x0fffffff; 231 232 return priv->brightness_level; 233 } 234 235 static int get_max_brightness(struct acpi_device *device) 236 { 237 struct fujitsu_bl *priv = acpi_driver_data(device); 238 unsigned long long state = 0; 239 acpi_status status = AE_OK; 240 241 acpi_handle_debug(device->handle, "get max lcd level via RBLL\n"); 242 243 status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state); 244 if (ACPI_FAILURE(status)) 245 return -1; 246 247 priv->max_brightness = state; 248 249 return priv->max_brightness; 250 } 251 252 /* Backlight device stuff */ 253 254 static int bl_get_brightness(struct backlight_device *b) 255 { 256 struct acpi_device *device = bl_get_data(b); 257 258 return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level(device); 259 } 260 261 static int bl_update_status(struct backlight_device *b) 262 { 263 struct acpi_device *device = bl_get_data(b); 264 265 if (fext) { 266 if (b->props.power == FB_BLANK_POWERDOWN) 267 call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 268 BACKLIGHT_PARAM_POWER, BACKLIGHT_OFF); 269 else 270 call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 271 BACKLIGHT_PARAM_POWER, BACKLIGHT_ON); 272 } 273 274 return set_lcd_level(device, b->props.brightness); 275 } 276 277 static const struct backlight_ops fujitsu_bl_ops = { 278 .get_brightness = bl_get_brightness, 279 .update_status = bl_update_status, 280 }; 281 282 static ssize_t lid_show(struct device *dev, struct device_attribute *attr, 283 char *buf) 284 { 285 struct fujitsu_laptop *priv = dev_get_drvdata(dev); 286 287 if (!(priv->flags_supported & FLAG_LID)) 288 return sprintf(buf, "unknown\n"); 289 if (priv->flags_state & FLAG_LID) 290 return sprintf(buf, "open\n"); 291 else 292 return sprintf(buf, "closed\n"); 293 } 294 295 static ssize_t dock_show(struct device *dev, struct device_attribute *attr, 296 char *buf) 297 { 298 struct fujitsu_laptop *priv = dev_get_drvdata(dev); 299 300 if (!(priv->flags_supported & FLAG_DOCK)) 301 return sprintf(buf, "unknown\n"); 302 if (priv->flags_state & FLAG_DOCK) 303 return sprintf(buf, "docked\n"); 304 else 305 return sprintf(buf, "undocked\n"); 306 } 307 308 static ssize_t radios_show(struct device *dev, struct device_attribute *attr, 309 char *buf) 310 { 311 struct fujitsu_laptop *priv = dev_get_drvdata(dev); 312 313 if (!(priv->flags_supported & FLAG_RFKILL)) 314 return sprintf(buf, "unknown\n"); 315 if (priv->flags_state & FLAG_RFKILL) 316 return sprintf(buf, "on\n"); 317 else 318 return sprintf(buf, "killed\n"); 319 } 320 321 static DEVICE_ATTR_RO(lid); 322 static DEVICE_ATTR_RO(dock); 323 static DEVICE_ATTR_RO(radios); 324 325 static struct attribute *fujitsu_pf_attributes[] = { 326 &dev_attr_lid.attr, 327 &dev_attr_dock.attr, 328 &dev_attr_radios.attr, 329 NULL 330 }; 331 332 static const struct attribute_group fujitsu_pf_attribute_group = { 333 .attrs = fujitsu_pf_attributes 334 }; 335 336 static struct platform_driver fujitsu_pf_driver = { 337 .driver = { 338 .name = "fujitsu-laptop", 339 } 340 }; 341 342 /* ACPI device for LCD brightness control */ 343 344 static const struct key_entry keymap_backlight[] = { 345 { KE_KEY, true, { KEY_BRIGHTNESSUP } }, 346 { KE_KEY, false, { KEY_BRIGHTNESSDOWN } }, 347 { KE_END, 0 } 348 }; 349 350 static int acpi_fujitsu_bl_input_setup(struct acpi_device *device) 351 { 352 struct fujitsu_bl *priv = acpi_driver_data(device); 353 int ret; 354 355 priv->input = devm_input_allocate_device(&device->dev); 356 if (!priv->input) 357 return -ENOMEM; 358 359 snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0", 360 acpi_device_hid(device)); 361 362 priv->input->name = acpi_device_name(device); 363 priv->input->phys = priv->phys; 364 priv->input->id.bustype = BUS_HOST; 365 priv->input->id.product = 0x06; 366 367 ret = sparse_keymap_setup(priv->input, keymap_backlight, NULL); 368 if (ret) 369 return ret; 370 371 return input_register_device(priv->input); 372 } 373 374 static int fujitsu_backlight_register(struct acpi_device *device) 375 { 376 struct fujitsu_bl *priv = acpi_driver_data(device); 377 const struct backlight_properties props = { 378 .brightness = priv->brightness_level, 379 .max_brightness = priv->max_brightness - 1, 380 .type = BACKLIGHT_PLATFORM 381 }; 382 struct backlight_device *bd; 383 384 bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop", 385 &device->dev, device, 386 &fujitsu_bl_ops, &props); 387 if (IS_ERR(bd)) 388 return PTR_ERR(bd); 389 390 priv->bl_device = bd; 391 392 return 0; 393 } 394 395 static int acpi_fujitsu_bl_add(struct acpi_device *device) 396 { 397 struct fujitsu_bl *priv; 398 int ret; 399 400 if (acpi_video_get_backlight_type() != acpi_backlight_vendor) 401 return -ENODEV; 402 403 priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); 404 if (!priv) 405 return -ENOMEM; 406 407 fujitsu_bl = priv; 408 strcpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME); 409 strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); 410 device->driver_data = priv; 411 412 pr_info("ACPI: %s [%s]\n", 413 acpi_device_name(device), acpi_device_bid(device)); 414 415 if (get_max_brightness(device) <= 0) 416 priv->max_brightness = FUJITSU_LCD_N_LEVELS; 417 get_lcd_level(device); 418 419 ret = acpi_fujitsu_bl_input_setup(device); 420 if (ret) 421 return ret; 422 423 return fujitsu_backlight_register(device); 424 } 425 426 /* Brightness notify */ 427 428 static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) 429 { 430 struct fujitsu_bl *priv = acpi_driver_data(device); 431 int oldb, newb; 432 433 if (event != ACPI_FUJITSU_NOTIFY_CODE) { 434 acpi_handle_info(device->handle, "unsupported event [0x%x]\n", 435 event); 436 sparse_keymap_report_event(priv->input, -1, 1, true); 437 return; 438 } 439 440 oldb = priv->brightness_level; 441 get_lcd_level(device); 442 newb = priv->brightness_level; 443 444 acpi_handle_debug(device->handle, 445 "brightness button event [%i -> %i]\n", oldb, newb); 446 447 if (oldb == newb) 448 return; 449 450 if (!disable_brightness_adjust) 451 set_lcd_level(device, newb); 452 453 sparse_keymap_report_event(priv->input, oldb < newb, 1, true); 454 } 455 456 /* ACPI device for hotkey handling */ 457 458 static const struct key_entry keymap_default[] = { 459 { KE_KEY, KEY1_CODE, { KEY_PROG1 } }, 460 { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, 461 { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, 462 { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, 463 { KE_KEY, KEY5_CODE, { KEY_RFKILL } }, 464 { KE_KEY, BIT(5), { KEY_RFKILL } }, 465 { KE_KEY, BIT(26), { KEY_TOUCHPAD_TOGGLE } }, 466 { KE_KEY, BIT(29), { KEY_MICMUTE } }, 467 { KE_END, 0 } 468 }; 469 470 static const struct key_entry keymap_s64x0[] = { 471 { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } }, /* "Lock" */ 472 { KE_KEY, KEY2_CODE, { KEY_HELP } }, /* "Mobility Center */ 473 { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, 474 { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, 475 { KE_END, 0 } 476 }; 477 478 static const struct key_entry keymap_p8010[] = { 479 { KE_KEY, KEY1_CODE, { KEY_HELP } }, /* "Support" */ 480 { KE_KEY, KEY2_CODE, { KEY_PROG2 } }, 481 { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */ 482 { KE_KEY, KEY4_CODE, { KEY_WWW } }, /* "WWW" */ 483 { KE_END, 0 } 484 }; 485 486 static const struct key_entry *keymap = keymap_default; 487 488 static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id) 489 { 490 pr_info("Identified laptop model '%s'\n", id->ident); 491 keymap = id->driver_data; 492 return 1; 493 } 494 495 static const struct dmi_system_id fujitsu_laptop_dmi_table[] = { 496 { 497 .callback = fujitsu_laptop_dmi_keymap_override, 498 .ident = "Fujitsu Siemens S6410", 499 .matches = { 500 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 501 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"), 502 }, 503 .driver_data = (void *)keymap_s64x0 504 }, 505 { 506 .callback = fujitsu_laptop_dmi_keymap_override, 507 .ident = "Fujitsu Siemens S6420", 508 .matches = { 509 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), 510 DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"), 511 }, 512 .driver_data = (void *)keymap_s64x0 513 }, 514 { 515 .callback = fujitsu_laptop_dmi_keymap_override, 516 .ident = "Fujitsu LifeBook P8010", 517 .matches = { 518 DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), 519 DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"), 520 }, 521 .driver_data = (void *)keymap_p8010 522 }, 523 {} 524 }; 525 526 static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device) 527 { 528 struct fujitsu_laptop *priv = acpi_driver_data(device); 529 int ret; 530 531 priv->input = devm_input_allocate_device(&device->dev); 532 if (!priv->input) 533 return -ENOMEM; 534 535 snprintf(priv->phys, sizeof(priv->phys), "%s/input0", 536 acpi_device_hid(device)); 537 538 priv->input->name = acpi_device_name(device); 539 priv->input->phys = priv->phys; 540 priv->input->id.bustype = BUS_HOST; 541 542 dmi_check_system(fujitsu_laptop_dmi_table); 543 ret = sparse_keymap_setup(priv->input, keymap, NULL); 544 if (ret) 545 return ret; 546 547 return input_register_device(priv->input); 548 } 549 550 static int fujitsu_laptop_platform_add(struct acpi_device *device) 551 { 552 struct fujitsu_laptop *priv = acpi_driver_data(device); 553 int ret; 554 555 priv->pf_device = platform_device_alloc("fujitsu-laptop", -1); 556 if (!priv->pf_device) 557 return -ENOMEM; 558 559 platform_set_drvdata(priv->pf_device, priv); 560 561 ret = platform_device_add(priv->pf_device); 562 if (ret) 563 goto err_put_platform_device; 564 565 ret = sysfs_create_group(&priv->pf_device->dev.kobj, 566 &fujitsu_pf_attribute_group); 567 if (ret) 568 goto err_del_platform_device; 569 570 return 0; 571 572 err_del_platform_device: 573 platform_device_del(priv->pf_device); 574 err_put_platform_device: 575 platform_device_put(priv->pf_device); 576 577 return ret; 578 } 579 580 static void fujitsu_laptop_platform_remove(struct acpi_device *device) 581 { 582 struct fujitsu_laptop *priv = acpi_driver_data(device); 583 584 sysfs_remove_group(&priv->pf_device->dev.kobj, 585 &fujitsu_pf_attribute_group); 586 platform_device_unregister(priv->pf_device); 587 } 588 589 static int logolamp_set(struct led_classdev *cdev, 590 enum led_brightness brightness) 591 { 592 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 593 int poweron = FUNC_LED_ON, always = FUNC_LED_ON; 594 int ret; 595 596 if (brightness < LED_HALF) 597 poweron = FUNC_LED_OFF; 598 599 if (brightness < LED_FULL) 600 always = FUNC_LED_OFF; 601 602 ret = call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron); 603 if (ret < 0) 604 return ret; 605 606 return call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always); 607 } 608 609 static enum led_brightness logolamp_get(struct led_classdev *cdev) 610 { 611 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 612 int ret; 613 614 ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0); 615 if (ret == FUNC_LED_ON) 616 return LED_FULL; 617 618 ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0); 619 if (ret == FUNC_LED_ON) 620 return LED_HALF; 621 622 return LED_OFF; 623 } 624 625 static int kblamps_set(struct led_classdev *cdev, 626 enum led_brightness brightness) 627 { 628 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 629 630 if (brightness >= LED_FULL) 631 return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, 632 FUNC_LED_ON); 633 else 634 return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS, 635 FUNC_LED_OFF); 636 } 637 638 static enum led_brightness kblamps_get(struct led_classdev *cdev) 639 { 640 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 641 enum led_brightness brightness = LED_OFF; 642 643 if (call_fext_func(device, 644 FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON) 645 brightness = LED_FULL; 646 647 return brightness; 648 } 649 650 static int radio_led_set(struct led_classdev *cdev, 651 enum led_brightness brightness) 652 { 653 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 654 655 if (brightness >= LED_FULL) 656 return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON, 657 RADIO_LED_ON); 658 else 659 return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON, 660 0x0); 661 } 662 663 static enum led_brightness radio_led_get(struct led_classdev *cdev) 664 { 665 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 666 enum led_brightness brightness = LED_OFF; 667 668 if (call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON) 669 brightness = LED_FULL; 670 671 return brightness; 672 } 673 674 static int eco_led_set(struct led_classdev *cdev, 675 enum led_brightness brightness) 676 { 677 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 678 int curr; 679 680 curr = call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0); 681 if (brightness >= LED_FULL) 682 return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED, 683 curr | ECO_LED_ON); 684 else 685 return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED, 686 curr & ~ECO_LED_ON); 687 } 688 689 static enum led_brightness eco_led_get(struct led_classdev *cdev) 690 { 691 struct acpi_device *device = to_acpi_device(cdev->dev->parent); 692 enum led_brightness brightness = LED_OFF; 693 694 if (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON) 695 brightness = LED_FULL; 696 697 return brightness; 698 } 699 700 static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) 701 { 702 struct fujitsu_laptop *priv = acpi_driver_data(device); 703 struct led_classdev *led; 704 int ret; 705 706 if (call_fext_func(device, 707 FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { 708 led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); 709 if (!led) 710 return -ENOMEM; 711 712 led->name = "fujitsu::logolamp"; 713 led->brightness_set_blocking = logolamp_set; 714 led->brightness_get = logolamp_get; 715 ret = devm_led_classdev_register(&device->dev, led); 716 if (ret) 717 return ret; 718 } 719 720 if ((call_fext_func(device, 721 FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) && 722 (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) { 723 led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); 724 if (!led) 725 return -ENOMEM; 726 727 led->name = "fujitsu::kblamps"; 728 led->brightness_set_blocking = kblamps_set; 729 led->brightness_get = kblamps_get; 730 ret = devm_led_classdev_register(&device->dev, led); 731 if (ret) 732 return ret; 733 } 734 735 /* 736 * Some Fujitsu laptops have a radio toggle button in place of a slide 737 * switch and all such machines appear to also have an RF LED. Based on 738 * comparing DSDT tables of four Fujitsu Lifebook models (E744, E751, 739 * S7110, S8420; the first one has a radio toggle button, the other 740 * three have slide switches), bit 17 of flags_supported (the value 741 * returned by method S000 of ACPI device FUJ02E3) seems to indicate 742 * whether given model has a radio toggle button. 743 */ 744 if (priv->flags_supported & BIT(17)) { 745 led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); 746 if (!led) 747 return -ENOMEM; 748 749 led->name = "fujitsu::radio_led"; 750 led->brightness_set_blocking = radio_led_set; 751 led->brightness_get = radio_led_get; 752 led->default_trigger = "rfkill-any"; 753 ret = devm_led_classdev_register(&device->dev, led); 754 if (ret) 755 return ret; 756 } 757 758 /* Support for eco led is not always signaled in bit corresponding 759 * to the bit used to control the led. According to the DSDT table, 760 * bit 14 seems to indicate presence of said led as well. 761 * Confirm by testing the status. 762 */ 763 if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) && 764 (call_fext_func(device, 765 FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) { 766 led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL); 767 if (!led) 768 return -ENOMEM; 769 770 led->name = "fujitsu::eco_led"; 771 led->brightness_set_blocking = eco_led_set; 772 led->brightness_get = eco_led_get; 773 ret = devm_led_classdev_register(&device->dev, led); 774 if (ret) 775 return ret; 776 } 777 778 return 0; 779 } 780 781 static int acpi_fujitsu_laptop_add(struct acpi_device *device) 782 { 783 struct fujitsu_laptop *priv; 784 int ret, i = 0; 785 786 priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); 787 if (!priv) 788 return -ENOMEM; 789 790 WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found. Driver may not work as intended."); 791 fext = device; 792 793 strcpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME); 794 strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); 795 device->driver_data = priv; 796 797 /* kfifo */ 798 spin_lock_init(&priv->fifo_lock); 799 ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int), 800 GFP_KERNEL); 801 if (ret) 802 return ret; 803 804 pr_info("ACPI: %s [%s]\n", 805 acpi_device_name(device), acpi_device_bid(device)); 806 807 while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && 808 i++ < MAX_HOTKEY_RINGBUFFER_SIZE) 809 ; /* No action, result is discarded */ 810 acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n", 811 i); 812 813 priv->flags_supported = call_fext_func(device, FUNC_FLAGS, 0x0, 0x0, 814 0x0); 815 816 /* Make sure our bitmask of supported functions is cleared if the 817 RFKILL function block is not implemented, like on the S7020. */ 818 if (priv->flags_supported == UNSUPPORTED_CMD) 819 priv->flags_supported = 0; 820 821 if (priv->flags_supported) 822 priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 823 0x0); 824 825 /* Suspect this is a keymap of the application panel, print it */ 826 acpi_handle_info(device->handle, "BTNI: [0x%x]\n", 827 call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0)); 828 829 /* Sync backlight power status */ 830 if (fujitsu_bl && fujitsu_bl->bl_device && 831 acpi_video_get_backlight_type() == acpi_backlight_vendor) { 832 if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2, 833 BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF) 834 fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN; 835 else 836 fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK; 837 } 838 839 ret = acpi_fujitsu_laptop_input_setup(device); 840 if (ret) 841 goto err_free_fifo; 842 843 ret = acpi_fujitsu_laptop_leds_register(device); 844 if (ret) 845 goto err_free_fifo; 846 847 ret = fujitsu_laptop_platform_add(device); 848 if (ret) 849 goto err_free_fifo; 850 851 return 0; 852 853 err_free_fifo: 854 kfifo_free(&priv->fifo); 855 856 return ret; 857 } 858 859 static int acpi_fujitsu_laptop_remove(struct acpi_device *device) 860 { 861 struct fujitsu_laptop *priv = acpi_driver_data(device); 862 863 fujitsu_laptop_platform_remove(device); 864 865 kfifo_free(&priv->fifo); 866 867 return 0; 868 } 869 870 static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode) 871 { 872 struct fujitsu_laptop *priv = acpi_driver_data(device); 873 int ret; 874 875 ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode, 876 sizeof(scancode), &priv->fifo_lock); 877 if (ret != sizeof(scancode)) { 878 dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n", 879 scancode); 880 return; 881 } 882 sparse_keymap_report_event(priv->input, scancode, 1, false); 883 dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n", 884 scancode); 885 } 886 887 static void acpi_fujitsu_laptop_release(struct acpi_device *device) 888 { 889 struct fujitsu_laptop *priv = acpi_driver_data(device); 890 int scancode, ret; 891 892 while (true) { 893 ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode, 894 sizeof(scancode), &priv->fifo_lock); 895 if (ret != sizeof(scancode)) 896 return; 897 sparse_keymap_report_event(priv->input, scancode, 0, false); 898 dev_dbg(&priv->input->dev, 899 "Pop scancode from ringbuffer [0x%x]\n", scancode); 900 } 901 } 902 903 static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) 904 { 905 struct fujitsu_laptop *priv = acpi_driver_data(device); 906 int scancode, i = 0, ret; 907 unsigned int irb; 908 909 if (event != ACPI_FUJITSU_NOTIFY_CODE) { 910 acpi_handle_info(device->handle, "Unsupported event [0x%x]\n", 911 event); 912 sparse_keymap_report_event(priv->input, -1, 1, true); 913 return; 914 } 915 916 if (priv->flags_supported) 917 priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 918 0x0); 919 920 while ((irb = call_fext_func(device, 921 FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 && 922 i++ < MAX_HOTKEY_RINGBUFFER_SIZE) { 923 scancode = irb & 0x4ff; 924 if (sparse_keymap_entry_from_scancode(priv->input, scancode)) 925 acpi_fujitsu_laptop_press(device, scancode); 926 else if (scancode == 0) 927 acpi_fujitsu_laptop_release(device); 928 else 929 acpi_handle_info(device->handle, 930 "Unknown GIRB result [%x]\n", irb); 931 } 932 933 /* On some models (first seen on the Skylake-based Lifebook 934 * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is 935 * handled in software; its state is queried using FUNC_FLAGS 936 */ 937 if (priv->flags_supported & (BIT(5) | BIT(26) | BIT(29))) { 938 ret = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0); 939 if (ret & BIT(5)) 940 sparse_keymap_report_event(priv->input, 941 BIT(5), 1, true); 942 if (ret & BIT(26)) 943 sparse_keymap_report_event(priv->input, 944 BIT(26), 1, true); 945 if (ret & BIT(29)) 946 sparse_keymap_report_event(priv->input, 947 BIT(29), 1, true); 948 } 949 } 950 951 /* Initialization */ 952 953 static const struct acpi_device_id fujitsu_bl_device_ids[] = { 954 {ACPI_FUJITSU_BL_HID, 0}, 955 {"", 0}, 956 }; 957 958 static struct acpi_driver acpi_fujitsu_bl_driver = { 959 .name = ACPI_FUJITSU_BL_DRIVER_NAME, 960 .class = ACPI_FUJITSU_CLASS, 961 .ids = fujitsu_bl_device_ids, 962 .ops = { 963 .add = acpi_fujitsu_bl_add, 964 .notify = acpi_fujitsu_bl_notify, 965 }, 966 }; 967 968 static const struct acpi_device_id fujitsu_laptop_device_ids[] = { 969 {ACPI_FUJITSU_LAPTOP_HID, 0}, 970 {"", 0}, 971 }; 972 973 static struct acpi_driver acpi_fujitsu_laptop_driver = { 974 .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME, 975 .class = ACPI_FUJITSU_CLASS, 976 .ids = fujitsu_laptop_device_ids, 977 .ops = { 978 .add = acpi_fujitsu_laptop_add, 979 .remove = acpi_fujitsu_laptop_remove, 980 .notify = acpi_fujitsu_laptop_notify, 981 }, 982 }; 983 984 static const struct acpi_device_id fujitsu_ids[] __used = { 985 {ACPI_FUJITSU_BL_HID, 0}, 986 {ACPI_FUJITSU_LAPTOP_HID, 0}, 987 {"", 0} 988 }; 989 MODULE_DEVICE_TABLE(acpi, fujitsu_ids); 990 991 static int __init fujitsu_init(void) 992 { 993 int ret; 994 995 ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver); 996 if (ret) 997 return ret; 998 999 /* Register platform stuff */ 1000 1001 ret = platform_driver_register(&fujitsu_pf_driver); 1002 if (ret) 1003 goto err_unregister_acpi; 1004 1005 /* Register laptop driver */ 1006 1007 ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver); 1008 if (ret) 1009 goto err_unregister_platform_driver; 1010 1011 pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n"); 1012 1013 return 0; 1014 1015 err_unregister_platform_driver: 1016 platform_driver_unregister(&fujitsu_pf_driver); 1017 err_unregister_acpi: 1018 acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); 1019 1020 return ret; 1021 } 1022 1023 static void __exit fujitsu_cleanup(void) 1024 { 1025 acpi_bus_unregister_driver(&acpi_fujitsu_laptop_driver); 1026 1027 platform_driver_unregister(&fujitsu_pf_driver); 1028 1029 acpi_bus_unregister_driver(&acpi_fujitsu_bl_driver); 1030 1031 pr_info("driver unloaded\n"); 1032 } 1033 1034 module_init(fujitsu_init); 1035 module_exit(fujitsu_cleanup); 1036 1037 module_param(use_alt_lcd_levels, int, 0644); 1038 MODULE_PARM_DESC(use_alt_lcd_levels, "Interface used for setting LCD brightness level (-1 = auto, 0 = force SBLL, 1 = force SBL2)"); 1039 module_param(disable_brightness_adjust, bool, 0644); 1040 MODULE_PARM_DESC(disable_brightness_adjust, "Disable LCD brightness adjustment"); 1041 1042 MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon"); 1043 MODULE_DESCRIPTION("Fujitsu laptop extras support"); 1044 MODULE_VERSION(FUJITSU_DRIVER_VERSION); 1045 MODULE_LICENSE("GPL"); 1046