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