Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard backlight on Dell E7470 not adjustable from /sys entry #407

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Keyboard backlight on Dell E7470 not adjustable from /sys entry
https://bugzilla.kernel.org/show_bug.cgi?id=191731
https://bugzilla.redhat.com/show_bug.cgi?id=1436686

Also fixes
dell_laptop: Setting old previous keyboard state failed
https://bugzilla.kernel.org/show_bug.cgi?id=194081

The issue is actually quite trivial. Byte 3 of kbd_state
on some machines contains "timeout_ac". If this byte is simply
set to 0 the result is failed state set. The "timeout_ac" is not
interpreted in any way, but it is now preserved in order to ensure
the LED state changes go through.
  • Loading branch information
arcivanov committed Apr 23, 2017
commit 250168ad3c58a0482dc57320c9ed1bd26858bd7f
53 changes: 53 additions & 0 deletions drivers/platform/x86/dell-laptop.c
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,15 @@ static void touchpad_led_exit(void)
* cbRES3, byte0 Current setting of ALS value that turns the light on or off.
* cbRES3, byte1 Current ALS reading
* cbRES3, byte2 Current keyboard light level.
* cbRES3, byte3 Current timeout, on AC Power Bits
* 7:6 Timeout units indicator:
* 00b Seconds
* 01b Minutes
* 10b Hours
* 11b Days
* Bits 5:0 Timeout value (0-63) in sec/min/hr/day
* NOTE: A value of 0 means always on (no timeout) if any bits of RES3 byte2
* are set upon return from the upon return from the [Get Feature information] call.
*
* cbArg1 0x2 = Set New State
* cbRES1 Standard return codes (0, -1, -2)
Expand Down Expand Up @@ -1067,6 +1076,13 @@ static void touchpad_led_exit(void)
* bits 5:0 Timeout value (0-63) in sec/min/hr/day
* cbArg3, byte0 Desired setting of ALS value that turns the light on or off.
* cbArg3, byte2 Desired keyboard light level.
* cbArg3, byte3 Desired Timeout on AC power
* bits 7:6 Timeout units indicator:
* 00b Seconds
* 01b Minutes
* 10b Hours
* 11b Days
* bits 5:0 Timeout value (0-63) in sec/min/hr/day
*/


Expand Down Expand Up @@ -1115,6 +1131,7 @@ struct kbd_state {
u8 als_setting;
u8 als_value;
u8 level;
u8 timeout_ac;
};

static const int kbd_tokens[] = {
Expand All @@ -1140,6 +1157,25 @@ static u8 kbd_previous_mode_bit;

static bool kbd_led_present;

#define pr_kbd_smi(x) \
pr_debug("func %s\n\tinputs: %#010x %#010x %#010x %#010x, outputs: %#010x %#010x %#010x %#010x", \
__func__, \
x->input[0], x->input[1], x->input[2], x->input[3],\
x->output[0], x->output[1], x->output[2], x->output[3])

#define pr_kbd_state(x) \
pr_debug("func %s\n\tmode_bit: %#04x, triggers: %#04x, timeout_value: %#04x, timeout_unit: %#04x, " \
"als_setting: %#04x, als_value: %#04x, level: %#04x, timeout_ac: %#04x", \
__func__, \
x->mode_bit, x->triggers, x->timeout_value, x->timeout_unit, x->als_setting, x->als_value, x->level, \
x->timeout_ac)

#define pr_kbd_info(x) \
pr_debug("func %s\n\tmodes: %#06x, type: %#04x, triggers: %#04x, levels: %#04x, seconds: %#04x, " \
"minutes: %#04x, hours: %#04x, days: %#04x", \
__func__, \
x->modes, x->type, x->triggers, x->levels, x->seconds, x->minutes, x->hours, x->days)

/*
* NOTE: there are three ways to set the keyboard backlight level.
* First, via kbd_state.mode_bit (assigning KBD_MODE_BIT_TRIGGER_* value).
Expand All @@ -1165,6 +1201,8 @@ static int kbd_get_info(struct kbd_info *info)
dell_smbios_send_request(4, 11);
ret = buffer->output[0];

pr_kbd_smi(buffer);

if (ret) {
ret = dell_smbios_error(ret);
goto out;
Expand All @@ -1185,6 +1223,8 @@ static int kbd_get_info(struct kbd_info *info)
if (units & BIT(3))
info->days = (buffer->output[3] >> 24) & 0xFF;

pr_kbd_info(info);

out:
dell_smbios_release_buffer();
return ret;
Expand Down Expand Up @@ -1252,6 +1292,9 @@ static int kbd_get_state(struct kbd_state *state)

buffer->input[0] = 0x1;
dell_smbios_send_request(4, 11);

pr_kbd_smi(buffer);

ret = buffer->output[0];

if (ret) {
Expand All @@ -1269,6 +1312,9 @@ static int kbd_get_state(struct kbd_state *state)
state->als_setting = buffer->output[2] & 0xFF;
state->als_value = (buffer->output[2] >> 8) & 0xFF;
state->level = (buffer->output[2] >> 16) & 0xFF;
state->timeout_ac = (buffer->output[2] >> 24) & 0xFF;

pr_kbd_state(state);

out:
dell_smbios_release_buffer();
Expand All @@ -1280,6 +1326,8 @@ static int kbd_set_state(struct kbd_state *state)
struct calling_interface_buffer *buffer;
int ret;

pr_kbd_state(state);

buffer = dell_smbios_get_buffer();
buffer->input[0] = 0x2;
buffer->input[1] = BIT(state->mode_bit) & 0xFFFF;
Expand All @@ -1288,6 +1336,10 @@ static int kbd_set_state(struct kbd_state *state)
buffer->input[1] |= (state->timeout_unit & 0x3) << 30;
buffer->input[2] = state->als_setting & 0xFF;
buffer->input[2] |= (state->level & 0xFF) << 16;
buffer->input[2] |= (state->timeout_ac & 0xFF) << 24;

pr_kbd_smi(buffer);

dell_smbios_send_request(4, 11);
ret = buffer->output[0];
dell_smbios_release_buffer();
Expand Down Expand Up @@ -1455,6 +1507,7 @@ static inline int kbd_init_info(void)
kbd_mode_levels_count++;
}

pr_kbd_info((&kbd_info));
return 0;

}
Expand Down