Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*-*-linux-c-*-*/
0003 
0004 /*
0005   Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@just42.net>
0006   Copyright (C) 2008 Peter Gruber <nokos@gmx.net>
0007   Copyright (C) 2008 Tony Vroon <tony@linx.net>
0008   Based on earlier work:
0009     Copyright (C) 2003 Shane Spencer <shane@bogomip.com>
0010     Adrian Yee <brewt-fujitsu@brewt.org>
0011 
0012   Templated from msi-laptop.c and thinkpad_acpi.c which is copyright
0013   by its respective authors.
0014 
0015  */
0016 
0017 /*
0018  * fujitsu-laptop.c - Fujitsu laptop support, providing access to additional
0019  * features made available on a range of Fujitsu laptops including the
0020  * P2xxx/P5xxx/S6xxx/S7xxx series.
0021  *
0022  * This driver implements a vendor-specific backlight control interface for
0023  * Fujitsu laptops and provides support for hotkeys present on certain Fujitsu
0024  * laptops.
0025  *
0026  * This driver has been tested on a Fujitsu Lifebook S6410, S7020 and
0027  * P8010.  It should work on most P-series and S-series Lifebooks, but
0028  * YMMV.
0029  *
0030  * The module parameter use_alt_lcd_levels switches between different ACPI
0031  * brightness controls which are used by different Fujitsu laptops.  In most
0032  * cases the correct method is automatically detected. "use_alt_lcd_levels=1"
0033  * is applicable for a Fujitsu Lifebook S6410 if autodetection fails.
0034  *
0035  */
0036 
0037 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0038 
0039 #include <linux/module.h>
0040 #include <linux/kernel.h>
0041 #include <linux/init.h>
0042 #include <linux/acpi.h>
0043 #include <linux/bitops.h>
0044 #include <linux/dmi.h>
0045 #include <linux/backlight.h>
0046 #include <linux/fb.h>
0047 #include <linux/input.h>
0048 #include <linux/input/sparse-keymap.h>
0049 #include <linux/kfifo.h>
0050 #include <linux/leds.h>
0051 #include <linux/platform_device.h>
0052 #include <acpi/video.h>
0053 
0054 #define FUJITSU_DRIVER_VERSION      "0.6.0"
0055 
0056 #define FUJITSU_LCD_N_LEVELS        8
0057 
0058 #define ACPI_FUJITSU_CLASS      "fujitsu"
0059 #define ACPI_FUJITSU_BL_HID     "FUJ02B1"
0060 #define ACPI_FUJITSU_BL_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
0061 #define ACPI_FUJITSU_BL_DEVICE_NAME "Fujitsu FUJ02B1"
0062 #define ACPI_FUJITSU_LAPTOP_HID     "FUJ02E3"
0063 #define ACPI_FUJITSU_LAPTOP_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
0064 #define ACPI_FUJITSU_LAPTOP_DEVICE_NAME "Fujitsu FUJ02E3"
0065 
0066 #define ACPI_FUJITSU_NOTIFY_CODE    0x80
0067 
0068 /* FUNC interface - command values */
0069 #define FUNC_FLAGS          BIT(12)
0070 #define FUNC_LEDS           (BIT(12) | BIT(0))
0071 #define FUNC_BUTTONS            (BIT(12) | BIT(1))
0072 #define FUNC_BACKLIGHT          (BIT(12) | BIT(2))
0073 
0074 /* FUNC interface - responses */
0075 #define UNSUPPORTED_CMD         0x80000000
0076 
0077 /* FUNC interface - status flags */
0078 #define FLAG_RFKILL         BIT(5)
0079 #define FLAG_LID            BIT(8)
0080 #define FLAG_DOCK           BIT(9)
0081 #define FLAG_TOUCHPAD_TOGGLE        BIT(26)
0082 #define FLAG_MICMUTE            BIT(29)
0083 #define FLAG_SOFTKEYS           (FLAG_RFKILL | FLAG_TOUCHPAD_TOGGLE | FLAG_MICMUTE)
0084 
0085 /* FUNC interface - LED control */
0086 #define FUNC_LED_OFF            BIT(0)
0087 #define FUNC_LED_ON         (BIT(0) | BIT(16) | BIT(17))
0088 #define LOGOLAMP_POWERON        BIT(13)
0089 #define LOGOLAMP_ALWAYS         BIT(14)
0090 #define KEYBOARD_LAMPS          BIT(8)
0091 #define RADIO_LED_ON            BIT(5)
0092 #define ECO_LED             BIT(16)
0093 #define ECO_LED_ON          BIT(19)
0094 
0095 /* FUNC interface - backlight power control */
0096 #define BACKLIGHT_PARAM_POWER       BIT(2)
0097 #define BACKLIGHT_OFF           (BIT(0) | BIT(1))
0098 #define BACKLIGHT_ON            0
0099 
0100 /* Scancodes read from the GIRB register */
0101 #define KEY1_CODE           0x410
0102 #define KEY2_CODE           0x411
0103 #define KEY3_CODE           0x412
0104 #define KEY4_CODE           0x413
0105 #define KEY5_CODE           0x420
0106 
0107 /* Hotkey ringbuffer limits */
0108 #define MAX_HOTKEY_RINGBUFFER_SIZE  100
0109 #define RINGBUFFERSIZE          40
0110 
0111 /* Module parameters */
0112 static int use_alt_lcd_levels = -1;
0113 static bool disable_brightness_adjust;
0114 
0115 /* Device controlling the backlight and associated keys */
0116 struct fujitsu_bl {
0117     struct input_dev *input;
0118     char phys[32];
0119     struct backlight_device *bl_device;
0120     unsigned int max_brightness;
0121     unsigned int brightness_level;
0122 };
0123 
0124 static struct fujitsu_bl *fujitsu_bl;
0125 
0126 /* Device used to access hotkeys and other features on the laptop */
0127 struct fujitsu_laptop {
0128     struct input_dev *input;
0129     char phys[32];
0130     struct platform_device *pf_device;
0131     struct kfifo fifo;
0132     spinlock_t fifo_lock;
0133     int flags_supported;
0134     int flags_state;
0135 };
0136 
0137 static struct acpi_device *fext;
0138 
0139 /* Fujitsu ACPI interface function */
0140 
0141 static int call_fext_func(struct acpi_device *device,
0142               int func, int op, int feature, int state)
0143 {
0144     union acpi_object params[4] = {
0145         { .integer.type = ACPI_TYPE_INTEGER, .integer.value = func },
0146         { .integer.type = ACPI_TYPE_INTEGER, .integer.value = op },
0147         { .integer.type = ACPI_TYPE_INTEGER, .integer.value = feature },
0148         { .integer.type = ACPI_TYPE_INTEGER, .integer.value = state }
0149     };
0150     struct acpi_object_list arg_list = { 4, params };
0151     unsigned long long value;
0152     acpi_status status;
0153 
0154     status = acpi_evaluate_integer(device->handle, "FUNC", &arg_list,
0155                        &value);
0156     if (ACPI_FAILURE(status)) {
0157         acpi_handle_err(device->handle, "Failed to evaluate FUNC\n");
0158         return -ENODEV;
0159     }
0160 
0161     acpi_handle_debug(device->handle,
0162               "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
0163               func, op, feature, state, (int)value);
0164     return value;
0165 }
0166 
0167 /* Hardware access for LCD brightness control */
0168 
0169 static int set_lcd_level(struct acpi_device *device, int level)
0170 {
0171     struct fujitsu_bl *priv = acpi_driver_data(device);
0172     acpi_status status;
0173     char *method;
0174 
0175     switch (use_alt_lcd_levels) {
0176     case -1:
0177         if (acpi_has_method(device->handle, "SBL2"))
0178             method = "SBL2";
0179         else
0180             method = "SBLL";
0181         break;
0182     case 1:
0183         method = "SBL2";
0184         break;
0185     default:
0186         method = "SBLL";
0187         break;
0188     }
0189 
0190     acpi_handle_debug(device->handle, "set lcd level via %s [%d]\n", method,
0191               level);
0192 
0193     if (level < 0 || level >= priv->max_brightness)
0194         return -EINVAL;
0195 
0196     status = acpi_execute_simple_method(device->handle, method, level);
0197     if (ACPI_FAILURE(status)) {
0198         acpi_handle_err(device->handle, "Failed to evaluate %s\n",
0199                 method);
0200         return -ENODEV;
0201     }
0202 
0203     priv->brightness_level = level;
0204 
0205     return 0;
0206 }
0207 
0208 static int get_lcd_level(struct acpi_device *device)
0209 {
0210     struct fujitsu_bl *priv = acpi_driver_data(device);
0211     unsigned long long state = 0;
0212     acpi_status status = AE_OK;
0213 
0214     acpi_handle_debug(device->handle, "get lcd level via GBLL\n");
0215 
0216     status = acpi_evaluate_integer(device->handle, "GBLL", NULL, &state);
0217     if (ACPI_FAILURE(status))
0218         return 0;
0219 
0220     priv->brightness_level = state & 0x0fffffff;
0221 
0222     return priv->brightness_level;
0223 }
0224 
0225 static int get_max_brightness(struct acpi_device *device)
0226 {
0227     struct fujitsu_bl *priv = acpi_driver_data(device);
0228     unsigned long long state = 0;
0229     acpi_status status = AE_OK;
0230 
0231     acpi_handle_debug(device->handle, "get max lcd level via RBLL\n");
0232 
0233     status = acpi_evaluate_integer(device->handle, "RBLL", NULL, &state);
0234     if (ACPI_FAILURE(status))
0235         return -1;
0236 
0237     priv->max_brightness = state;
0238 
0239     return priv->max_brightness;
0240 }
0241 
0242 /* Backlight device stuff */
0243 
0244 static int bl_get_brightness(struct backlight_device *b)
0245 {
0246     struct acpi_device *device = bl_get_data(b);
0247 
0248     return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level(device);
0249 }
0250 
0251 static int bl_update_status(struct backlight_device *b)
0252 {
0253     struct acpi_device *device = bl_get_data(b);
0254 
0255     if (fext) {
0256         if (b->props.power == FB_BLANK_POWERDOWN)
0257             call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
0258                        BACKLIGHT_PARAM_POWER, BACKLIGHT_OFF);
0259         else
0260             call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
0261                        BACKLIGHT_PARAM_POWER, BACKLIGHT_ON);
0262     }
0263 
0264     return set_lcd_level(device, b->props.brightness);
0265 }
0266 
0267 static const struct backlight_ops fujitsu_bl_ops = {
0268     .get_brightness = bl_get_brightness,
0269     .update_status = bl_update_status,
0270 };
0271 
0272 static ssize_t lid_show(struct device *dev, struct device_attribute *attr,
0273             char *buf)
0274 {
0275     struct fujitsu_laptop *priv = dev_get_drvdata(dev);
0276 
0277     if (!(priv->flags_supported & FLAG_LID))
0278         return sprintf(buf, "unknown\n");
0279     if (priv->flags_state & FLAG_LID)
0280         return sprintf(buf, "open\n");
0281     else
0282         return sprintf(buf, "closed\n");
0283 }
0284 
0285 static ssize_t dock_show(struct device *dev, struct device_attribute *attr,
0286              char *buf)
0287 {
0288     struct fujitsu_laptop *priv = dev_get_drvdata(dev);
0289 
0290     if (!(priv->flags_supported & FLAG_DOCK))
0291         return sprintf(buf, "unknown\n");
0292     if (priv->flags_state & FLAG_DOCK)
0293         return sprintf(buf, "docked\n");
0294     else
0295         return sprintf(buf, "undocked\n");
0296 }
0297 
0298 static ssize_t radios_show(struct device *dev, struct device_attribute *attr,
0299                char *buf)
0300 {
0301     struct fujitsu_laptop *priv = dev_get_drvdata(dev);
0302 
0303     if (!(priv->flags_supported & FLAG_RFKILL))
0304         return sprintf(buf, "unknown\n");
0305     if (priv->flags_state & FLAG_RFKILL)
0306         return sprintf(buf, "on\n");
0307     else
0308         return sprintf(buf, "killed\n");
0309 }
0310 
0311 static DEVICE_ATTR_RO(lid);
0312 static DEVICE_ATTR_RO(dock);
0313 static DEVICE_ATTR_RO(radios);
0314 
0315 static struct attribute *fujitsu_pf_attributes[] = {
0316     &dev_attr_lid.attr,
0317     &dev_attr_dock.attr,
0318     &dev_attr_radios.attr,
0319     NULL
0320 };
0321 
0322 static const struct attribute_group fujitsu_pf_attribute_group = {
0323     .attrs = fujitsu_pf_attributes
0324 };
0325 
0326 static struct platform_driver fujitsu_pf_driver = {
0327     .driver = {
0328            .name = "fujitsu-laptop",
0329            }
0330 };
0331 
0332 /* ACPI device for LCD brightness control */
0333 
0334 static const struct key_entry keymap_backlight[] = {
0335     { KE_KEY, true, { KEY_BRIGHTNESSUP } },
0336     { KE_KEY, false, { KEY_BRIGHTNESSDOWN } },
0337     { KE_END, 0 }
0338 };
0339 
0340 static int acpi_fujitsu_bl_input_setup(struct acpi_device *device)
0341 {
0342     struct fujitsu_bl *priv = acpi_driver_data(device);
0343     int ret;
0344 
0345     priv->input = devm_input_allocate_device(&device->dev);
0346     if (!priv->input)
0347         return -ENOMEM;
0348 
0349     snprintf(priv->phys, sizeof(priv->phys), "%s/video/input0",
0350          acpi_device_hid(device));
0351 
0352     priv->input->name = acpi_device_name(device);
0353     priv->input->phys = priv->phys;
0354     priv->input->id.bustype = BUS_HOST;
0355     priv->input->id.product = 0x06;
0356 
0357     ret = sparse_keymap_setup(priv->input, keymap_backlight, NULL);
0358     if (ret)
0359         return ret;
0360 
0361     return input_register_device(priv->input);
0362 }
0363 
0364 static int fujitsu_backlight_register(struct acpi_device *device)
0365 {
0366     struct fujitsu_bl *priv = acpi_driver_data(device);
0367     const struct backlight_properties props = {
0368         .brightness = priv->brightness_level,
0369         .max_brightness = priv->max_brightness - 1,
0370         .type = BACKLIGHT_PLATFORM
0371     };
0372     struct backlight_device *bd;
0373 
0374     bd = devm_backlight_device_register(&device->dev, "fujitsu-laptop",
0375                         &device->dev, device,
0376                         &fujitsu_bl_ops, &props);
0377     if (IS_ERR(bd))
0378         return PTR_ERR(bd);
0379 
0380     priv->bl_device = bd;
0381 
0382     return 0;
0383 }
0384 
0385 static int acpi_fujitsu_bl_add(struct acpi_device *device)
0386 {
0387     struct fujitsu_bl *priv;
0388     int ret;
0389 
0390     if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
0391         return -ENODEV;
0392 
0393     priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
0394     if (!priv)
0395         return -ENOMEM;
0396 
0397     fujitsu_bl = priv;
0398     strcpy(acpi_device_name(device), ACPI_FUJITSU_BL_DEVICE_NAME);
0399     strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
0400     device->driver_data = priv;
0401 
0402     pr_info("ACPI: %s [%s]\n",
0403         acpi_device_name(device), acpi_device_bid(device));
0404 
0405     if (get_max_brightness(device) <= 0)
0406         priv->max_brightness = FUJITSU_LCD_N_LEVELS;
0407     get_lcd_level(device);
0408 
0409     ret = acpi_fujitsu_bl_input_setup(device);
0410     if (ret)
0411         return ret;
0412 
0413     return fujitsu_backlight_register(device);
0414 }
0415 
0416 /* Brightness notify */
0417 
0418 static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event)
0419 {
0420     struct fujitsu_bl *priv = acpi_driver_data(device);
0421     int oldb, newb;
0422 
0423     if (event != ACPI_FUJITSU_NOTIFY_CODE) {
0424         acpi_handle_info(device->handle, "unsupported event [0x%x]\n",
0425                  event);
0426         sparse_keymap_report_event(priv->input, -1, 1, true);
0427         return;
0428     }
0429 
0430     oldb = priv->brightness_level;
0431     get_lcd_level(device);
0432     newb = priv->brightness_level;
0433 
0434     acpi_handle_debug(device->handle,
0435               "brightness button event [%i -> %i]\n", oldb, newb);
0436 
0437     if (oldb == newb)
0438         return;
0439 
0440     if (!disable_brightness_adjust)
0441         set_lcd_level(device, newb);
0442 
0443     sparse_keymap_report_event(priv->input, oldb < newb, 1, true);
0444 }
0445 
0446 /* ACPI device for hotkey handling */
0447 
0448 static const struct key_entry keymap_default[] = {
0449     { KE_KEY, KEY1_CODE,            { KEY_PROG1 } },
0450     { KE_KEY, KEY2_CODE,            { KEY_PROG2 } },
0451     { KE_KEY, KEY3_CODE,            { KEY_PROG3 } },
0452     { KE_KEY, KEY4_CODE,            { KEY_PROG4 } },
0453     { KE_KEY, KEY5_CODE,            { KEY_RFKILL } },
0454     /* Soft keys read from status flags */
0455     { KE_KEY, FLAG_RFKILL,          { KEY_RFKILL } },
0456     { KE_KEY, FLAG_TOUCHPAD_TOGGLE, { KEY_TOUCHPAD_TOGGLE } },
0457     { KE_KEY, FLAG_MICMUTE,         { KEY_MICMUTE } },
0458     { KE_END, 0 }
0459 };
0460 
0461 static const struct key_entry keymap_s64x0[] = {
0462     { KE_KEY, KEY1_CODE, { KEY_SCREENLOCK } },  /* "Lock" */
0463     { KE_KEY, KEY2_CODE, { KEY_HELP } },        /* "Mobility Center */
0464     { KE_KEY, KEY3_CODE, { KEY_PROG3 } },
0465     { KE_KEY, KEY4_CODE, { KEY_PROG4 } },
0466     { KE_END, 0 }
0467 };
0468 
0469 static const struct key_entry keymap_p8010[] = {
0470     { KE_KEY, KEY1_CODE, { KEY_HELP } },        /* "Support" */
0471     { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
0472     { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } }, /* "Presentation" */
0473     { KE_KEY, KEY4_CODE, { KEY_WWW } },     /* "WWW" */
0474     { KE_END, 0 }
0475 };
0476 
0477 static const struct key_entry *keymap = keymap_default;
0478 
0479 static int fujitsu_laptop_dmi_keymap_override(const struct dmi_system_id *id)
0480 {
0481     pr_info("Identified laptop model '%s'\n", id->ident);
0482     keymap = id->driver_data;
0483     return 1;
0484 }
0485 
0486 static const struct dmi_system_id fujitsu_laptop_dmi_table[] = {
0487     {
0488         .callback = fujitsu_laptop_dmi_keymap_override,
0489         .ident = "Fujitsu Siemens S6410",
0490         .matches = {
0491             DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
0492             DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6410"),
0493         },
0494         .driver_data = (void *)keymap_s64x0
0495     },
0496     {
0497         .callback = fujitsu_laptop_dmi_keymap_override,
0498         .ident = "Fujitsu Siemens S6420",
0499         .matches = {
0500             DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
0501             DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK S6420"),
0502         },
0503         .driver_data = (void *)keymap_s64x0
0504     },
0505     {
0506         .callback = fujitsu_laptop_dmi_keymap_override,
0507         .ident = "Fujitsu LifeBook P8010",
0508         .matches = {
0509             DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
0510             DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook P8010"),
0511         },
0512         .driver_data = (void *)keymap_p8010
0513     },
0514     {}
0515 };
0516 
0517 static int acpi_fujitsu_laptop_input_setup(struct acpi_device *device)
0518 {
0519     struct fujitsu_laptop *priv = acpi_driver_data(device);
0520     int ret;
0521 
0522     priv->input = devm_input_allocate_device(&device->dev);
0523     if (!priv->input)
0524         return -ENOMEM;
0525 
0526     snprintf(priv->phys, sizeof(priv->phys), "%s/input0",
0527          acpi_device_hid(device));
0528 
0529     priv->input->name = acpi_device_name(device);
0530     priv->input->phys = priv->phys;
0531     priv->input->id.bustype = BUS_HOST;
0532 
0533     dmi_check_system(fujitsu_laptop_dmi_table);
0534     ret = sparse_keymap_setup(priv->input, keymap, NULL);
0535     if (ret)
0536         return ret;
0537 
0538     return input_register_device(priv->input);
0539 }
0540 
0541 static int fujitsu_laptop_platform_add(struct acpi_device *device)
0542 {
0543     struct fujitsu_laptop *priv = acpi_driver_data(device);
0544     int ret;
0545 
0546     priv->pf_device = platform_device_alloc("fujitsu-laptop", -1);
0547     if (!priv->pf_device)
0548         return -ENOMEM;
0549 
0550     platform_set_drvdata(priv->pf_device, priv);
0551 
0552     ret = platform_device_add(priv->pf_device);
0553     if (ret)
0554         goto err_put_platform_device;
0555 
0556     ret = sysfs_create_group(&priv->pf_device->dev.kobj,
0557                  &fujitsu_pf_attribute_group);
0558     if (ret)
0559         goto err_del_platform_device;
0560 
0561     return 0;
0562 
0563 err_del_platform_device:
0564     platform_device_del(priv->pf_device);
0565 err_put_platform_device:
0566     platform_device_put(priv->pf_device);
0567 
0568     return ret;
0569 }
0570 
0571 static void fujitsu_laptop_platform_remove(struct acpi_device *device)
0572 {
0573     struct fujitsu_laptop *priv = acpi_driver_data(device);
0574 
0575     sysfs_remove_group(&priv->pf_device->dev.kobj,
0576                &fujitsu_pf_attribute_group);
0577     platform_device_unregister(priv->pf_device);
0578 }
0579 
0580 static int logolamp_set(struct led_classdev *cdev,
0581             enum led_brightness brightness)
0582 {
0583     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0584     int poweron = FUNC_LED_ON, always = FUNC_LED_ON;
0585     int ret;
0586 
0587     if (brightness < LED_HALF)
0588         poweron = FUNC_LED_OFF;
0589 
0590     if (brightness < LED_FULL)
0591         always = FUNC_LED_OFF;
0592 
0593     ret = call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_POWERON, poweron);
0594     if (ret < 0)
0595         return ret;
0596 
0597     return call_fext_func(device, FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, always);
0598 }
0599 
0600 static enum led_brightness logolamp_get(struct led_classdev *cdev)
0601 {
0602     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0603     int ret;
0604 
0605     ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
0606     if (ret == FUNC_LED_ON)
0607         return LED_FULL;
0608 
0609     ret = call_fext_func(device, FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
0610     if (ret == FUNC_LED_ON)
0611         return LED_HALF;
0612 
0613     return LED_OFF;
0614 }
0615 
0616 static int kblamps_set(struct led_classdev *cdev,
0617                enum led_brightness brightness)
0618 {
0619     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0620 
0621     if (brightness >= LED_FULL)
0622         return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
0623                       FUNC_LED_ON);
0624     else
0625         return call_fext_func(device, FUNC_LEDS, 0x1, KEYBOARD_LAMPS,
0626                       FUNC_LED_OFF);
0627 }
0628 
0629 static enum led_brightness kblamps_get(struct led_classdev *cdev)
0630 {
0631     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0632     enum led_brightness brightness = LED_OFF;
0633 
0634     if (call_fext_func(device,
0635                FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
0636         brightness = LED_FULL;
0637 
0638     return brightness;
0639 }
0640 
0641 static int radio_led_set(struct led_classdev *cdev,
0642              enum led_brightness brightness)
0643 {
0644     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0645 
0646     if (brightness >= LED_FULL)
0647         return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
0648                       RADIO_LED_ON);
0649     else
0650         return call_fext_func(device, FUNC_FLAGS, 0x5, RADIO_LED_ON,
0651                       0x0);
0652 }
0653 
0654 static enum led_brightness radio_led_get(struct led_classdev *cdev)
0655 {
0656     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0657     enum led_brightness brightness = LED_OFF;
0658 
0659     if (call_fext_func(device, FUNC_FLAGS, 0x4, 0x0, 0x0) & RADIO_LED_ON)
0660         brightness = LED_FULL;
0661 
0662     return brightness;
0663 }
0664 
0665 static int eco_led_set(struct led_classdev *cdev,
0666                enum led_brightness brightness)
0667 {
0668     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0669     int curr;
0670 
0671     curr = call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0);
0672     if (brightness >= LED_FULL)
0673         return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
0674                       curr | ECO_LED_ON);
0675     else
0676         return call_fext_func(device, FUNC_LEDS, 0x1, ECO_LED,
0677                       curr & ~ECO_LED_ON);
0678 }
0679 
0680 static enum led_brightness eco_led_get(struct led_classdev *cdev)
0681 {
0682     struct acpi_device *device = to_acpi_device(cdev->dev->parent);
0683     enum led_brightness brightness = LED_OFF;
0684 
0685     if (call_fext_func(device, FUNC_LEDS, 0x2, ECO_LED, 0x0) & ECO_LED_ON)
0686         brightness = LED_FULL;
0687 
0688     return brightness;
0689 }
0690 
0691 static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device)
0692 {
0693     struct fujitsu_laptop *priv = acpi_driver_data(device);
0694     struct led_classdev *led;
0695     int ret;
0696 
0697     if (call_fext_func(device,
0698                FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
0699         led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
0700         if (!led)
0701             return -ENOMEM;
0702 
0703         led->name = "fujitsu::logolamp";
0704         led->brightness_set_blocking = logolamp_set;
0705         led->brightness_get = logolamp_get;
0706         ret = devm_led_classdev_register(&device->dev, led);
0707         if (ret)
0708             return ret;
0709     }
0710 
0711     if ((call_fext_func(device,
0712                 FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
0713         (call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
0714         led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
0715         if (!led)
0716             return -ENOMEM;
0717 
0718         led->name = "fujitsu::kblamps";
0719         led->brightness_set_blocking = kblamps_set;
0720         led->brightness_get = kblamps_get;
0721         ret = devm_led_classdev_register(&device->dev, led);
0722         if (ret)
0723             return ret;
0724     }
0725 
0726     /*
0727      * Some Fujitsu laptops have a radio toggle button in place of a slide
0728      * switch and all such machines appear to also have an RF LED.  Based on
0729      * comparing DSDT tables of four Fujitsu Lifebook models (E744, E751,
0730      * S7110, S8420; the first one has a radio toggle button, the other
0731      * three have slide switches), bit 17 of flags_supported (the value
0732      * returned by method S000 of ACPI device FUJ02E3) seems to indicate
0733      * whether given model has a radio toggle button.
0734      */
0735     if (priv->flags_supported & BIT(17)) {
0736         led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
0737         if (!led)
0738             return -ENOMEM;
0739 
0740         led->name = "fujitsu::radio_led";
0741         led->brightness_set_blocking = radio_led_set;
0742         led->brightness_get = radio_led_get;
0743         led->default_trigger = "rfkill-any";
0744         ret = devm_led_classdev_register(&device->dev, led);
0745         if (ret)
0746             return ret;
0747     }
0748 
0749     /* Support for eco led is not always signaled in bit corresponding
0750      * to the bit used to control the led. According to the DSDT table,
0751      * bit 14 seems to indicate presence of said led as well.
0752      * Confirm by testing the status.
0753      */
0754     if ((call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & BIT(14)) &&
0755         (call_fext_func(device,
0756                 FUNC_LEDS, 0x2, ECO_LED, 0x0) != UNSUPPORTED_CMD)) {
0757         led = devm_kzalloc(&device->dev, sizeof(*led), GFP_KERNEL);
0758         if (!led)
0759             return -ENOMEM;
0760 
0761         led->name = "fujitsu::eco_led";
0762         led->brightness_set_blocking = eco_led_set;
0763         led->brightness_get = eco_led_get;
0764         ret = devm_led_classdev_register(&device->dev, led);
0765         if (ret)
0766             return ret;
0767     }
0768 
0769     return 0;
0770 }
0771 
0772 static int acpi_fujitsu_laptop_add(struct acpi_device *device)
0773 {
0774     struct fujitsu_laptop *priv;
0775     int ret, i = 0;
0776 
0777     priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL);
0778     if (!priv)
0779         return -ENOMEM;
0780 
0781     WARN_ONCE(fext, "More than one FUJ02E3 ACPI device was found.  Driver may not work as intended.");
0782     fext = device;
0783 
0784     strcpy(acpi_device_name(device), ACPI_FUJITSU_LAPTOP_DEVICE_NAME);
0785     strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS);
0786     device->driver_data = priv;
0787 
0788     /* kfifo */
0789     spin_lock_init(&priv->fifo_lock);
0790     ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int),
0791               GFP_KERNEL);
0792     if (ret)
0793         return ret;
0794 
0795     pr_info("ACPI: %s [%s]\n",
0796         acpi_device_name(device), acpi_device_bid(device));
0797 
0798     while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 &&
0799            i++ < MAX_HOTKEY_RINGBUFFER_SIZE)
0800         ; /* No action, result is discarded */
0801     acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n",
0802               i);
0803 
0804     priv->flags_supported = call_fext_func(device, FUNC_FLAGS, 0x0, 0x0,
0805                            0x0);
0806 
0807     /* Make sure our bitmask of supported functions is cleared if the
0808        RFKILL function block is not implemented, like on the S7020. */
0809     if (priv->flags_supported == UNSUPPORTED_CMD)
0810         priv->flags_supported = 0;
0811 
0812     if (priv->flags_supported)
0813         priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
0814                            0x0);
0815 
0816     /* Suspect this is a keymap of the application panel, print it */
0817     acpi_handle_info(device->handle, "BTNI: [0x%x]\n",
0818              call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0));
0819 
0820     /* Sync backlight power status */
0821     if (fujitsu_bl && fujitsu_bl->bl_device &&
0822         acpi_video_get_backlight_type() == acpi_backlight_vendor) {
0823         if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
0824                    BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
0825             fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN;
0826         else
0827             fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK;
0828     }
0829 
0830     ret = acpi_fujitsu_laptop_input_setup(device);
0831     if (ret)
0832         goto err_free_fifo;
0833 
0834     ret = acpi_fujitsu_laptop_leds_register(device);
0835     if (ret)
0836         goto err_free_fifo;
0837 
0838     ret = fujitsu_laptop_platform_add(device);
0839     if (ret)
0840         goto err_free_fifo;
0841 
0842     return 0;
0843 
0844 err_free_fifo:
0845     kfifo_free(&priv->fifo);
0846 
0847     return ret;
0848 }
0849 
0850 static int acpi_fujitsu_laptop_remove(struct acpi_device *device)
0851 {
0852     struct fujitsu_laptop *priv = acpi_driver_data(device);
0853 
0854     fujitsu_laptop_platform_remove(device);
0855 
0856     kfifo_free(&priv->fifo);
0857 
0858     return 0;
0859 }
0860 
0861 static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode)
0862 {
0863     struct fujitsu_laptop *priv = acpi_driver_data(device);
0864     int ret;
0865 
0866     ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode,
0867                   sizeof(scancode), &priv->fifo_lock);
0868     if (ret != sizeof(scancode)) {
0869         dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n",
0870              scancode);
0871         return;
0872     }
0873     sparse_keymap_report_event(priv->input, scancode, 1, false);
0874     dev_dbg(&priv->input->dev, "Push scancode into ringbuffer [0x%x]\n",
0875         scancode);
0876 }
0877 
0878 static void acpi_fujitsu_laptop_release(struct acpi_device *device)
0879 {
0880     struct fujitsu_laptop *priv = acpi_driver_data(device);
0881     int scancode, ret;
0882 
0883     while (true) {
0884         ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode,
0885                        sizeof(scancode), &priv->fifo_lock);
0886         if (ret != sizeof(scancode))
0887             return;
0888         sparse_keymap_report_event(priv->input, scancode, 0, false);
0889         dev_dbg(&priv->input->dev,
0890             "Pop scancode from ringbuffer [0x%x]\n", scancode);
0891     }
0892 }
0893 
0894 static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event)
0895 {
0896     struct fujitsu_laptop *priv = acpi_driver_data(device);
0897     unsigned long flags;
0898     int scancode, i = 0;
0899     unsigned int irb;
0900 
0901     if (event != ACPI_FUJITSU_NOTIFY_CODE) {
0902         acpi_handle_info(device->handle, "Unsupported event [0x%x]\n",
0903                  event);
0904         sparse_keymap_report_event(priv->input, -1, 1, true);
0905         return;
0906     }
0907 
0908     if (priv->flags_supported)
0909         priv->flags_state = call_fext_func(device, FUNC_FLAGS, 0x4, 0x0,
0910                            0x0);
0911 
0912     while ((irb = call_fext_func(device,
0913                      FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0 &&
0914            i++ < MAX_HOTKEY_RINGBUFFER_SIZE) {
0915         scancode = irb & 0x4ff;
0916         if (sparse_keymap_entry_from_scancode(priv->input, scancode))
0917             acpi_fujitsu_laptop_press(device, scancode);
0918         else if (scancode == 0)
0919             acpi_fujitsu_laptop_release(device);
0920         else
0921             acpi_handle_info(device->handle,
0922                      "Unknown GIRB result [%x]\n", irb);
0923     }
0924 
0925     /*
0926      * First seen on the Skylake-based Lifebook E736/E746/E756), the
0927      * touchpad toggle hotkey (Fn+F4) is handled in software. Other models
0928      * have since added additional "soft keys". These are reported in the
0929      * status flags queried using FUNC_FLAGS.
0930      */
0931     if (priv->flags_supported & (FLAG_SOFTKEYS)) {
0932         flags = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0);
0933         flags &= (FLAG_SOFTKEYS);
0934         for_each_set_bit(i, &flags, BITS_PER_LONG)
0935             sparse_keymap_report_event(priv->input, BIT(i), 1, true);
0936     }
0937 }
0938 
0939 /* Initialization */
0940 
0941 static const struct acpi_device_id fujitsu_bl_device_ids[] = {
0942     {ACPI_FUJITSU_BL_HID, 0},
0943     {"", 0},
0944 };
0945 
0946 static struct acpi_driver acpi_fujitsu_bl_driver = {
0947     .name = ACPI_FUJITSU_BL_DRIVER_NAME,
0948     .class = ACPI_FUJITSU_CLASS,
0949     .ids = fujitsu_bl_device_ids,
0950     .ops = {
0951         .add = acpi_fujitsu_bl_add,
0952         .notify = acpi_fujitsu_bl_notify,
0953         },
0954 };
0955 
0956 static const struct acpi_device_id fujitsu_laptop_device_ids[] = {
0957     {ACPI_FUJITSU_LAPTOP_HID, 0},
0958     {"", 0},
0959 };
0960 
0961 static struct acpi_driver acpi_fujitsu_laptop_driver = {
0962     .name = ACPI_FUJITSU_LAPTOP_DRIVER_NAME,
0963     .class = ACPI_FUJITSU_CLASS,
0964     .ids = fujitsu_laptop_device_ids,
0965     .ops = {
0966         .add = acpi_fujitsu_laptop_add,
0967         .remove = acpi_fujitsu_laptop_remove,
0968         .notify = acpi_fujitsu_laptop_notify,
0969         },
0970 };
0971 
0972 static const struct acpi_device_id fujitsu_ids[] __used = {
0973     {ACPI_FUJITSU_BL_HID, 0},
0974     {ACPI_FUJITSU_LAPTOP_HID, 0},
0975     {"", 0}
0976 };
0977 MODULE_DEVICE_TABLE(acpi, fujitsu_ids);
0978 
0979 static int __init fujitsu_init(void)
0980 {
0981     int ret;
0982 
0983     ret = acpi_bus_register_driver(&acpi_fujitsu_bl_driver);
0984     if (ret)
0985         return ret;
0986 
0987     /* Register platform stuff */
0988 
0989     ret = platform_driver_register(&fujitsu_pf_driver);
0990     if (ret)
0991         goto err_unregister_acpi;
0992 
0993     /* Register laptop driver */
0994 
0995     ret = acpi_bus_register_driver(&acpi_fujitsu_laptop_driver);
0996     if (ret)
0997         goto err_unregister_platform_driver;
0998 
0999     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");