0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
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
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
0075 #define UNSUPPORTED_CMD 0x80000000
0076
0077
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
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
0096 #define BACKLIGHT_PARAM_POWER BIT(2)
0097 #define BACKLIGHT_OFF (BIT(0) | BIT(1))
0098 #define BACKLIGHT_ON 0
0099
0100
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
0108 #define MAX_HOTKEY_RINGBUFFER_SIZE 100
0109 #define RINGBUFFERSIZE 40
0110
0111
0112 static int use_alt_lcd_levels = -1;
0113 static bool disable_brightness_adjust;
0114
0115
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
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
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
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
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
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
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
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
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 } },
0463 { KE_KEY, KEY2_CODE, { KEY_HELP } },
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 } },
0471 { KE_KEY, KEY2_CODE, { KEY_PROG2 } },
0472 { KE_KEY, KEY3_CODE, { KEY_SWITCHVIDEOMODE } },
0473 { KE_KEY, KEY4_CODE, { KEY_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
0728
0729
0730
0731
0732
0733
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
0750
0751
0752
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
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 ;
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
0808
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
0817 acpi_handle_info(device->handle, "BTNI: [0x%x]\n",
0818 call_fext_func(device, FUNC_BUTTONS, 0x0, 0x0, 0x0));
0819
0820
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
0927
0928
0929
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
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
0988
0989 ret = platform_driver_register(&fujitsu_pf_driver);
0990 if (ret)
0991 goto err_unregister_acpi;
0992
0993
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");