diff options
Diffstat (limited to 'drivers/platform/x86/fujitsu-laptop.c')
-rw-r--r-- | drivers/platform/x86/fujitsu-laptop.c | 199 |
1 files changed, 106 insertions, 93 deletions
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index 2cfbd3fa5136..cd95b6f3a064 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c @@ -53,6 +53,7 @@ #include <linux/kernel.h> #include <linux/init.h> #include <linux/acpi.h> +#include <linux/bitops.h> #include <linux/dmi.h> #include <linux/backlight.h> #include <linux/fb.h> @@ -61,12 +62,11 @@ #include <linux/kfifo.h> #include <linux/leds.h> #include <linux/platform_device.h> -#include <linux/slab.h> #include <acpi/video.h> -#define FUJITSU_DRIVER_VERSION "0.6.0" +#define FUJITSU_DRIVER_VERSION "0.6.0" -#define FUJITSU_LCD_N_LEVELS 8 +#define FUJITSU_LCD_N_LEVELS 8 #define ACPI_FUJITSU_CLASS "fujitsu" #define ACPI_FUJITSU_BL_HID "FUJ02B1" @@ -76,41 +76,51 @@ #define ACPI_FUJITSU_LAPTOP_DRIVER_NAME "Fujitsu laptop FUJ02E3 ACPI hotkeys driver" #define ACPI_FUJITSU_LAPTOP_DEVICE_NAME "Fujitsu FUJ02E3" -#define ACPI_FUJITSU_NOTIFY_CODE1 0x80 +#define ACPI_FUJITSU_NOTIFY_CODE 0x80 /* FUNC interface - command values */ -#define FUNC_FLAGS 0x1000 -#define FUNC_LEDS 0x1001 -#define FUNC_BUTTONS 0x1002 -#define FUNC_BACKLIGHT 0x1004 +#define FUNC_FLAGS BIT(12) +#define FUNC_LEDS (BIT(12) | BIT(0)) +#define FUNC_BUTTONS (BIT(12) | BIT(1)) +#define FUNC_BACKLIGHT (BIT(12) | BIT(2)) /* FUNC interface - responses */ -#define UNSUPPORTED_CMD 0x80000000 +#define UNSUPPORTED_CMD 0x80000000 /* FUNC interface - status flags */ -#define FLAG_RFKILL 0x020 -#define FLAG_LID 0x100 -#define FLAG_DOCK 0x200 +#define FLAG_RFKILL BIT(5) +#define FLAG_LID BIT(8) +#define FLAG_DOCK BIT(9) /* FUNC interface - LED control */ -#define FUNC_LED_OFF 0x1 -#define FUNC_LED_ON 0x30001 -#define KEYBOARD_LAMPS 0x100 -#define LOGOLAMP_POWERON 0x2000 -#define LOGOLAMP_ALWAYS 0x4000 -#define RADIO_LED_ON 0x20 -#define ECO_LED 0x10000 -#define ECO_LED_ON 0x80000 - -/* Hotkey details */ -#define KEY1_CODE 0x410 /* codes for the keys in the GIRB register */ -#define KEY2_CODE 0x411 -#define KEY3_CODE 0x412 -#define KEY4_CODE 0x413 -#define KEY5_CODE 0x420 - -#define MAX_HOTKEY_RINGBUFFER_SIZE 100 -#define RINGBUFFERSIZE 40 +#define FUNC_LED_OFF BIT(0) +#define FUNC_LED_ON (BIT(0) | BIT(16) | BIT(17)) +#define LOGOLAMP_POWERON BIT(13) +#define LOGOLAMP_ALWAYS BIT(14) +#define KEYBOARD_LAMPS BIT(8) +#define RADIO_LED_ON BIT(5) +#define ECO_LED BIT(16) +#define ECO_LED_ON BIT(19) + +/* FUNC interface - backlight power control */ +#define BACKLIGHT_PARAM_POWER BIT(2) +#define BACKLIGHT_OFF (BIT(0) | BIT(1)) +#define BACKLIGHT_ON 0 + +/* Scancodes read from the GIRB register */ +#define KEY1_CODE 0x410 +#define KEY2_CODE 0x411 +#define KEY3_CODE 0x412 +#define KEY4_CODE 0x413 +#define KEY5_CODE 0x420 + +/* Hotkey ringbuffer limits */ +#define MAX_HOTKEY_RINGBUFFER_SIZE 100 +#define RINGBUFFERSIZE 40 + +/* Module parameters */ +static int use_alt_lcd_levels = -1; +static bool disable_brightness_adjust; /* Device controlling the backlight and associated keys */ struct fujitsu_bl { @@ -122,8 +132,6 @@ struct fujitsu_bl { }; static struct fujitsu_bl *fujitsu_bl; -static int use_alt_lcd_levels = -1; -static bool disable_brightness_adjust; /* Device used to access hotkeys and other features on the laptop */ struct fujitsu_laptop { @@ -256,9 +264,11 @@ static int bl_update_status(struct backlight_device *b) if (fext) { if (b->props.power == FB_BLANK_POWERDOWN) - call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 0x4, 0x3); + call_fext_func(fext, FUNC_BACKLIGHT, 0x1, + BACKLIGHT_PARAM_POWER, BACKLIGHT_OFF); else - call_fext_func(fext, FUNC_BACKLIGHT, 0x1, 0x4, 0x0); + call_fext_func(fext, FUNC_BACKLIGHT, 0x1, + BACKLIGHT_PARAM_POWER, BACKLIGHT_ON); } return set_lcd_level(device, b->props.brightness); @@ -385,7 +395,7 @@ static int fujitsu_backlight_register(struct acpi_device *device) static int acpi_fujitsu_bl_add(struct acpi_device *device) { struct fujitsu_bl *priv; - int error; + int ret; if (acpi_video_get_backlight_type() != acpi_backlight_vendor) return -ENODEV; @@ -399,10 +409,6 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) strcpy(acpi_device_class(device), ACPI_FUJITSU_CLASS); device->driver_data = priv; - error = acpi_fujitsu_bl_input_setup(device); - if (error) - return error; - pr_info("ACPI: %s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); @@ -410,11 +416,11 @@ static int acpi_fujitsu_bl_add(struct acpi_device *device) priv->max_brightness = FUJITSU_LCD_N_LEVELS; get_lcd_level(device); - error = fujitsu_backlight_register(device); - if (error) - return error; + ret = acpi_fujitsu_bl_input_setup(device); + if (ret) + return ret; - return 0; + return fujitsu_backlight_register(device); } /* Brightness notify */ @@ -424,7 +430,7 @@ static void acpi_fujitsu_bl_notify(struct acpi_device *device, u32 event) struct fujitsu_bl *priv = acpi_driver_data(device); int oldb, newb; - if (event != ACPI_FUJITSU_NOTIFY_CODE1) { + if (event != ACPI_FUJITSU_NOTIFY_CODE) { acpi_handle_info(device->handle, "unsupported event [0x%x]\n", event); sparse_keymap_report_event(priv->input, -1, 1, true); @@ -455,7 +461,9 @@ static const struct key_entry keymap_default[] = { { KE_KEY, KEY3_CODE, { KEY_PROG3 } }, { KE_KEY, KEY4_CODE, { KEY_PROG4 } }, { KE_KEY, KEY5_CODE, { KEY_RFKILL } }, + { KE_KEY, BIT(5), { KEY_RFKILL } }, { KE_KEY, BIT(26), { KEY_TOUCHPAD_TOGGLE } }, + { KE_KEY, BIT(29), { KEY_MICMUTE } }, { KE_END, 0 } }; @@ -693,7 +701,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) { struct fujitsu_laptop *priv = acpi_driver_data(device); struct led_classdev *led; - int result; + int ret; if (call_fext_func(device, FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) { @@ -704,9 +712,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) led->name = "fujitsu::logolamp"; led->brightness_set_blocking = logolamp_set; led->brightness_get = logolamp_get; - result = devm_led_classdev_register(&device->dev, led); - if (result) - return result; + ret = devm_led_classdev_register(&device->dev, led); + if (ret) + return ret; } if ((call_fext_func(device, @@ -719,9 +727,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) led->name = "fujitsu::kblamps"; led->brightness_set_blocking = kblamps_set; led->brightness_get = kblamps_get; - result = devm_led_classdev_register(&device->dev, led); - if (result) - return result; + ret = devm_led_classdev_register(&device->dev, led); + if (ret) + return ret; } /* @@ -742,9 +750,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) led->brightness_set_blocking = radio_led_set; led->brightness_get = radio_led_get; led->default_trigger = "rfkill-any"; - result = devm_led_classdev_register(&device->dev, led); - if (result) - return result; + ret = devm_led_classdev_register(&device->dev, led); + if (ret) + return ret; } /* Support for eco led is not always signaled in bit corresponding @@ -762,9 +770,9 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) led->name = "fujitsu::eco_led"; led->brightness_set_blocking = eco_led_set; led->brightness_get = eco_led_get; - result = devm_led_classdev_register(&device->dev, led); - if (result) - return result; + ret = devm_led_classdev_register(&device->dev, led); + if (ret) + return ret; } return 0; @@ -773,8 +781,7 @@ static int acpi_fujitsu_laptop_leds_register(struct acpi_device *device) static int acpi_fujitsu_laptop_add(struct acpi_device *device) { struct fujitsu_laptop *priv; - int error; - int i; + int ret, i = 0; priv = devm_kzalloc(&device->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -789,23 +796,16 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) /* kfifo */ spin_lock_init(&priv->fifo_lock); - error = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int), - GFP_KERNEL); - if (error) { - pr_err("kfifo_alloc failed\n"); - goto err_stop; - } - - error = acpi_fujitsu_laptop_input_setup(device); - if (error) - goto err_free_fifo; + ret = kfifo_alloc(&priv->fifo, RINGBUFFERSIZE * sizeof(int), + GFP_KERNEL); + if (ret) + return ret; pr_info("ACPI: %s [%s]\n", acpi_device_name(device), acpi_device_bid(device)); - i = 0; - while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 - && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) + while (call_fext_func(device, FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0 && + i++ < MAX_HOTKEY_RINGBUFFER_SIZE) ; /* No action, result is discarded */ acpi_handle_debug(device->handle, "Discarded %i ringbuffer entries\n", i); @@ -829,26 +829,31 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device) /* Sync backlight power status */ if (fujitsu_bl && fujitsu_bl->bl_device && acpi_video_get_backlight_type() == acpi_backlight_vendor) { - if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3) + if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2, + BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF) fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN; else fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK; } - error = acpi_fujitsu_laptop_leds_register(device); - if (error) + ret = acpi_fujitsu_laptop_input_setup(device); + if (ret) + goto err_free_fifo; + + ret = acpi_fujitsu_laptop_leds_register(device); + if (ret) goto err_free_fifo; - error = fujitsu_laptop_platform_add(device); - if (error) + ret = fujitsu_laptop_platform_add(device); + if (ret) goto err_free_fifo; return 0; err_free_fifo: kfifo_free(&priv->fifo); -err_stop: - return error; + + return ret; } static int acpi_fujitsu_laptop_remove(struct acpi_device *device) @@ -865,11 +870,11 @@ static int acpi_fujitsu_laptop_remove(struct acpi_device *device) static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode) { struct fujitsu_laptop *priv = acpi_driver_data(device); - int status; + int ret; - status = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode, - sizeof(scancode), &priv->fifo_lock); - if (status != sizeof(scancode)) { + ret = kfifo_in_locked(&priv->fifo, (unsigned char *)&scancode, + sizeof(scancode), &priv->fifo_lock); + if (ret != sizeof(scancode)) { dev_info(&priv->input->dev, "Could not push scancode [0x%x]\n", scancode); return; @@ -882,13 +887,12 @@ static void acpi_fujitsu_laptop_press(struct acpi_device *device, int scancode) static void acpi_fujitsu_laptop_release(struct acpi_device *device) { struct fujitsu_laptop *priv = acpi_driver_data(device); - int scancode, status; + int scancode, ret; while (true) { - status = kfifo_out_locked(&priv->fifo, - (unsigned char *)&scancode, - sizeof(scancode), &priv->fifo_lock); - if (status != sizeof(scancode)) + ret = kfifo_out_locked(&priv->fifo, (unsigned char *)&scancode, + sizeof(scancode), &priv->fifo_lock); + if (ret != sizeof(scancode)) return; sparse_keymap_report_event(priv->input, scancode, 0, false); dev_dbg(&priv->input->dev, @@ -899,10 +903,10 @@ static void acpi_fujitsu_laptop_release(struct acpi_device *device) static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) { struct fujitsu_laptop *priv = acpi_driver_data(device); - int scancode, i = 0; + int scancode, i = 0, ret; unsigned int irb; - if (event != ACPI_FUJITSU_NOTIFY_CODE1) { + if (event != ACPI_FUJITSU_NOTIFY_CODE) { acpi_handle_info(device->handle, "Unsupported event [0x%x]\n", event); sparse_keymap_report_event(priv->input, -1, 1, true); @@ -930,9 +934,18 @@ static void acpi_fujitsu_laptop_notify(struct acpi_device *device, u32 event) * E736/E746/E756), the touchpad toggle hotkey (Fn+F4) is * handled in software; its state is queried using FUNC_FLAGS */ - if ((priv->flags_supported & BIT(26)) && - (call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0) & BIT(26))) - sparse_keymap_report_event(priv->input, BIT(26), 1, true); + if (priv->flags_supported & (BIT(5) | BIT(26) | BIT(29))) { + ret = call_fext_func(device, FUNC_FLAGS, 0x1, 0x0, 0x0); + if (ret & BIT(5)) + sparse_keymap_report_event(priv->input, + BIT(5), 1, true); + if (ret & BIT(26)) + sparse_keymap_report_event(priv->input, + BIT(26), 1, true); + if (ret & BIT(29)) + sparse_keymap_report_event(priv->input, + BIT(29), 1, true); + } } /* Initialization */ |