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