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