59 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
61 #include <linux/module.h>
62 #include <linux/kernel.h>
67 #include <linux/input.h>
71 #include <linux/slab.h>
72 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
76 #define FUJITSU_DRIVER_VERSION "0.6.0"
78 #define FUJITSU_LCD_N_LEVELS 8
80 #define ACPI_FUJITSU_CLASS "fujitsu"
81 #define ACPI_FUJITSU_HID "FUJ02B1"
82 #define ACPI_FUJITSU_DRIVER_NAME "Fujitsu laptop FUJ02B1 ACPI brightness driver"
83 #define ACPI_FUJITSU_DEVICE_NAME "Fujitsu FUJ02B1"
84 #define ACPI_FUJITSU_HOTKEY_HID "FUJ02E3"
85 #define ACPI_FUJITSU_HOTKEY_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver"
86 #define ACPI_FUJITSU_HOTKEY_DEVICE_NAME "Fujitsu FUJ02E3"
88 #define ACPI_FUJITSU_NOTIFY_CODE1 0x80
90 #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS 0x86
91 #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS 0x87
94 #define FUNC_RFKILL 0x1000
95 #define FUNC_LEDS 0x1001
96 #define FUNC_BUTTONS 0x1002
97 #define FUNC_BACKLIGHT 0x1004
100 #define UNSUPPORTED_CMD 0x80000000
102 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
104 #define FUNC_LED_OFF 0x1
105 #define FUNC_LED_ON 0x30001
106 #define KEYBOARD_LAMPS 0x100
107 #define LOGOLAMP_POWERON 0x2000
108 #define LOGOLAMP_ALWAYS 0x4000
112 #define KEY1_CODE 0x410
113 #define KEY2_CODE 0x411
114 #define KEY3_CODE 0x412
115 #define KEY4_CODE 0x413
117 #define MAX_HOTKEY_RINGBUFFER_SIZE 100
118 #define RINGBUFFERSIZE 40
121 #define FUJLAPTOP_LOG ACPI_FUJITSU_HID ": "
122 #define FUJLAPTOP_ERR KERN_ERR FUJLAPTOP_LOG
123 #define FUJLAPTOP_NOTICE KERN_NOTICE FUJLAPTOP_LOG
124 #define FUJLAPTOP_INFO KERN_INFO FUJLAPTOP_LOG
125 #define FUJLAPTOP_DEBUG KERN_DEBUG FUJLAPTOP_LOG
127 #define FUJLAPTOP_DBG_ALL 0xffff
128 #define FUJLAPTOP_DBG_ERROR 0x0001
129 #define FUJLAPTOP_DBG_WARN 0x0002
130 #define FUJLAPTOP_DBG_INFO 0x0004
131 #define FUJLAPTOP_DBG_TRACE 0x0008
133 #define dbg_printk(a_dbg_level, format, arg...) \
134 do { if (dbg_level & a_dbg_level) \
135 printk(FUJLAPTOP_DEBUG "%s: " format, __func__ , ## arg); \
137 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
138 #define vdbg_printk(a_dbg_level, format, arg...) \
139 dbg_printk(a_dbg_level, format, ## arg)
141 #define vdbg_printk(a_dbg_level, format, arg...)
160 static int use_alt_lcd_levels = -1;
161 static int disable_brightness_adjust = -1;
180 static void acpi_fujitsu_hotkey_notify(
struct acpi_device *
device,
u32 event);
182 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
188 .
name =
"fujitsu::logolamp",
189 .brightness_get = logolamp_get,
190 .brightness_set = logolamp_set
198 .
name =
"fujitsu::kblamps",
199 .brightness_get = kblamps_get,
200 .brightness_set = kblamps_set
204 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
205 static u32 dbg_level = 0x03;
208 static void acpi_fujitsu_notify(
struct acpi_device *
device,
u32 event);
212 static int call_fext_func(
int cmd,
int arg0,
int arg1,
int arg2)
229 "FUNC interface is not present\n");
234 params[1].
integer.value = arg0;
238 output.length =
sizeof(out_obj);
239 output.pointer = &out_obj;
244 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
245 cmd, arg0, arg1, arg2);
251 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not "
252 "return an integer\n",
253 cmd, arg0, arg1, arg2);
258 "FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
259 cmd, arg0, arg1, arg2, (
int)out_obj.integer.value);
260 return out_obj.integer.value;
263 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
270 call_fext_func(
FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
271 call_fext_func(
FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON);
272 }
else if (brightness >=
LED_HALF) {
273 call_fext_func(
FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
274 call_fext_func(
FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF);
276 call_fext_func(
FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF);
284 call_fext_func(
FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
286 call_fext_func(
FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
294 poweron = call_fext_func(
FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
295 if (poweron == FUNC_LED_ON) {
297 always = call_fext_func(
FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
298 if (always == FUNC_LED_ON)
308 if (call_fext_func(
FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
317 static int set_lcd_level(
int level)
345 static int set_lcd_level_alt(
int level)
373 static int get_lcd_level(
void)
375 unsigned long long state = 0;
387 if (state & 0x80000000)
395 static int get_max_brightness(
void)
397 unsigned long long state = 0;
416 return get_lcd_level();
422 if (b->
props.power == 4)
428 "Unable to adjust backlight power, error code %i\n",
431 if (use_alt_lcd_levels)
432 ret = set_lcd_level_alt(b->
props.brightness);
434 ret = set_lcd_level(b->
props.brightness);
437 "Unable to adjust LCD brightness, error code %i\n",
443 .get_brightness = bl_get_brightness,
444 .update_status = bl_update_status,
456 ret = get_max_brightness();
460 return sprintf(buf,
"%i\n", ret);
464 show_brightness_changed(
struct device *dev,
474 return sprintf(buf,
"%i\n", ret);
483 ret = get_lcd_level();
487 return sprintf(buf,
"%i\n", ret);
497 if (
sscanf(buf,
"%i", &level) != 1
501 if (use_alt_lcd_levels)
502 ret = set_lcd_level_alt(level);
504 ret = set_lcd_level(level);
508 ret = get_lcd_level();
516 ignore_store(
struct device *dev,
523 show_lid_state(
struct device *dev,
527 return sprintf(buf,
"unknown\n");
531 return sprintf(buf,
"closed\n");
535 show_dock_state(
struct device *dev,
539 return sprintf(buf,
"unknown\n");
541 return sprintf(buf,
"docked\n");
543 return sprintf(buf,
"undocked\n");
547 show_radios_state(
struct device *dev,
551 return sprintf(buf,
"unknown\n");
555 return sprintf(buf,
"killed\n");
558 static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
559 static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
561 static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
563 static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store);
564 static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store);
566 static struct attribute *fujitsupf_attributes[] = {
567 &dev_attr_brightness_changed.attr,
568 &dev_attr_max_brightness.attr,
569 &dev_attr_lcd_level.attr,
572 &dev_attr_radios.attr,
577 .attrs = fujitsupf_attributes
582 .name =
"fujitsu-laptop",
587 static void dmi_check_cb_common(
const struct dmi_system_id *
id)
591 if (use_alt_lcd_levels == -1) {
593 "\\_SB.PCI0.LPCB.FJEX.SBL2", &handle)))
594 use_alt_lcd_levels = 1;
596 use_alt_lcd_levels = 0;
598 "%i\n", use_alt_lcd_levels);
602 static int dmi_check_cb_s6410(
const struct dmi_system_id *
id)
604 dmi_check_cb_common(
id);
610 static int dmi_check_cb_s6420(
const struct dmi_system_id *
id)
612 dmi_check_cb_common(
id);
618 static int dmi_check_cb_p8010(
const struct dmi_system_id *
id)
620 dmi_check_cb_common(
id);
629 .ident =
"Fujitsu Siemens S6410",
634 .callback = dmi_check_cb_s6410},
636 .ident =
"Fujitsu Siemens S6420",
641 .callback = dmi_check_cb_s6420},
643 .ident =
"Fujitsu LifeBook P8010",
648 .callback = dmi_check_cb_p8010},
654 static int acpi_fujitsu_add(
struct acpi_device *
device)
659 struct input_dev *
input;
668 device->driver_data = fujitsu;
670 fujitsu->
input = input = input_allocate_device();
679 input->name = acpi_device_name(device);
680 input->phys = fujitsu->
phys;
682 input->id.product = 0x06;
683 input->dev.parent = &device->dev;
689 error = input_register_device(input);
691 goto err_free_input_dev;
695 pr_err(
"Error reading power state\n");
696 goto err_unregister_input_dev;
699 pr_info(
"ACPI: %s [%s] (%s)\n",
700 acpi_device_name(device), acpi_device_bid(device),
701 !device->power.state ?
"on" :
"off");
703 fujitsu->
dev = device;
711 pr_err(
"_INI Method failed\n");
715 use_alt_lcd_levels = use_alt_lcd_levels == 1 ? 1 : 0;
716 disable_brightness_adjust = disable_brightness_adjust == 1 ? 1 : 0;
718 "config: [alt interface: %d], [adjust disable: %d]\n",
719 use_alt_lcd_levels, disable_brightness_adjust);
721 if (get_max_brightness() <= 0)
727 err_unregister_input_dev:
728 input_unregister_device(input);
731 input_free_device(input);
736 static int acpi_fujitsu_remove(
struct acpi_device *device,
int type)
738 struct fujitsu_t *fujitsu = acpi_driver_data(device);
739 struct input_dev *input = fujitsu->
input;
741 input_unregister_device(input);
750 static void acpi_fujitsu_notify(
struct acpi_device *device,
u32 event)
752 struct input_dev *
input;
756 input = fujitsu->
input;
766 "brightness button event [%i -> %i (%i)]\n",
770 if (disable_brightness_adjust != 1) {
771 if (use_alt_lcd_levels)
772 set_lcd_level_alt(newb);
776 acpi_bus_generate_proc_event(fujitsu->
dev,
779 }
else if (oldb > newb) {
780 if (disable_brightness_adjust != 1) {
781 if (use_alt_lcd_levels)
782 set_lcd_level_alt(newb);
786 acpi_bus_generate_proc_event(fujitsu->
dev,
794 "unsupported event [0x%x]\n", event);
799 input_report_key(input, keycode, 1);
801 input_report_key(input, keycode, 0);
808 static int acpi_fujitsu_hotkey_add(
struct acpi_device *device)
813 struct input_dev *
input;
821 sprintf(acpi_device_name(device),
"%s",
824 device->driver_data = fujitsu_hotkey;
831 pr_err(
"kfifo_alloc failed\n");
835 fujitsu_hotkey->
input = input = input_allocate_device();
844 input->name = acpi_device_name(device);
845 input->phys = fujitsu_hotkey->
phys;
847 input->id.product = 0x06;
848 input->dev.parent = &device->dev;
857 error = input_register_device(input);
859 goto err_free_input_dev;
863 pr_err(
"Error reading power state\n");
864 goto err_unregister_input_dev;
867 pr_info(
"ACPI: %s [%s] (%s)\n",
868 acpi_device_name(device), acpi_device_bid(device),
869 !device->power.state ?
"on" :
"off");
871 fujitsu_hotkey->
dev = device;
879 pr_err(
"_INI Method failed\n");
903 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
904 if (call_fext_func(
FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
910 pr_err(
"Could not register LED handler for logo lamp, error %i\n",
915 if ((call_fext_func(
FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
922 pr_err(
"Could not register LED handler for keyboard lamps, error %i\n",
930 err_unregister_input_dev:
931 input_unregister_device(input);
934 input_free_device(input);
941 static int acpi_fujitsu_hotkey_remove(
struct acpi_device *device,
int type)
944 struct input_dev *input = fujitsu_hotkey->
input;
946 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
954 input_unregister_device(input);
963 static void acpi_fujitsu_hotkey_notify(
struct acpi_device *device,
u32 event)
965 struct input_dev *
input;
967 unsigned int irb = 1;
970 input = fujitsu_hotkey->
input;
982 switch (irb & 0x4ff) {
1000 "Unknown GIRB result [%x]\n", irb);
1006 "Push keycode into ringbuffer [%d]\n",
1009 (
unsigned char *)&keycode,
1012 if (status !=
sizeof(keycode)) {
1014 "Could not push keycode [0x%x]\n",
1017 input_report_key(input, keycode, 1);
1020 }
else if (keycode == 0) {
1023 &fujitsu_hotkey->
fifo,
1024 (
unsigned char *) &keycode_r,
1027 ==
sizeof(keycode_r)) {
1028 input_report_key(input, keycode_r, 0);
1031 "Pop keycode from ringbuffer [%d]\n",
1041 "Unsupported event [0x%x]\n", event);
1042 input_report_key(input, keycode, 1);
1044 input_report_key(input, keycode, 0);
1057 static struct acpi_driver acpi_fujitsu_driver = {
1060 .ids = fujitsu_device_ids,
1062 .add = acpi_fujitsu_add,
1063 .remove = acpi_fujitsu_remove,
1064 .notify = acpi_fujitsu_notify,
1068 static const struct acpi_device_id fujitsu_hotkey_device_ids[] = {
1073 static struct acpi_driver acpi_fujitsu_hotkey_driver = {
1076 .ids = fujitsu_hotkey_device_ids,
1078 .add = acpi_fujitsu_hotkey_add,
1079 .remove = acpi_fujitsu_hotkey_remove,
1080 .notify = acpi_fujitsu_hotkey_notify,
1084 static int __init fujitsu_init(
void)
1111 goto fail_platform_driver;
1116 goto fail_platform_device1;
1120 &fujitsupf_attribute_group);
1122 goto fail_platform_device2;
1132 props.max_brightness = max_brightness - 1;
1140 goto fail_sysfs_group;
1147 goto fail_backlight;
1152 if (!fujitsu_hotkey) {
1177 kfree(fujitsu_hotkey);
1185 &fujitsupf_attribute_group);
1186 fail_platform_device2:
1188 fail_platform_device1:
1190 fail_platform_driver:
1198 static void __exit fujitsu_cleanup(
void)
1202 kfree(fujitsu_hotkey);
1210 &fujitsupf_attribute_group);
1226 "Use alternative interface for lcd_levels (needed for Lifebook s6410).");
1228 MODULE_PARM_DESC(disable_brightness_adjust,
"Disable brightness adjustment .");
1229 #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
1239 MODULE_ALIAS(
"dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
1240 MODULE_ALIAS(
"dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
1241 MODULE_ALIAS(
"dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");