root/drivers/platform/x86/fujitsu-laptop.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. call_fext_func
  2. set_lcd_level
  3. get_lcd_level
  4. get_max_brightness
  5. bl_get_brightness
  6. bl_update_status
  7. lid_show
  8. dock_show
  9. radios_show
  10. acpi_fujitsu_bl_input_setup
  11. fujitsu_backlight_register
  12. acpi_fujitsu_bl_add
  13. acpi_fujitsu_bl_notify
  14. fujitsu_laptop_dmi_keymap_override
  15. acpi_fujitsu_laptop_input_setup
  16. fujitsu_laptop_platform_add
  17. fujitsu_laptop_platform_remove
  18. logolamp_set
  19. logolamp_get
  20. kblamps_set
  21. kblamps_get
  22. radio_led_set
  23. radio_led_get
  24. eco_led_set
  25. eco_led_get
  26. acpi_fujitsu_laptop_leds_register
  27. acpi_fujitsu_laptop_add
  28. acpi_fujitsu_laptop_remove
  29. acpi_fujitsu_laptop_press
  30. acpi_fujitsu_laptop_release
  31. acpi_fujitsu_laptop_notify
  32. fujitsu_init
  33. fujitsu_cleanup

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

/* [<][>][^][v][top][bottom][index][help] */