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