mirror of
https://github.com/wessel-novacustom/clevo-keyboard.git
synced 2024-11-15 03:34:01 +01:00
Merge remote-tracking branch 'origin/generalize_keyboard_backlight_brightness' into upcoming-release
This commit is contained in:
commit
b963225cf7
|
@ -32,7 +32,7 @@ struct clevo_acpi_driver_data_t {
|
|||
|
||||
static struct clevo_acpi_driver_data_t *active_driver_data = NULL;
|
||||
|
||||
static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg, u32 *result)
|
||||
static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg, union acpi_object **result)
|
||||
{
|
||||
u32 status;
|
||||
acpi_handle handle;
|
||||
|
@ -69,23 +69,17 @@ static u32 clevo_acpi_evaluate(struct acpi_device *device, u8 cmd, u32 arg, u32
|
|||
if (!out_obj) {
|
||||
pr_err("failed to evaluate _DSM\n");
|
||||
status = -1;
|
||||
} else {
|
||||
if (out_obj->type == ACPI_TYPE_INTEGER) {
|
||||
if (!IS_ERR_OR_NULL(result))
|
||||
*result = (u32) out_obj->integer.value;
|
||||
// pr_debug("evaluate _DSM cmd: %0#4x arg: %0#10x\n", cmd, arg);
|
||||
} else {
|
||||
pr_err("unknown output from _DSM\n");
|
||||
status = -ENODATA;
|
||||
}
|
||||
else {
|
||||
if (!IS_ERR_OR_NULL(result)) {
|
||||
*result = out_obj;
|
||||
}
|
||||
}
|
||||
|
||||
ACPI_FREE(out_obj);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
u32 clevo_acpi_interface_method_call(u8 cmd, u32 arg, u32 *result_value)
|
||||
u32 clevo_acpi_interface_method_call(u8 cmd, u32 arg, union acpi_object **result_value)
|
||||
{
|
||||
u32 status = 0;
|
||||
|
||||
|
@ -146,9 +140,19 @@ static void clevo_acpi_remove(struct acpi_device *device)
|
|||
void clevo_acpi_notify(struct acpi_device *device, u32 event)
|
||||
{
|
||||
u32 event_value;
|
||||
union acpi_object *out_obj;
|
||||
u32 status;
|
||||
// struct clevo_acpi_driver_data_t *clevo_acpi_driver_data;
|
||||
|
||||
clevo_acpi_evaluate(device, 0x01, 0, &event_value);
|
||||
status = clevo_acpi_evaluate(device, 0x01, 0, &out_obj);
|
||||
if (!status) {
|
||||
if (out_obj->type == ACPI_TYPE_INTEGER) {
|
||||
event_value = (u32)out_obj->integer.value;
|
||||
} else {
|
||||
pr_err("return type not integer, use clevo_evaluate_method2\n");
|
||||
}
|
||||
ACPI_FREE(out_obj);
|
||||
}
|
||||
pr_debug("clevo_acpi event: %0#6x, clevo event value: %0#6x\n", event, event_value);
|
||||
|
||||
// clevo_acpi_driver_data = container_of(&device, struct clevo_acpi_driver_data_t, adev);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#define CLEVO_INTERFACES_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/acpi.h>
|
||||
|
||||
#define CLEVO_WMI_EVENT_GUID "ABBC0F6B-8EA1-11D1-00A0-C90629100000"
|
||||
#define CLEVO_WMI_EMAIL_GUID "ABBC0F6C-8EA1-11D1-00A0-C90629100000"
|
||||
|
@ -37,6 +38,16 @@
|
|||
#define CLEVO_CMD_GET_FLIGHTMODE_SW 0x07
|
||||
#define CLEVO_CMD_GET_TOUCHPAD_SW 0x09
|
||||
|
||||
#define CLEVO_CMD_GET_EVENT 0x01
|
||||
|
||||
#define CLEVO_CMD_GET_SPECS 0x0D // Returns buffer -> only works with clevo_evaluate_method2
|
||||
#define CLEVO_CMD_GET_BIOS_FEATURES_1 0x52
|
||||
#define CLEVO_CMD_GET_BIOS_FEATURES_1_SUB_WHITE_ONLY_KB 0x40000000
|
||||
#define CLEVO_CMD_GET_BIOS_FEATURES_1_SUB_3_ZONE_RGB_KB 0x00400000
|
||||
|
||||
#define CLEVO_CMD_GET_BIOS_FEATURES_2 0x7A
|
||||
#define CLEVO_CMD_GET_BIOS_FEATURES_2_SUB_WHITE_ONLY_KB_MAX_5 0x4000
|
||||
|
||||
// The clevo set commands expect a parameter
|
||||
#define CLEVO_CMD_SET_FANSPEED_VALUE 0x68
|
||||
#define CLEVO_CMD_SET_FANSPEED_AUTO 0x69
|
||||
|
@ -45,18 +56,29 @@
|
|||
#define CLEVO_CMD_SET_FLIGHTMODE_SW 0x20
|
||||
#define CLEVO_CMD_SET_TOUCHPAD_SW 0x2a
|
||||
|
||||
#define CLEVO_CMD_SET_EVENTS_ENABLED 0x46
|
||||
|
||||
#define CLEVO_CMD_SET_KB_WHITE_LEDS 0x27 // Set brightness of single color keyboard backlights
|
||||
#define CLEVO_CMD_SET_KB_RGB_LEDS 0x67 // Used to set color, brightness, blinking pattern, etc.
|
||||
#define CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_0 0xF0000000 // 1-zone RGB and 3-zone RGB left
|
||||
#define CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_1 0xF1000000 // 3-zone RGB center
|
||||
#define CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_2 0xF2000000 // 3-Zone RGB right
|
||||
#define CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_3 0xF3000000 // Unused on all known Clevo devices
|
||||
#define CLEVO_CMD_SET_KB_LEDS_SUB_RGB_BRIGHTNESS 0xF4000000
|
||||
|
||||
#define CLEVO_CMD_OPT 0x79
|
||||
#define CLEVO_OPT_SUBCMD_SET_PERF_PROF 0x19
|
||||
#define CLEVO_CMD_OPT_SUB_SET_PERF_PROF 0x19
|
||||
|
||||
struct clevo_interface_t {
|
||||
char *string_id;
|
||||
void (*event_callb)(u32);
|
||||
u32 (*method_call)(u8, u32, u32*);
|
||||
u32 (*method_call)(u8, u32, union acpi_object **);
|
||||
};
|
||||
|
||||
u32 clevo_keyboard_add_interface(struct clevo_interface_t *new_interface);
|
||||
u32 clevo_keyboard_remove_interface(struct clevo_interface_t *interface);
|
||||
u32 clevo_evaluate_method(u8 cmd, u32 arg, u32 *result);
|
||||
u32 clevo_evaluate_method2(u8 cmd, u32 arg, union acpi_object **result);
|
||||
u32 clevo_get_active_interface_id(char **id_str);
|
||||
|
||||
#define MODULE_ALIAS_CLEVO_WMI() \
|
||||
|
|
1087
src/clevo_keyboard.h
1087
src/clevo_keyboard.h
File diff suppressed because it is too large
Load diff
424
src/clevo_leds.h
Normal file
424
src/clevo_leds.h
Normal file
|
@ -0,0 +1,424 @@
|
|||
/*!
|
||||
* Copyright (c) 2018-2020 TUXEDO Computers GmbH <tux@tuxedocomputers.com>
|
||||
*
|
||||
* This file is part of tuxedo-keyboard.
|
||||
*
|
||||
* tuxedo-keyboard is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CLEVO_LEDS_H
|
||||
#define CLEVO_LEDS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
enum clevo_kb_backlight_types {
|
||||
CLEVO_KB_BACKLIGHT_TYPE_NONE = 0x00,
|
||||
CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR = 0x01,
|
||||
CLEVO_KB_BACKLIGHT_TYPE_3_ZONE_RGB = 0x02,
|
||||
CLEVO_KB_BACKLIGHT_TYPE_1_ZONE_RGB = 0x06,
|
||||
CLEVO_KB_BACKLIGHT_TYPE_PER_KEY_RGB = 0xf3
|
||||
};
|
||||
|
||||
int clevo_leds_init(struct platform_device *dev);
|
||||
int clevo_leds_remove(struct platform_device *dev);
|
||||
enum clevo_kb_backlight_types clevo_leds_get_backlight_type(void);
|
||||
void clevo_leds_set_brightness_extern(enum led_brightness brightness);
|
||||
void clevo_leds_set_color_extern(u32 color);
|
||||
|
||||
// TODO The following should go into a seperate .c file, but for this to work more reworking is required in the tuxedo_keyboard structure.
|
||||
|
||||
#include "clevo_leds.h"
|
||||
|
||||
#include "clevo_interfaces.h"
|
||||
|
||||
#include <linux/led-class-multicolor.h>
|
||||
|
||||
#define CLEVO_KBD_BRIGHTNESS_MAX 0xff
|
||||
#define CLEVO_KBD_BRIGHTNESS_DEFAULT 0x00
|
||||
|
||||
#define CLEVO_KBD_BRIGHTNESS_WHITE_MAX 0x02 // White only keyboards can only be off, half, or full brightness
|
||||
#define CLEVO_KBD_BRIGHTNESS_WHITE_DEFAULT 0x00
|
||||
|
||||
#define CLEVO_KBD_BRIGHTNESS_WHITE_MAX_5 0x05 // Devices <= Intel 7th gen had a different white control with 5 brightness values + off
|
||||
#define CLEVO_KBD_BRIGHTNESS_WHITE_MAX_5_DEFAULT 0x00
|
||||
|
||||
#define CLEVO_KB_COLOR_DEFAULT_RED 0xff
|
||||
#define CLEVO_KB_COLOR_DEFAULT_GREEN 0xff
|
||||
#define CLEVO_KB_COLOR_DEFAULT_BLUE 0xff
|
||||
#define CLEVO_KB_COLOR_DEFAULT ((CLEVO_KB_COLOR_DEFAULT_RED << 16) + (CLEVO_KB_COLOR_DEFAULT_GREEN << 8) + CLEVO_KB_COLOR_DEFAULT_BLUE)
|
||||
|
||||
static enum clevo_kb_backlight_types clevo_kb_backlight_type = CLEVO_KB_BACKLIGHT_TYPE_NONE;
|
||||
static bool leds_initialized = false;
|
||||
|
||||
static int clevo_evaluate_set_white_brightness(u8 brightness)
|
||||
{
|
||||
pr_debug("Set white brightness on %d\n", brightness);
|
||||
|
||||
return clevo_evaluate_method (CLEVO_CMD_SET_KB_WHITE_LEDS, brightness, NULL);
|
||||
}
|
||||
|
||||
static int clevo_evaluate_set_rgb_brightness(u8 brightness)
|
||||
{
|
||||
pr_debug("Set RGB brightness on %d\n", brightness);
|
||||
|
||||
return clevo_evaluate_method (CLEVO_CMD_SET_KB_RGB_LEDS, CLEVO_CMD_SET_KB_LEDS_SUB_RGB_BRIGHTNESS | brightness, NULL);
|
||||
}
|
||||
|
||||
static int clevo_evaluate_set_rgb_color(u32 zone, u32 color)
|
||||
{
|
||||
u32 cset = ((color & 0x0000FF) << 16) | ((color & 0xFF0000) >> 8) | ((color & 0x00FF00) >> 8);
|
||||
u32 clevo_submethod_arg = zone | cset;
|
||||
|
||||
pr_debug("Set Color 0x%08x for region 0x%08x\n", color, zone);
|
||||
|
||||
return clevo_evaluate_method(CLEVO_CMD_SET_KB_RGB_LEDS, clevo_submethod_arg, NULL);
|
||||
}
|
||||
|
||||
static void clevo_leds_set_brightness(struct led_classdev *led_cdev __always_unused, enum led_brightness brightness) {
|
||||
int ret = clevo_evaluate_set_white_brightness(brightness);
|
||||
if (ret) {
|
||||
pr_debug("clevo_leds_set_brightness(): clevo_evaluate_set_white_brightness() failed\n");
|
||||
return;
|
||||
}
|
||||
led_cdev->brightness = brightness;
|
||||
}
|
||||
|
||||
/*static void clevo_leds_set_brightness_mc(struct led_classdev *led_cdev, enum led_brightness brightness) {
|
||||
int ret;
|
||||
u32 zone, color;
|
||||
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
|
||||
|
||||
ret = clevo_evaluate_set_rgb_brightness(CLEVO_KBD_BRIGHTNESS_MAX);
|
||||
if (ret) {
|
||||
pr_debug("clevo_leds_set_brightness_mc(): clevo_evaluate_set_rgb_brightness() failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
zone = mcled_cdev->subled_info[0].channel;
|
||||
|
||||
led_mc_calc_color_components(mcled_cdev, brightness);
|
||||
color = (mcled_cdev->subled_info[0].brightness << 16) +
|
||||
(mcled_cdev->subled_info[1].brightness << 8) +
|
||||
mcled_cdev->subled_info[2].brightness;
|
||||
|
||||
ret = clevo_evaluate_set_rgb_color(zone, color);
|
||||
if (ret) {
|
||||
pr_debug("clevo_leds_set_brightness_mc(): clevo_evaluate_set_rgb_color() failed\n");
|
||||
return;
|
||||
}
|
||||
led_cdev->brightness = brightness;
|
||||
}*/
|
||||
|
||||
// Temprary fix for KDE: KDE does only set one kbd_backlight brightness value, this version of the
|
||||
// function uses clevos built in brightness setting to set the whole keyboard brightness at once.
|
||||
// -> use clevo_evaluate_set_rgb_brightness() to set overall brightness via firmware instead of scaling
|
||||
// the RGB values
|
||||
// -> update all clevo_mcled_cdevs brightness levels to refect that the firmware method sets the
|
||||
// the whole keyboard brightness and not just one zone
|
||||
// This is a temporary fix until KDE handles multiple keyboard backlights correctly
|
||||
static struct led_classdev_mc clevo_mcled_cdevs[3]; // forward declaration
|
||||
static void clevo_leds_set_brightness_mc(struct led_classdev *led_cdev, enum led_brightness brightness) {
|
||||
int ret;
|
||||
u32 zone, color;
|
||||
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
|
||||
|
||||
ret = clevo_evaluate_set_rgb_brightness(brightness);
|
||||
if (ret) {
|
||||
pr_debug("clevo_leds_set_brightness_mc(): clevo_evaluate_set_rgb_brightness() failed\n");
|
||||
return;
|
||||
}
|
||||
clevo_mcled_cdevs[0].led_cdev.brightness = brightness;
|
||||
clevo_mcled_cdevs[1].led_cdev.brightness = brightness;
|
||||
clevo_mcled_cdevs[2].led_cdev.brightness = brightness;
|
||||
|
||||
zone = mcled_cdev->subled_info[0].channel;
|
||||
|
||||
color = (mcled_cdev->subled_info[0].intensity << 16) +
|
||||
(mcled_cdev->subled_info[1].intensity << 8) +
|
||||
mcled_cdev->subled_info[2].intensity;
|
||||
|
||||
ret = clevo_evaluate_set_rgb_color(zone, color);
|
||||
if (ret) {
|
||||
pr_debug("clevo_leds_set_brightness_mc(): clevo_evaluate_set_rgb_color() failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
static struct led_classdev clevo_led_cdev = {
|
||||
.name = "white:" LED_FUNCTION_KBD_BACKLIGHT,
|
||||
.max_brightness = CLEVO_KBD_BRIGHTNESS_WHITE_MAX,
|
||||
.brightness_set = &clevo_leds_set_brightness,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_WHITE_DEFAULT
|
||||
};
|
||||
|
||||
static struct mc_subled clevo_mcled_cdevs_subleds[3][3] = {
|
||||
{
|
||||
{
|
||||
.color_index = LED_COLOR_ID_RED,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_RED,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_0
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_GREEN,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_GREEN,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_0
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_BLUE,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_BLUE,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_0
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
.color_index = LED_COLOR_ID_RED,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_RED,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_1
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_GREEN,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_GREEN,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_1
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_BLUE,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_BLUE,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_1
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
.color_index = LED_COLOR_ID_RED,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_RED,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_2
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_GREEN,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_GREEN,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_2
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_BLUE,
|
||||
.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.intensity = CLEVO_KB_COLOR_DEFAULT_BLUE,
|
||||
.channel = CLEVO_CMD_SET_KB_LEDS_SUB_RGB_ZONE_2
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static struct led_classdev_mc clevo_mcled_cdevs[3] = {
|
||||
{
|
||||
.led_cdev.name = "rgb:" LED_FUNCTION_KBD_BACKLIGHT,
|
||||
.led_cdev.max_brightness = CLEVO_KBD_BRIGHTNESS_MAX,
|
||||
.led_cdev.brightness_set = &clevo_leds_set_brightness_mc,
|
||||
.led_cdev.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.num_colors = 3,
|
||||
.subled_info = clevo_mcled_cdevs_subleds[0]
|
||||
},
|
||||
{
|
||||
.led_cdev.name = "rgb:" LED_FUNCTION_KBD_BACKLIGHT,
|
||||
.led_cdev.max_brightness = CLEVO_KBD_BRIGHTNESS_MAX,
|
||||
.led_cdev.brightness_set = &clevo_leds_set_brightness_mc,
|
||||
.led_cdev.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.num_colors = 3,
|
||||
.subled_info = clevo_mcled_cdevs_subleds[1]
|
||||
},
|
||||
{
|
||||
.led_cdev.name = "rgb:" LED_FUNCTION_KBD_BACKLIGHT,
|
||||
.led_cdev.max_brightness = CLEVO_KBD_BRIGHTNESS_MAX,
|
||||
.led_cdev.brightness_set = &clevo_leds_set_brightness_mc,
|
||||
.led_cdev.brightness = CLEVO_KBD_BRIGHTNESS_DEFAULT,
|
||||
.num_colors = 3,
|
||||
.subled_info = clevo_mcled_cdevs_subleds[2]
|
||||
}
|
||||
};
|
||||
|
||||
int clevo_leds_init(struct platform_device *dev)
|
||||
{
|
||||
int ret;
|
||||
u32 status;
|
||||
union acpi_object *result;
|
||||
u32 result_fallback;
|
||||
|
||||
status = clevo_evaluate_method2(CLEVO_CMD_GET_SPECS, 0, &result);
|
||||
if (!status) {
|
||||
if (result->type == ACPI_TYPE_BUFFER) {
|
||||
pr_debug("CLEVO_CMD_GET_SPECS result->buffer.pointer[0x0f]: 0x%02x\n", result->buffer.pointer[0x0f]);
|
||||
clevo_kb_backlight_type = result->buffer.pointer[0x0f];
|
||||
}
|
||||
else {
|
||||
pr_err("CLEVO_CMD_GET_SPECS does not exist on this device or return value has wrong type, trying CLEVO_CMD_GET_BIOS_FEATURES\n");
|
||||
status = -EINVAL;
|
||||
}
|
||||
ACPI_FREE(result);
|
||||
}
|
||||
else {
|
||||
pr_notice("CLEVO_CMD_GET_SPECS does not exist on this device or failed, trying CLEVO_CMD_GET_BIOS_FEATURES_1\n");
|
||||
}
|
||||
|
||||
if (status || clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_NONE) {
|
||||
// check for devices <= Intel 8th gen (only white only, 3 zone RGB, or no backlight on these devices)
|
||||
status = clevo_evaluate_method(CLEVO_CMD_GET_BIOS_FEATURES_1, 0, &result_fallback);
|
||||
if (!status) {
|
||||
pr_debug("CLEVO_CMD_GET_BIOS_FEATURES_1 result_fallback: 0x%08x\n", result_fallback);
|
||||
if (result_fallback & CLEVO_CMD_GET_BIOS_FEATURES_1_SUB_3_ZONE_RGB_KB) {
|
||||
clevo_kb_backlight_type = CLEVO_KB_BACKLIGHT_TYPE_3_ZONE_RGB;
|
||||
}
|
||||
else if (result_fallback & CLEVO_CMD_GET_BIOS_FEATURES_1_SUB_WHITE_ONLY_KB) {
|
||||
clevo_kb_backlight_type = CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR;
|
||||
|
||||
status = clevo_evaluate_method(CLEVO_CMD_GET_BIOS_FEATURES_2, 0, &result_fallback);
|
||||
if (!status) {
|
||||
pr_debug("CLEVO_CMD_GET_BIOS_FEATURES_2 result_fallback: 0x%08x\n", result_fallback);
|
||||
if (result_fallback & CLEVO_CMD_GET_BIOS_FEATURES_2_SUB_WHITE_ONLY_KB_MAX_5) {
|
||||
clevo_led_cdev.max_brightness = CLEVO_KBD_BRIGHTNESS_WHITE_MAX_5;
|
||||
clevo_led_cdev.brightness = CLEVO_KBD_BRIGHTNESS_WHITE_MAX_5_DEFAULT;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pr_notice("CLEVO_CMD_GET_BIOS_FEATURES_2 does not exist on this device or failed\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
pr_notice("CLEVO_CMD_GET_BIOS_FEATURES_1 does not exist on this device or failed\n");
|
||||
}
|
||||
}
|
||||
pr_debug("Keyboard backlight type: 0x%02x\n", clevo_kb_backlight_type);
|
||||
|
||||
if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR)
|
||||
clevo_leds_set_brightness_extern(clevo_led_cdev.brightness);
|
||||
else
|
||||
clevo_leds_set_color_extern(CLEVO_KB_COLOR_DEFAULT);
|
||||
|
||||
if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
|
||||
pr_debug("Registering fixed color leds interface\n");
|
||||
ret = led_classdev_register(&dev->dev, &clevo_led_cdev);
|
||||
if (ret) {
|
||||
pr_err("Registering fixed color leds interface failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
pr_debug("Registering single zone rgb leds interface\n");
|
||||
ret = devm_led_classdev_multicolor_register(&dev->dev, &clevo_mcled_cdevs[0]);
|
||||
if (ret) {
|
||||
pr_err("Registering single zone rgb leds interface failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_3_ZONE_RGB) {
|
||||
pr_debug("Registering three zone rgb leds interface\n");
|
||||
ret = devm_led_classdev_multicolor_register(&dev->dev, &clevo_mcled_cdevs[0]);
|
||||
if (ret) {
|
||||
pr_err("Registering three zone rgb zone 0 leds interface failed\n");
|
||||
return ret;
|
||||
}
|
||||
ret = devm_led_classdev_multicolor_register(&dev->dev, &clevo_mcled_cdevs[1]);
|
||||
if (ret) {
|
||||
pr_err("Registering three zone rgb zone 1 leds interface failed\n");
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &clevo_mcled_cdevs[0]);
|
||||
return ret;
|
||||
}
|
||||
ret = devm_led_classdev_multicolor_register(&dev->dev, &clevo_mcled_cdevs[2]);
|
||||
if (ret) {
|
||||
pr_err("Registering three zone rgb zone 2 leds interface failed\n");
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &clevo_mcled_cdevs[0]);
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &clevo_mcled_cdevs[1]);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
leds_initialized = true;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clevo_leds_init);
|
||||
|
||||
int clevo_leds_remove(struct platform_device *dev) {
|
||||
if (leds_initialized) {
|
||||
if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
|
||||
led_classdev_unregister(&clevo_led_cdev);
|
||||
}
|
||||
else if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &clevo_mcled_cdevs[0]);
|
||||
}
|
||||
else if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_3_ZONE_RGB) {
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &clevo_mcled_cdevs[0]);
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &clevo_mcled_cdevs[1]);
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &clevo_mcled_cdevs[2]);
|
||||
}
|
||||
}
|
||||
|
||||
leds_initialized = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clevo_leds_remove);
|
||||
|
||||
enum clevo_kb_backlight_types clevo_leds_get_backlight_type() {
|
||||
return clevo_kb_backlight_type;
|
||||
}
|
||||
EXPORT_SYMBOL(clevo_leds_get_backlight_type);
|
||||
|
||||
void clevo_leds_set_brightness_extern(enum led_brightness brightness) {
|
||||
if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
|
||||
clevo_led_cdev.brightness_set(&clevo_led_cdev, brightness);
|
||||
}
|
||||
else if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
clevo_mcled_cdevs[0].led_cdev.brightness_set(&clevo_mcled_cdevs[0].led_cdev, brightness);
|
||||
}
|
||||
else if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_3_ZONE_RGB) {
|
||||
clevo_mcled_cdevs[0].led_cdev.brightness_set(&clevo_mcled_cdevs[0].led_cdev, brightness);
|
||||
clevo_mcled_cdevs[1].led_cdev.brightness_set(&clevo_mcled_cdevs[1].led_cdev, brightness);
|
||||
clevo_mcled_cdevs[2].led_cdev.brightness_set(&clevo_mcled_cdevs[2].led_cdev, brightness);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(clevo_leds_set_brightness_extern);
|
||||
|
||||
void clevo_leds_set_color_extern(u32 color) {
|
||||
if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
clevo_mcled_cdevs[0].subled_info[0].intensity = (color >> 16) & 0xff;
|
||||
clevo_mcled_cdevs[0].subled_info[1].intensity = (color >> 8) & 0xff;
|
||||
clevo_mcled_cdevs[0].subled_info[2].intensity = color & 0xff;
|
||||
clevo_mcled_cdevs[0].led_cdev.brightness_set(&clevo_mcled_cdevs[0].led_cdev, clevo_mcled_cdevs[0].led_cdev.brightness);
|
||||
}
|
||||
else if (clevo_kb_backlight_type == CLEVO_KB_BACKLIGHT_TYPE_3_ZONE_RGB) {
|
||||
clevo_mcled_cdevs[0].subled_info[0].intensity = (color >> 16) & 0xff;
|
||||
clevo_mcled_cdevs[0].subled_info[1].intensity = (color >> 8) & 0xff;
|
||||
clevo_mcled_cdevs[0].subled_info[2].intensity = color & 0xff;
|
||||
clevo_mcled_cdevs[0].led_cdev.brightness_set(&clevo_mcled_cdevs[0].led_cdev, clevo_mcled_cdevs[0].led_cdev.brightness);
|
||||
clevo_mcled_cdevs[1].subled_info[0].intensity = (color >> 16) & 0xff;
|
||||
clevo_mcled_cdevs[1].subled_info[1].intensity = (color >> 8) & 0xff;
|
||||
clevo_mcled_cdevs[1].subled_info[2].intensity = color & 0xff;
|
||||
clevo_mcled_cdevs[1].led_cdev.brightness_set(&clevo_mcled_cdevs[1].led_cdev, clevo_mcled_cdevs[1].led_cdev.brightness);
|
||||
clevo_mcled_cdevs[2].subled_info[0].intensity = (color >> 16) & 0xff;
|
||||
clevo_mcled_cdevs[2].subled_info[1].intensity = (color >> 8) & 0xff;
|
||||
clevo_mcled_cdevs[2].subled_info[2].intensity = color & 0xff;
|
||||
clevo_mcled_cdevs[2].led_cdev.brightness_set(&clevo_mcled_cdevs[2].led_cdev, clevo_mcled_cdevs[2].led_cdev.brightness);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(clevo_leds_set_color_extern);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#endif // CLEVO_LEDS_H
|
|
@ -23,7 +23,7 @@
|
|||
#include <linux/version.h>
|
||||
#include "clevo_interfaces.h"
|
||||
|
||||
static int clevo_wmi_evaluate(u32 wmi_method_id, u32 wmi_arg, u32 *result)
|
||||
static int clevo_wmi_evaluate(u32 wmi_method_id, u32 wmi_arg, union acpi_object **result)
|
||||
{
|
||||
struct acpi_buffer acpi_buffer_in = { (acpi_size)sizeof(wmi_arg),
|
||||
&wmi_arg };
|
||||
|
@ -45,26 +45,17 @@ static int clevo_wmi_evaluate(u32 wmi_method_id, u32 wmi_arg, u32 *result)
|
|||
if (!acpi_result) {
|
||||
pr_err("failed to evaluate WMI method\n");
|
||||
return_status = -1;
|
||||
} else {
|
||||
if (acpi_result->type == ACPI_TYPE_INTEGER) {
|
||||
if (!IS_ERR_OR_NULL(result)) {
|
||||
*result = (u32)acpi_result->integer.value;
|
||||
/*pr_debug(
|
||||
"evaluate wmi cmd: %0#4x arg: %0#10x\n",
|
||||
wmi_method_id, wmi_arg);*/
|
||||
}
|
||||
} else {
|
||||
pr_err("unknown output from wmi method\n");
|
||||
return_status = -EIO;
|
||||
}
|
||||
else {
|
||||
if (!IS_ERR_OR_NULL(result)) {
|
||||
*result = acpi_result;
|
||||
}
|
||||
}
|
||||
|
||||
kfree(acpi_result);
|
||||
|
||||
return return_status;
|
||||
}
|
||||
|
||||
u32 clevo_wmi_interface_method_call(u8 cmd, u32 arg, u32 *result_value)
|
||||
u32 clevo_wmi_interface_method_call(u8 cmd, u32 arg, union acpi_object **result_value)
|
||||
{
|
||||
return clevo_wmi_evaluate(cmd, arg, result_value);
|
||||
}
|
||||
|
@ -80,7 +71,8 @@ static int clevo_wmi_probe(struct wmi_device *wdev)
|
|||
static int clevo_wmi_probe(struct wmi_device *wdev, const void *dummy_context)
|
||||
#endif
|
||||
{
|
||||
u32 status, ret;
|
||||
u32 status;
|
||||
union acpi_object *out_obj;
|
||||
|
||||
pr_debug("clevo_wmi driver probe\n");
|
||||
|
||||
|
@ -96,16 +88,18 @@ static int clevo_wmi_probe(struct wmi_device *wdev, const void *dummy_context)
|
|||
|
||||
// Since the WMI GUIDs aren't unique let's (at least)
|
||||
// check the return of some "known existing general" method
|
||||
status = clevo_wmi_evaluate(0x52, 0, &ret);
|
||||
status = clevo_wmi_evaluate(0x52, 0, &out_obj);
|
||||
if (status < 0) {
|
||||
pr_debug("probe: Clevo GUIDs present but method call failed\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
if (ret == 0xffffffff) {
|
||||
if (out_obj->type != ACPI_TYPE_INTEGER || (out_obj->type == ACPI_TYPE_INTEGER && (u32)out_obj->integer.value == 0xffffffff)) {
|
||||
pr_debug(
|
||||
"probe: Clevo GUIDs present but method returned unexpected value\n");
|
||||
ACPI_FREE(out_obj);
|
||||
return -ENODEV;
|
||||
}
|
||||
ACPI_FREE(out_obj);
|
||||
|
||||
// Add this interface
|
||||
clevo_keyboard_add_interface(&clevo_wmi_interface);
|
||||
|
@ -131,7 +125,18 @@ static void clevo_wmi_remove(struct wmi_device *wdev)
|
|||
static void clevo_wmi_notify(struct wmi_device *wdev, union acpi_object *dummy)
|
||||
{
|
||||
u32 event_value;
|
||||
clevo_wmi_evaluate(0x01, 0, &event_value);
|
||||
union acpi_object *out_obj;
|
||||
u32 status;
|
||||
|
||||
status = clevo_wmi_evaluate(0x01, 0, &out_obj);
|
||||
if (!status) {
|
||||
if (out_obj->type == ACPI_TYPE_INTEGER) {
|
||||
event_value = (u32)out_obj->integer.value;
|
||||
} else {
|
||||
pr_err("return type not integer, use clevo_evaluate_method2\n");
|
||||
}
|
||||
ACPI_FREE(out_obj);
|
||||
}
|
||||
pr_debug("clevo_wmi notify\n");
|
||||
if (!IS_ERR_OR_NULL(clevo_wmi_interface.event_callb)) {
|
||||
// Execute registered callback
|
||||
|
|
|
@ -254,7 +254,7 @@ static long clevo_ioctl_interface(struct file *file, unsigned int cmd, unsigned
|
|||
break;
|
||||
case W_CL_PERF_PROFILE:
|
||||
copy_result = copy_from_user(&argument, (int32_t *) arg, sizeof(argument));
|
||||
clevo_arg = (CLEVO_OPT_SUBCMD_SET_PERF_PROF << 0x18) | (argument & 0xff);
|
||||
clevo_arg = (CLEVO_CMD_OPT_SUB_SET_PERF_PROF << 0x18) | (argument & 0xff);
|
||||
clevo_evaluate_method(CLEVO_CMD_OPT, clevo_arg, &result);
|
||||
break;
|
||||
}
|
||||
|
@ -811,6 +811,8 @@ static int __init tuxedo_io_init(void)
|
|||
id_check_uniwill = uniwill_identify();
|
||||
|
||||
#ifdef DEBUG
|
||||
pr_debug("DEBUG is defined\n");
|
||||
|
||||
if (id_check_clevo == 0 && id_check_uniwill == 0) {
|
||||
pr_debug("No matching hardware found on module load\n");
|
||||
}
|
||||
|
|
|
@ -102,41 +102,4 @@ static struct color_list_t color_list = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Looks up a color in the color_list
|
||||
*
|
||||
* Returns found color value, or 0xffffffff if string did not match
|
||||
*/
|
||||
static u32 color_lookup(const struct color_list_t *color_list, const char *color_name)
|
||||
{
|
||||
u32 found_color = 0xffffffff;
|
||||
int i;
|
||||
for (i = 0; i < color_list->size; ++i) {
|
||||
if (strcmp(color_list->colors[i].name, color_name) == 0) {
|
||||
found_color = color_list->colors[i].code;
|
||||
}
|
||||
}
|
||||
|
||||
return found_color;
|
||||
}
|
||||
|
||||
// Common parameters
|
||||
|
||||
static int brightness_validator(const char *val,
|
||||
const struct kernel_param *brightness_param);
|
||||
static const struct kernel_param_ops param_ops_brightness_ops = {
|
||||
.set = brightness_validator,
|
||||
.get = param_get_int,
|
||||
};
|
||||
|
||||
static ushort param_brightness = 0xffff; // Default unset value (higher than max)
|
||||
module_param_cb(brightness, ¶m_ops_brightness_ops, ¶m_brightness,
|
||||
S_IRUSR);
|
||||
MODULE_PARM_DESC(brightness, "Set the Keyboard Brightness");
|
||||
|
||||
#define COLOR_STRING_LEN 20
|
||||
static char param_color[COLOR_STRING_LEN];
|
||||
module_param_string(color, param_color, COLOR_STRING_LEN, S_IRUSR);
|
||||
MODULE_PARM_DESC(color, "Preset color for the keyboard backlight as string");
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -35,11 +35,40 @@
|
|||
|
||||
#define UNIWILL_INTERFACE_WMI_STRID "uniwill_wmi"
|
||||
|
||||
typedef u32 (uniwill_read_ec_ram_t)(u16, u8*);
|
||||
typedef u32 (uniwill_write_ec_ram_t)(u16, u8);
|
||||
typedef u32 (uniwill_write_ec_ram_with_retry_t)(u16, u8, int);
|
||||
typedef int (uniwill_read_ec_ram_t)(u16, u8*);
|
||||
typedef int (uniwill_write_ec_ram_t)(u16, u8);
|
||||
typedef int (uniwill_write_ec_ram_with_retry_t)(u16, u8, int);
|
||||
typedef void (uniwill_event_callb_t)(u32);
|
||||
|
||||
// UW_EC_REG_* known relevant EC address exposing some information or function
|
||||
// UW_EC_REG_*_BIT_* single bit from byte holding information, should be handled with bit-wise operations
|
||||
// UW_EC_REG_*_VALUE_* discrete value of the whole byte with special meaning
|
||||
// UW_EC_REG_*_SUBCMD_* writing this discrete value triggers special behaviour
|
||||
|
||||
#define UW_EC_REG_KBD_BL_STATUS 0x078c
|
||||
#define UW_EC_REG_KBD_BL_STATUS_BIT_WHITE_ONLY_KB 0x01
|
||||
#define UW_EC_REG_KBD_BL_STATUS_SUBCMD_RESET 0x10
|
||||
|
||||
#define UW_EC_REG_KBD_BL_MAX_BRIGHTNESS 0x1801
|
||||
#define UW_EC_REG_KBD_BL_WHITE_BRIGHTNESS 0x1802
|
||||
#define UW_EC_REG_KBD_BL_RGB_RED_BRIGHTNESS 0x1803
|
||||
#define UW_EC_REG_KBD_BL_RGB_GREEN_BRIGHTNESS 0x1805
|
||||
#define UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS 0x1808
|
||||
|
||||
#define UW_EC_REG_BAREBONE_ID 0x0740
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PFxxxxx 0x09
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PFxMxxx 0x0e
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PH4TRX1 0x12
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PH4TUX1 0x13
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PH4TQx1 0x14
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PH6TRX1 0x15
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PH6TQxx 0x16
|
||||
#define UW_EC_REG_BAREBONE_ID_VALUE_PH4Axxx 0x17
|
||||
|
||||
#define UW_EC_REG_FEATURES_0 0x0765
|
||||
#define UW_EC_REG_FEATURES_1 0x0766
|
||||
#define UW_EC_REG_FEATURES_1_BIT_1_ZONE_RGB_KB 0x04
|
||||
|
||||
struct uniwill_interface_t {
|
||||
char *string_id;
|
||||
uniwill_event_callb_t *event_callb;
|
||||
|
@ -47,6 +76,13 @@ struct uniwill_interface_t {
|
|||
uniwill_write_ec_ram_t *write_ec_ram;
|
||||
};
|
||||
|
||||
int uniwill_add_interface(struct uniwill_interface_t *new_interface);
|
||||
int uniwill_remove_interface(struct uniwill_interface_t *interface);
|
||||
uniwill_read_ec_ram_t uniwill_read_ec_ram;
|
||||
uniwill_write_ec_ram_t uniwill_write_ec_ram;
|
||||
uniwill_write_ec_ram_with_retry_t uniwill_write_ec_ram_with_retry;
|
||||
int uniwill_get_active_interface_id(char **id_str);
|
||||
|
||||
#define UW_MODEL_PF5LUXG 0x09
|
||||
#define UW_MODEL_PH4TUX 0x13
|
||||
#define UW_MODEL_PH4TRX 0x12
|
||||
|
@ -72,12 +108,6 @@ struct uniwill_device_features_t {
|
|||
bool uniwill_has_charging_profile;
|
||||
};
|
||||
|
||||
u32 uniwill_add_interface(struct uniwill_interface_t *new_interface);
|
||||
u32 uniwill_remove_interface(struct uniwill_interface_t *interface);
|
||||
uniwill_read_ec_ram_t uniwill_read_ec_ram;
|
||||
uniwill_write_ec_ram_t uniwill_write_ec_ram;
|
||||
uniwill_write_ec_ram_with_retry_t uniwill_write_ec_ram_with_retry;
|
||||
u32 uniwill_get_active_interface_id(char **id_str);
|
||||
struct uniwill_device_features_t *uniwill_get_device_features(void);
|
||||
|
||||
union uw_ec_read_return {
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef UNIWILL_KEYBOARD_H
|
||||
#define UNIWILL_KEYBOARD_H
|
||||
|
||||
#include "tuxedo_keyboard_common.h"
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/wmi.h>
|
||||
|
@ -24,17 +27,11 @@
|
|||
#include <linux/timer.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/led-class-multicolor.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/version.h>
|
||||
#include "uniwill_interfaces.h"
|
||||
|
||||
#define UNIWILL_WMI_MGMT_GUID_BA "ABBC0F6D-8EA1-11D1-00A0-C90629100000"
|
||||
#define UNIWILL_WMI_MGMT_GUID_BB "ABBC0F6E-8EA1-11D1-00A0-C90629100000"
|
||||
#define UNIWILL_WMI_MGMT_GUID_BC "ABBC0F6F-8EA1-11D1-00A0-C90629100000"
|
||||
|
||||
#define UNIWILL_WMI_EVENT_GUID_0 "ABBC0F70-8EA1-11D1-00A0-C90629100000"
|
||||
#define UNIWILL_WMI_EVENT_GUID_1 "ABBC0F71-8EA1-11D1-00A0-C90629100000"
|
||||
#define UNIWILL_WMI_EVENT_GUID_2 "ABBC0F72-8EA1-11D1-00A0-C90629100000"
|
||||
#include "uniwill_leds.h"
|
||||
|
||||
#define UNIWILL_OSD_RADIOON 0x01A
|
||||
#define UNIWILL_OSD_RADIOOFF 0x01B
|
||||
|
@ -44,6 +41,7 @@
|
|||
#define UNIWILL_OSD_KB_LED_LEVEL3 0x03E
|
||||
#define UNIWILL_OSD_KB_LED_LEVEL4 0x03F
|
||||
#define UNIWILL_OSD_DC_ADAPTER_CHANGE 0x0AB
|
||||
#define UNIWILL_OSD_MODE_CHANGE_KEY_EVENT 0x0B0
|
||||
|
||||
#define UNIWILL_KEY_RFKILL 0x0A4
|
||||
#define UNIWILL_KEY_KBDILLUMDOWN 0x0B1
|
||||
|
@ -52,30 +50,16 @@
|
|||
|
||||
#define UNIWILL_OSD_TOUCHPADWORKAROUND 0xFFF
|
||||
|
||||
#define UNIWILL_BRIGHTNESS_MIN 0x00
|
||||
#define UNIWILL_BRIGHTNESS_MAX 0xc8
|
||||
#define UNIWILL_BRIGHTNESS_DEFAULT UNIWILL_BRIGHTNESS_MAX * 0.30
|
||||
#define UNIWILL_COLOR_DEFAULT 0xffffff
|
||||
|
||||
static void uw_charging_priority_write_state(void);
|
||||
static void uw_charging_profile_write_state(void);
|
||||
|
||||
struct tuxedo_keyboard_driver uniwill_keyboard_driver;
|
||||
|
||||
struct kbd_led_state_uw_t {
|
||||
u32 brightness;
|
||||
u32 color;
|
||||
} kbd_led_state_uw = {
|
||||
.brightness = UNIWILL_BRIGHTNESS_DEFAULT,
|
||||
.color = UNIWILL_COLOR_DEFAULT,
|
||||
};
|
||||
|
||||
struct uniwill_device_features_t uniwill_device_features;
|
||||
|
||||
static bool uw_feats_loaded = false;
|
||||
|
||||
static u8 uniwill_kbd_bl_enable_state_on_start;
|
||||
static bool uniwill_kbd_bl_type_rgb_single_color = true;
|
||||
|
||||
static struct key_entry uniwill_wmi_keymap[] = {
|
||||
// { KE_KEY, UNIWILL_OSD_RADIOON, { KEY_RFKILL } },
|
||||
|
@ -88,6 +72,11 @@ static struct key_entry uniwill_wmi_keymap[] = {
|
|||
{ KE_KEY, UNIWILL_KEY_KBDILLUMDOWN, { KEY_KBDILLUMDOWN } },
|
||||
{ KE_KEY, UNIWILL_KEY_KBDILLUMUP, { KEY_KBDILLUMUP } },
|
||||
{ KE_KEY, UNIWILL_KEY_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE } },
|
||||
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE } },
|
||||
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE } },
|
||||
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE } },
|
||||
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE } },
|
||||
{ KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE } },
|
||||
// Only used to put ev bits
|
||||
{ KE_KEY, 0xffff, { KEY_F6 } },
|
||||
{ KE_KEY, 0xffff, { KEY_LEFTALT } },
|
||||
|
@ -101,9 +90,9 @@ static struct uniwill_interfaces_t {
|
|||
|
||||
uniwill_event_callb_t uniwill_event_callb;
|
||||
|
||||
u32 uniwill_read_ec_ram(u16 address, u8 *data)
|
||||
int uniwill_read_ec_ram(u16 address, u8 *data)
|
||||
{
|
||||
u32 status;
|
||||
int status;
|
||||
|
||||
if (!IS_ERR_OR_NULL(uniwill_interfaces.wmi))
|
||||
status = uniwill_interfaces.wmi->read_ec_ram(address, data);
|
||||
|
@ -116,9 +105,9 @@ u32 uniwill_read_ec_ram(u16 address, u8 *data)
|
|||
}
|
||||
EXPORT_SYMBOL(uniwill_read_ec_ram);
|
||||
|
||||
u32 uniwill_write_ec_ram(u16 address, u8 data)
|
||||
int uniwill_write_ec_ram(u16 address, u8 data)
|
||||
{
|
||||
u32 status;
|
||||
int status;
|
||||
|
||||
if (!IS_ERR_OR_NULL(uniwill_interfaces.wmi))
|
||||
status = uniwill_interfaces.wmi->write_ec_ram(address, data);
|
||||
|
@ -131,7 +120,7 @@ u32 uniwill_write_ec_ram(u16 address, u8 data)
|
|||
}
|
||||
EXPORT_SYMBOL(uniwill_write_ec_ram);
|
||||
|
||||
u32 uniwill_write_ec_ram_with_retry(u16 address, u8 data, int retries)
|
||||
int uniwill_write_ec_ram_with_retry(u16 address, u8 data, int retries)
|
||||
{
|
||||
u32 status;
|
||||
int i;
|
||||
|
@ -159,7 +148,7 @@ EXPORT_SYMBOL(uniwill_write_ec_ram_with_retry);
|
|||
|
||||
static DEFINE_MUTEX(uniwill_interface_modification_lock);
|
||||
|
||||
u32 uniwill_add_interface(struct uniwill_interface_t *interface)
|
||||
int uniwill_add_interface(struct uniwill_interface_t *interface)
|
||||
{
|
||||
mutex_lock(&uniwill_interface_modification_lock);
|
||||
|
||||
|
@ -181,7 +170,7 @@ u32 uniwill_add_interface(struct uniwill_interface_t *interface)
|
|||
}
|
||||
EXPORT_SYMBOL(uniwill_add_interface);
|
||||
|
||||
u32 uniwill_remove_interface(struct uniwill_interface_t *interface)
|
||||
int uniwill_remove_interface(struct uniwill_interface_t *interface)
|
||||
{
|
||||
mutex_lock(&uniwill_interface_modification_lock);
|
||||
|
||||
|
@ -201,7 +190,7 @@ u32 uniwill_remove_interface(struct uniwill_interface_t *interface)
|
|||
}
|
||||
EXPORT_SYMBOL(uniwill_remove_interface);
|
||||
|
||||
u32 uniwill_get_active_interface_id(char **id_str)
|
||||
int uniwill_get_active_interface_id(char **id_str)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(uniwill_interfaces.wmi))
|
||||
return -ENODEV;
|
||||
|
@ -258,89 +247,15 @@ static struct notifier_block keyboard_notifier_block = {
|
|||
.notifier_call = keyboard_notifier_callb
|
||||
};
|
||||
|
||||
static u8 uniwill_read_kbd_bl_enabled(void)
|
||||
{
|
||||
u8 backlight_data;
|
||||
u8 enabled = 0xff;
|
||||
|
||||
uniwill_read_ec_ram(0x078c, &backlight_data);
|
||||
enabled = (backlight_data >> 1) & 0x01;
|
||||
enabled = !enabled;
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
static void uniwill_write_kbd_bl_enable(u8 enable)
|
||||
{
|
||||
u8 backlight_data;
|
||||
enable = enable & 0x01;
|
||||
|
||||
uniwill_read_ec_ram(0x078c, &backlight_data);
|
||||
uniwill_read_ec_ram(UW_EC_REG_KBD_BL_STATUS, &backlight_data);
|
||||
backlight_data = backlight_data & ~(1 << 1);
|
||||
backlight_data |= (!enable << 1);
|
||||
uniwill_write_ec_ram(0x078c, backlight_data);
|
||||
}
|
||||
|
||||
/*static u32 uniwill_read_kbd_bl_br_state(u8 *brightness_state)
|
||||
{
|
||||
u8 backlight_data;
|
||||
u32 result;
|
||||
|
||||
uniwill_read_ec_ram(0x078c, &backlight_data);
|
||||
*brightness_state = (backlight_data & 0xf0) >> 4;
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}*/
|
||||
|
||||
static u32 uniwill_read_kbd_bl_rgb(u8 *red, u8 *green, u8 *blue)
|
||||
{
|
||||
u32 result;
|
||||
|
||||
uniwill_read_ec_ram(0x1803, red);
|
||||
uniwill_read_ec_ram(0x1805, green);
|
||||
uniwill_read_ec_ram(0x1808, blue);
|
||||
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void uniwill_write_kbd_bl_rgb(u8 red, u8 green, u8 blue)
|
||||
{
|
||||
if (red > 0xc8) red = 0xc8;
|
||||
if (green > 0xc8) green = 0xc8;
|
||||
if (blue > 0xc8) blue = 0xc8;
|
||||
uniwill_write_ec_ram(0x1803, red);
|
||||
uniwill_write_ec_ram(0x1805, green);
|
||||
uniwill_write_ec_ram(0x1808, blue);
|
||||
TUXEDO_DEBUG("Wrote kbd color [%0#4x, %0#4x, %0#4x]\n", red, green, blue);
|
||||
}
|
||||
|
||||
static void uniwill_write_kbd_bl_state(void) {
|
||||
// Get single colors from state
|
||||
u32 color_red = ((kbd_led_state_uw.color >> 0x10) & 0xff);
|
||||
u32 color_green = (kbd_led_state_uw.color >> 0x08) & 0xff;
|
||||
u32 color_blue = (kbd_led_state_uw.color >> 0x00) & 0xff;
|
||||
|
||||
u32 brightness_percentage = (kbd_led_state_uw.brightness * 100) / UNIWILL_BRIGHTNESS_MAX;
|
||||
|
||||
// Scale color values to valid range
|
||||
color_red = (color_red * 0xc8) / 0xff;
|
||||
color_green = (color_green * 0xc8) / 0xff;
|
||||
color_blue = (color_blue * 0xc8) / 0xff;
|
||||
|
||||
// Scale the respective color values with brightness
|
||||
color_red = (color_red * brightness_percentage) / 100;
|
||||
color_green = (color_green * brightness_percentage) / 100;
|
||||
color_blue = (color_blue * brightness_percentage) / 100;
|
||||
|
||||
uniwill_write_kbd_bl_rgb(color_red, color_green, color_blue);
|
||||
}
|
||||
|
||||
static void uniwill_write_kbd_bl_reset(void)
|
||||
{
|
||||
uniwill_write_ec_ram(0x078c, 0x10);
|
||||
uniwill_write_ec_ram(UW_EC_REG_KBD_BL_STATUS, backlight_data);
|
||||
}
|
||||
|
||||
void uniwill_event_callb(u32 code)
|
||||
|
@ -351,7 +266,7 @@ void uniwill_event_callb(u32 code)
|
|||
}
|
||||
|
||||
// Special key combination when mode change key is pressed
|
||||
if (code == 0xb0) {
|
||||
if (code == UNIWILL_OSD_MODE_CHANGE_KEY_EVENT) {
|
||||
input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTMETA, 1);
|
||||
input_report_key(uniwill_keyboard_driver.input_device, KEY_LEFTALT, 1);
|
||||
input_report_key(uniwill_keyboard_driver.input_device, KEY_F6, 1);
|
||||
|
@ -362,131 +277,18 @@ void uniwill_event_callb(u32 code)
|
|||
input_sync(uniwill_keyboard_driver.input_device);
|
||||
}
|
||||
|
||||
// Keyboard backlight brightness toggle
|
||||
if (uniwill_kbd_bl_type_rgb_single_color) {
|
||||
switch (code) {
|
||||
case UNIWILL_OSD_KB_LED_LEVEL0:
|
||||
kbd_led_state_uw.brightness = 0x00;
|
||||
uniwill_write_kbd_bl_state();
|
||||
break;
|
||||
case UNIWILL_OSD_KB_LED_LEVEL1:
|
||||
kbd_led_state_uw.brightness = 0x20;
|
||||
uniwill_write_kbd_bl_state();
|
||||
break;
|
||||
case UNIWILL_OSD_KB_LED_LEVEL2:
|
||||
kbd_led_state_uw.brightness = 0x50;
|
||||
uniwill_write_kbd_bl_state();
|
||||
break;
|
||||
case UNIWILL_OSD_KB_LED_LEVEL3:
|
||||
kbd_led_state_uw.brightness = 0x80;
|
||||
uniwill_write_kbd_bl_state();
|
||||
break;
|
||||
case UNIWILL_OSD_KB_LED_LEVEL4:
|
||||
kbd_led_state_uw.brightness = 0xc8;
|
||||
uniwill_write_kbd_bl_state();
|
||||
break;
|
||||
// Refresh keyboard state on cable switch event
|
||||
case UNIWILL_OSD_DC_ADAPTER_CHANGE:
|
||||
uniwill_write_kbd_bl_state();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Refresh keyboard state and charging prio on cable switch event
|
||||
if (code == UNIWILL_OSD_DC_ADAPTER_CHANGE) {
|
||||
uniwill_leds_restore_state_extern();
|
||||
|
||||
switch (code) {
|
||||
case UNIWILL_OSD_DC_ADAPTER_CHANGE:
|
||||
msleep(50);
|
||||
uw_charging_priority_write_state();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t uw_brightness_show(struct device *child,
|
||||
struct device_attribute *attr, char *buffer)
|
||||
static void uw_kbd_bl_init_set(struct platform_device *dev)
|
||||
{
|
||||
return sprintf(buffer, "%d\n", kbd_led_state_uw.brightness);
|
||||
}
|
||||
|
||||
static ssize_t uw_brightness_store(struct device *child,
|
||||
struct device_attribute *attr,
|
||||
const char *buffer, size_t size)
|
||||
{
|
||||
u32 brightness_input;
|
||||
int err = kstrtouint(buffer, 0, &brightness_input);
|
||||
if (err) return err;
|
||||
if (brightness_input > UNIWILL_BRIGHTNESS_MAX) return -EINVAL;
|
||||
kbd_led_state_uw.brightness = (u8)brightness_input;
|
||||
uniwill_write_kbd_bl_state();
|
||||
return size;
|
||||
}
|
||||
|
||||
static ssize_t uw_color_string_show(struct device *child,
|
||||
struct device_attribute *attr, char *buffer)
|
||||
{
|
||||
int i;
|
||||
sprintf(buffer, "Color values:");
|
||||
for (i = 0; i < color_list.size; ++i) {
|
||||
sprintf(buffer + strlen(buffer), " %s",
|
||||
color_list.colors[i].name);
|
||||
}
|
||||
sprintf(buffer + strlen(buffer), "\n");
|
||||
return strlen(buffer);
|
||||
}
|
||||
|
||||
static ssize_t uw_color_string_store(struct device *child,
|
||||
struct device_attribute *attr,
|
||||
const char *buffer, size_t size)
|
||||
{
|
||||
u32 color_value;
|
||||
char *buffer_copy;
|
||||
|
||||
buffer_copy = kmalloc(size + 1, GFP_KERNEL);
|
||||
strcpy(buffer_copy, buffer);
|
||||
color_value = color_lookup(&color_list, strstrip(buffer_copy));
|
||||
kfree(buffer_copy);
|
||||
|
||||
if (color_value > 0xffffff) return -EINVAL;
|
||||
kbd_led_state_uw.color = color_value;
|
||||
uniwill_write_kbd_bl_state();
|
||||
return size;
|
||||
}
|
||||
|
||||
// Device attributes used by uw kbd
|
||||
struct uw_kbd_dev_attrs_t {
|
||||
struct device_attribute brightness;
|
||||
struct device_attribute color_string;
|
||||
} uw_kbd_dev_attrs = {
|
||||
.brightness = __ATTR(brightness, 0644, uw_brightness_show, uw_brightness_store),
|
||||
.color_string = __ATTR(color_string, 0644, uw_color_string_show, uw_color_string_store)
|
||||
};
|
||||
|
||||
// Device attributes used for uw_kbd_bl_color
|
||||
static struct attribute *uw_kbd_bl_color_attrs[] = {
|
||||
&uw_kbd_dev_attrs.brightness.attr,
|
||||
&uw_kbd_dev_attrs.color_string.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct attribute_group uw_kbd_bl_color_attr_group = {
|
||||
.name = "uw_kbd_bl_color",
|
||||
.attrs = uw_kbd_bl_color_attrs
|
||||
};
|
||||
|
||||
static void uw_kbd_bl_init_set(void)
|
||||
{
|
||||
if (uniwill_kbd_bl_type_rgb_single_color) {
|
||||
// Reset keyboard backlight
|
||||
uniwill_write_kbd_bl_reset();
|
||||
// Make sure reset finish before continue
|
||||
msleep(100);
|
||||
|
||||
// Disable backlight while initializing
|
||||
// uniwill_write_kbd_bl_enable(0);
|
||||
|
||||
// Update keyboard backlight according to the current state
|
||||
uniwill_write_kbd_bl_state();
|
||||
}
|
||||
|
||||
// Enable keyboard backlight
|
||||
uniwill_leds_init_late(dev);
|
||||
uniwill_write_kbd_bl_enable(1);
|
||||
}
|
||||
|
||||
|
@ -500,6 +302,28 @@ static struct timer_list uw_kbd_bl_init_timer;
|
|||
static volatile int uw_kbd_bl_check_count = 40;
|
||||
static int uw_kbd_bl_init_check_interval_ms = 500;
|
||||
|
||||
static int uniwill_read_kbd_bl_rgb(u8 *red, u8 *green, u8 *blue)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
result = uniwill_read_ec_ram(UW_EC_REG_KBD_BL_RGB_RED_BRIGHTNESS, red);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
result = uniwill_read_ec_ram(UW_EC_REG_KBD_BL_RGB_GREEN_BRIGHTNESS, green);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
result = uniwill_read_ec_ram(UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS, blue);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct platform_device *uw_kbd_bl_init_ready_check_work_func_args_dev;
|
||||
|
||||
static void uw_kbd_bl_init_ready_check_work_func(struct work_struct *work)
|
||||
{
|
||||
u8 uw_cur_red, uw_cur_green, uw_cur_blue;
|
||||
|
@ -515,7 +339,7 @@ static void uw_kbd_bl_init_ready_check_work_func(struct work_struct *work)
|
|||
}
|
||||
|
||||
if (prev_colors_same) {
|
||||
uw_kbd_bl_init_set();
|
||||
uw_kbd_bl_init_set(uw_kbd_bl_init_ready_check_work_func_args_dev);
|
||||
del_timer(&uw_kbd_bl_init_timer);
|
||||
} else {
|
||||
if (uw_kbd_bl_check_count != 0) {
|
||||
|
@ -540,51 +364,15 @@ static int uw_kbd_bl_init(struct platform_device *dev)
|
|||
{
|
||||
int status = 0;
|
||||
|
||||
uniwill_kbd_bl_type_rgb_single_color = false
|
||||
// New names
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1501A1650TI")
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1501A2060")
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1501I1650TI")
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1501I2060")
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1701A1650TI")
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1701A2060")
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1701I1650TI")
|
||||
| dmi_match(DMI_BOARD_NAME, "POLARIS1701I2060")
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 18, 0)
|
||||
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XA02")
|
||||
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XI02")
|
||||
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XA03")
|
||||
| dmi_match(DMI_PRODUCT_SKU, "POLARIS1XI03")
|
||||
#endif
|
||||
|
||||
// Old names
|
||||
// | dmi_match(DMI_BOARD_NAME, "Polaris15I01")
|
||||
// | dmi_match(DMI_BOARD_NAME, "Polaris17I01")
|
||||
// | dmi_match(DMI_BOARD_NAME, "Polaris15A01")
|
||||
// | dmi_match(DMI_BOARD_NAME, "Polaris1501I2060")
|
||||
// | dmi_match(DMI_BOARD_NAME, "Polaris1701I2060")
|
||||
;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)
|
||||
TUXEDO_ERROR(
|
||||
"Warning: Kernel version less that 4.18, keyboard backlight might not be properly recognized.");
|
||||
TUXEDO_ERROR("Warning: Kernel version less that 4.18, keyboard backlight might not be properly recognized.");
|
||||
#endif
|
||||
|
||||
// Save previous enable state
|
||||
uniwill_kbd_bl_enable_state_on_start = uniwill_read_kbd_bl_enabled();
|
||||
|
||||
if (uniwill_kbd_bl_type_rgb_single_color) {
|
||||
// Initialize keyboard backlight driver state according to parameters
|
||||
if (param_brightness > UNIWILL_BRIGHTNESS_MAX) param_brightness = UNIWILL_BRIGHTNESS_DEFAULT;
|
||||
kbd_led_state_uw.brightness = param_brightness;
|
||||
if (color_lookup(&color_list, param_color) <= (u32) 0xffffff) kbd_led_state_uw.color = color_lookup(&color_list, param_color);
|
||||
else kbd_led_state_uw.color = UNIWILL_COLOR_DEFAULT;
|
||||
|
||||
// Init sysfs bl attributes group
|
||||
status = sysfs_create_group(&dev->dev.kobj, &uw_kbd_bl_color_attr_group);
|
||||
if (status) TUXEDO_ERROR("Failed to create sysfs group\n");
|
||||
uniwill_leds_init_early(dev);
|
||||
|
||||
if (uniwill_leds_get_backlight_type() == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
// Start periodic checking of animation, set and enable bl when done
|
||||
uw_kbd_bl_init_ready_check_work_func_args_dev = dev;
|
||||
timer_setup(&uw_kbd_bl_init_timer, uw_kbd_bl_init_ready_check, 0);
|
||||
mod_timer(&uw_kbd_bl_init_timer, jiffies + msecs_to_jiffies(uw_kbd_bl_init_check_interval_ms));
|
||||
} else {
|
||||
|
@ -1291,9 +1079,7 @@ static int uniwill_keyboard_remove(struct platform_device *dev)
|
|||
if (uw_charging_profile_loaded)
|
||||
sysfs_remove_group(&dev->dev.kobj, &uw_charging_profile_attr_group);
|
||||
|
||||
if (uniwill_kbd_bl_type_rgb_single_color) {
|
||||
sysfs_remove_group(&dev->dev.kobj, &uw_kbd_bl_color_attr_group);
|
||||
}
|
||||
uniwill_leds_remove(dev);
|
||||
|
||||
// Restore previous backlight enable state
|
||||
if (uniwill_kbd_bl_enable_state_on_start != 0xff) {
|
||||
|
@ -1321,11 +1107,7 @@ static int uniwill_keyboard_suspend(struct platform_device *dev, pm_message_t st
|
|||
|
||||
static int uniwill_keyboard_resume(struct platform_device *dev)
|
||||
{
|
||||
if (uniwill_kbd_bl_type_rgb_single_color) {
|
||||
uniwill_write_kbd_bl_reset();
|
||||
msleep(100);
|
||||
uniwill_write_kbd_bl_state();
|
||||
}
|
||||
uniwill_leds_restore_state_extern();
|
||||
uniwill_write_kbd_bl_enable(1);
|
||||
return 0;
|
||||
}
|
||||
|
@ -1346,3 +1128,5 @@ struct tuxedo_keyboard_driver uniwill_keyboard_driver = {
|
|||
.probe = uniwill_keyboard_probe,
|
||||
.key_map = uniwill_wmi_keymap,
|
||||
};
|
||||
|
||||
#endif // UNIWILL_KEYBOARD_H
|
||||
|
|
329
src/uniwill_leds.h
Normal file
329
src/uniwill_leds.h
Normal file
|
@ -0,0 +1,329 @@
|
|||
/*!
|
||||
* Copyright (c) 2018-2020 TUXEDO Computers GmbH <tux@tuxedocomputers.com>
|
||||
*
|
||||
* This file is part of tuxedo-keyboard.
|
||||
*
|
||||
* tuxedo-keyboard is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This software is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this software. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef UNIWILL_LEDS_H
|
||||
#define UNIWILL_LEDS_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
enum uniwill_kb_backlight_types {
|
||||
UNIWILL_KB_BACKLIGHT_TYPE_NONE,
|
||||
UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR,
|
||||
UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB,
|
||||
UNIWILL_KB_BACKLIGHT_TYPE_PER_KEY_RGB
|
||||
};
|
||||
|
||||
#define UNIWILL_KBD_BRIGHTNESS_MAX 0xff
|
||||
#define UNIWILL_KBD_BRIGHTNESS_DEFAULT 0x00
|
||||
|
||||
#define UNIWILL_KBD_BRIGHTNESS_WHITE_MAX 0x02
|
||||
#define UNIWILL_KBD_BRIGHTNESS_WHITE_DEFAULT 0x00
|
||||
|
||||
#define UNIWILL_KB_COLOR_DEFAULT_RED 0xff
|
||||
#define UNIWILL_KB_COLOR_DEFAULT_GREEN 0xff
|
||||
#define UNIWILL_KB_COLOR_DEFAULT_BLUE 0xff
|
||||
#define UNIWILL_KB_COLOR_DEFAULT ((UNIWILL_KB_COLOR_DEFAULT_RED << 16) + (UNIWILL_KB_COLOR_DEFAULT_GREEN << 8) + UNIWILL_KB_COLOR_DEFAULT_BLUE)
|
||||
|
||||
int uniwill_leds_init_early(struct platform_device *dev);
|
||||
int uniwill_leds_init_late(struct platform_device *dev);
|
||||
int uniwill_leds_remove(struct platform_device *dev);
|
||||
enum uniwill_kb_backlight_types uniwill_leds_get_backlight_type(void);
|
||||
void uniwill_leds_restore_state_extern(void);
|
||||
void uniwill_leds_set_brightness_extern(enum led_brightness brightness);
|
||||
void uniwill_leds_set_color_extern(u32 color);
|
||||
|
||||
// TODO The following should go into a seperate .c file, but for this to work more reworking is required in the tuxedo_keyboard structure.
|
||||
|
||||
#include "uniwill_leds.h"
|
||||
|
||||
#include "uniwill_interfaces.h"
|
||||
|
||||
#include <linux/led-class-multicolor.h>
|
||||
|
||||
static enum uniwill_kb_backlight_types uniwill_kb_backlight_type = UNIWILL_KB_BACKLIGHT_TYPE_NONE;
|
||||
static bool uw_leds_initialized = false;
|
||||
|
||||
static int uniwill_write_kbd_bl_white(u8 brightness)
|
||||
{
|
||||
u8 data;
|
||||
|
||||
uniwill_read_ec_ram(UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS, &data);
|
||||
// When keyboard backlight is off, new settings to 0x078c do not get applied automatically
|
||||
// on Pulse Gen1/2 until next keypress or manual change to 0x1808 (immediate brightness
|
||||
// value for some reason.
|
||||
// Sidenote: IBP Gen6/7 has immediate brightness value on 0x1802 and not on 0x1808, but does
|
||||
// not need this workaround.
|
||||
if (!data) {
|
||||
uniwill_write_ec_ram(UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS, 0x01);
|
||||
}
|
||||
|
||||
data = 0;
|
||||
uniwill_read_ec_ram(UW_EC_REG_KBD_BL_STATUS, &data);
|
||||
data &= 0x0f; // lower bits must be preserved
|
||||
data |= UW_EC_REG_KBD_BL_STATUS_SUBCMD_RESET;
|
||||
data |= brightness << 5;
|
||||
return uniwill_write_ec_ram(UW_EC_REG_KBD_BL_STATUS, data);
|
||||
}
|
||||
|
||||
static int uniwill_write_kbd_bl_rgb(u8 red, u8 green, u8 blue)
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
result = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_RGB_RED_BRIGHTNESS, red);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
result = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_RGB_GREEN_BRIGHTNESS, green);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
result = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_RGB_BLUE_BRIGHTNESS, blue);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
|
||||
pr_debug("Wrote kbd color [%0#4x, %0#4x, %0#4x]\n", red, green, blue);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void uniwill_leds_set_brightness(struct led_classdev *led_cdev __always_unused, enum led_brightness brightness) {
|
||||
int ret = uniwill_write_kbd_bl_white(brightness);
|
||||
if (ret) {
|
||||
pr_debug("uniwill_leds_set_brightness(): uniwill_write_kbd_bl_white() failed\n");
|
||||
return;
|
||||
}
|
||||
led_cdev->brightness = brightness;
|
||||
}
|
||||
|
||||
static void uniwill_leds_set_brightness_mc(struct led_classdev *led_cdev, enum led_brightness brightness) {
|
||||
int ret;
|
||||
struct led_classdev_mc *mcled_cdev = lcdev_to_mccdev(led_cdev);
|
||||
|
||||
led_mc_calc_color_components(mcled_cdev, brightness);
|
||||
|
||||
ret = uniwill_write_kbd_bl_rgb(mcled_cdev->subled_info[0].brightness,
|
||||
mcled_cdev->subled_info[1].brightness,
|
||||
mcled_cdev->subled_info[2].brightness);
|
||||
if (ret) {
|
||||
pr_debug("uniwill_leds_set_brightness_mc(): uniwill_write_kbd_bl_rgb() failed\n");
|
||||
return;
|
||||
}
|
||||
led_cdev->brightness = brightness;
|
||||
}
|
||||
|
||||
static struct led_classdev uniwill_led_cdev = {
|
||||
.name = "white:" LED_FUNCTION_KBD_BACKLIGHT,
|
||||
.max_brightness = UNIWILL_KBD_BRIGHTNESS_WHITE_MAX,
|
||||
.brightness_set = &uniwill_leds_set_brightness,
|
||||
.brightness = UNIWILL_KBD_BRIGHTNESS_WHITE_DEFAULT
|
||||
};
|
||||
|
||||
static struct mc_subled uw_mcled_cdev_subleds[3] = {
|
||||
{
|
||||
.color_index = LED_COLOR_ID_RED,
|
||||
.brightness = UNIWILL_KBD_BRIGHTNESS_MAX,
|
||||
.intensity = UNIWILL_KB_COLOR_DEFAULT_RED,
|
||||
.channel = 0
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_GREEN,
|
||||
.brightness = UNIWILL_KBD_BRIGHTNESS_MAX,
|
||||
.intensity = UNIWILL_KB_COLOR_DEFAULT_GREEN,
|
||||
.channel = 0
|
||||
},
|
||||
{
|
||||
.color_index = LED_COLOR_ID_BLUE,
|
||||
.brightness = UNIWILL_KBD_BRIGHTNESS_MAX,
|
||||
.intensity = UNIWILL_KB_COLOR_DEFAULT_BLUE,
|
||||
.channel = 0
|
||||
}
|
||||
};
|
||||
|
||||
static struct led_classdev_mc uniwill_mcled_cdev = {
|
||||
.led_cdev.name = "rgb:" LED_FUNCTION_KBD_BACKLIGHT,
|
||||
.led_cdev.max_brightness = UNIWILL_KBD_BRIGHTNESS_MAX,
|
||||
.led_cdev.brightness_set = &uniwill_leds_set_brightness_mc,
|
||||
.led_cdev.brightness = UNIWILL_KBD_BRIGHTNESS_DEFAULT,
|
||||
.num_colors = 3,
|
||||
.subled_info = uw_mcled_cdev_subleds
|
||||
};
|
||||
|
||||
int uniwill_leds_init_early(struct platform_device *dev)
|
||||
{
|
||||
// FIXME Use mutexes
|
||||
int ret;
|
||||
u8 data;
|
||||
|
||||
ret = uniwill_read_ec_ram(UW_EC_REG_BAREBONE_ID, &data);
|
||||
if (ret) {
|
||||
pr_err("Reading barebone ID failed.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data == UW_EC_REG_BAREBONE_ID_VALUE_PFxxxxx ||
|
||||
data == UW_EC_REG_BAREBONE_ID_VALUE_PFxMxxx ||
|
||||
data == UW_EC_REG_BAREBONE_ID_VALUE_PH4TRX1 ||
|
||||
data == UW_EC_REG_BAREBONE_ID_VALUE_PH4TUX1 ||
|
||||
data == UW_EC_REG_BAREBONE_ID_VALUE_PH4TQx1 ||
|
||||
data == UW_EC_REG_BAREBONE_ID_VALUE_PH6TRX1 ||
|
||||
data == UW_EC_REG_BAREBONE_ID_VALUE_PH6TQxx ||
|
||||
data == UW_EC_REG_BAREBONE_ID_VALUE_PH4Axxx) {
|
||||
ret = uniwill_read_ec_ram(UW_EC_REG_KBD_BL_STATUS, &data);
|
||||
if (ret) {
|
||||
pr_err("Reading keyboard backlight status failed.\n");
|
||||
return ret;
|
||||
}
|
||||
if (data & UW_EC_REG_KBD_BL_STATUS_BIT_WHITE_ONLY_KB) {
|
||||
uniwill_kb_backlight_type = UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR;
|
||||
}
|
||||
}
|
||||
else {
|
||||
ret = uniwill_read_ec_ram(UW_EC_REG_FEATURES_1, &data);
|
||||
if (ret) {
|
||||
pr_err("Reading features 1 failed.\n");
|
||||
return ret;
|
||||
}
|
||||
if (data & UW_EC_REG_FEATURES_1_BIT_1_ZONE_RGB_KB) {
|
||||
uniwill_kb_backlight_type = UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB;
|
||||
}
|
||||
}
|
||||
pr_debug("Keyboard backlight type: 0x%02x\n", uniwill_kb_backlight_type);
|
||||
|
||||
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
|
||||
pr_debug("Registering fixed color leds interface\n");
|
||||
ret = led_classdev_register(&dev->dev, &uniwill_led_cdev);
|
||||
if (ret) {
|
||||
pr_err("Registering fixed color leds interface failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
pr_debug("Registering single zone rgb leds interface\n");
|
||||
ret = devm_led_classdev_multicolor_register(&dev->dev, &uniwill_mcled_cdev);
|
||||
if (ret) {
|
||||
pr_err("Registering single zone rgb leds interface failed\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
uw_leds_initialized = true;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(uniwill_leds_init_early);
|
||||
|
||||
int uniwill_leds_init_late(struct platform_device *dev)
|
||||
{
|
||||
// FIXME Use mutexes
|
||||
int ret;
|
||||
|
||||
ret = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_MAX_BRIGHTNESS, 0xff);
|
||||
if (ret) {
|
||||
pr_err("Setting max keyboard brightness value failed\n");
|
||||
uniwill_leds_remove(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
uniwill_leds_restore_state_extern();
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(uniwill_leds_init_late);
|
||||
|
||||
int uniwill_leds_remove(struct platform_device *dev)
|
||||
{
|
||||
// FIXME Use mutexes
|
||||
int ret;
|
||||
|
||||
if (uw_leds_initialized) {
|
||||
uw_leds_initialized = false;
|
||||
|
||||
uniwill_leds_set_brightness_extern(0x00);
|
||||
ret = uniwill_write_ec_ram(UW_EC_REG_KBD_BL_MAX_BRIGHTNESS, 0xc8);
|
||||
if (ret) {
|
||||
pr_err("Resetting max keyboard brightness value failed\n");
|
||||
}
|
||||
|
||||
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
|
||||
led_classdev_unregister(&uniwill_led_cdev);
|
||||
}
|
||||
else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
devm_led_classdev_multicolor_unregister(&dev->dev, &uniwill_mcled_cdev);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(uniwill_leds_remove);
|
||||
|
||||
enum uniwill_kb_backlight_types uniwill_leds_get_backlight_type() {
|
||||
return uniwill_kb_backlight_type;
|
||||
}
|
||||
EXPORT_SYMBOL(uniwill_leds_get_backlight_type);
|
||||
|
||||
void uniwill_leds_restore_state_extern(void) {
|
||||
u8 data;
|
||||
|
||||
if (uw_leds_initialized) {
|
||||
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
|
||||
uniwill_led_cdev.brightness_set(&uniwill_led_cdev, uniwill_led_cdev.brightness);
|
||||
}
|
||||
else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
// reset
|
||||
uniwill_read_ec_ram(UW_EC_REG_KBD_BL_STATUS, &data);
|
||||
data |= UW_EC_REG_KBD_BL_STATUS_SUBCMD_RESET;
|
||||
uniwill_write_ec_ram(UW_EC_REG_KBD_BL_STATUS, data);
|
||||
|
||||
// write
|
||||
uniwill_mcled_cdev.led_cdev.brightness_set(&uniwill_mcled_cdev.led_cdev, uniwill_mcled_cdev.led_cdev.brightness);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(uniwill_leds_restore_state_extern);
|
||||
|
||||
void uniwill_leds_set_brightness_extern(enum led_brightness brightness) {
|
||||
if (uw_leds_initialized) {
|
||||
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_FIXED_COLOR) {
|
||||
uniwill_led_cdev.brightness_set(&uniwill_led_cdev, brightness);
|
||||
}
|
||||
else if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
uniwill_mcled_cdev.led_cdev.brightness_set(&uniwill_mcled_cdev.led_cdev, brightness);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(uniwill_leds_set_brightness_extern);
|
||||
|
||||
void uniwill_leds_set_color_extern(u32 color) {
|
||||
if (uw_leds_initialized) {
|
||||
if (uniwill_kb_backlight_type == UNIWILL_KB_BACKLIGHT_TYPE_1_ZONE_RGB) {
|
||||
uniwill_mcled_cdev.subled_info[0].intensity = (color >> 16) & 0xff;
|
||||
uniwill_mcled_cdev.subled_info[1].intensity = (color >> 8) & 0xff;
|
||||
uniwill_mcled_cdev.subled_info[2].intensity = color & 0xff;
|
||||
uniwill_mcled_cdev.led_cdev.brightness_set(&uniwill_mcled_cdev.led_cdev, uniwill_mcled_cdev.led_cdev.brightness);
|
||||
}
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(uniwill_leds_set_color_extern);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#endif // UNIWILL_LEDS_H
|
|
@ -43,11 +43,11 @@ static bool uniwill_ec_direct = true;
|
|||
|
||||
DEFINE_MUTEX(uniwill_ec_lock);
|
||||
|
||||
static u32 uw_wmi_ec_evaluate(u8 addr_low, u8 addr_high, u8 data_low, u8 data_high, u8 read_flag, u32 *return_buffer)
|
||||
static int uw_wmi_ec_evaluate(u8 addr_low, u8 addr_high, u8 data_low, u8 data_high, u8 read_flag, u32 *return_buffer)
|
||||
{
|
||||
acpi_status status;
|
||||
union acpi_object *out_acpi;
|
||||
u32 e_result = 0;
|
||||
int e_result = 0;
|
||||
|
||||
// Kernel buffer for input argument
|
||||
u32 *wmi_arg = (u32 *) kmalloc(sizeof(u32)*10, GFP_KERNEL);
|
||||
|
@ -98,10 +98,10 @@ static u32 uw_wmi_ec_evaluate(u8 addr_low, u8 addr_high, u8 data_low, u8 data_hi
|
|||
/**
|
||||
* EC address read through WMI
|
||||
*/
|
||||
static u32 uw_ec_read_addr_wmi(u8 addr_low, u8 addr_high, union uw_ec_read_return *output)
|
||||
static int uw_ec_read_addr_wmi(u8 addr_low, u8 addr_high, union uw_ec_read_return *output)
|
||||
{
|
||||
u32 uw_data[10];
|
||||
u32 ret = uw_wmi_ec_evaluate(addr_low, addr_high, 0x00, 0x00, 1, uw_data);
|
||||
int ret = uw_wmi_ec_evaluate(addr_low, addr_high, 0x00, 0x00, 1, uw_data);
|
||||
output->dword = uw_data[0];
|
||||
// pr_debug("addr: 0x%02x%02x value: %0#4x (high: %0#4x) result: %d\n", addr_high, addr_low, output->bytes.data_low, output->bytes.data_high, ret);
|
||||
return ret;
|
||||
|
@ -110,10 +110,10 @@ static u32 uw_ec_read_addr_wmi(u8 addr_low, u8 addr_high, union uw_ec_read_retur
|
|||
/**
|
||||
* EC address write through WMI
|
||||
*/
|
||||
static u32 uw_ec_write_addr_wmi(u8 addr_low, u8 addr_high, u8 data_low, u8 data_high, union uw_ec_write_return *output)
|
||||
static int uw_ec_write_addr_wmi(u8 addr_low, u8 addr_high, u8 data_low, u8 data_high, union uw_ec_write_return *output)
|
||||
{
|
||||
u32 uw_data[10];
|
||||
u32 ret = uw_wmi_ec_evaluate(addr_low, addr_high, data_low, data_high, 0, uw_data);
|
||||
int ret = uw_wmi_ec_evaluate(addr_low, addr_high, data_low, data_high, 0, uw_data);
|
||||
output->dword = uw_data[0];
|
||||
return ret;
|
||||
}
|
||||
|
@ -121,9 +121,9 @@ static u32 uw_ec_write_addr_wmi(u8 addr_low, u8 addr_high, u8 data_low, u8 data_
|
|||
/**
|
||||
* Direct EC address read
|
||||
*/
|
||||
static u32 uw_ec_read_addr_direct(u8 addr_low, u8 addr_high, union uw_ec_read_return *output)
|
||||
static int uw_ec_read_addr_direct(u8 addr_low, u8 addr_high, union uw_ec_read_return *output)
|
||||
{
|
||||
u32 result;
|
||||
int result;
|
||||
u8 tmp, count, flags;
|
||||
bool ready;
|
||||
bool bflag = false;
|
||||
|
@ -180,9 +180,9 @@ static u32 uw_ec_read_addr_direct(u8 addr_low, u8 addr_high, union uw_ec_read_re
|
|||
return result;
|
||||
}
|
||||
|
||||
static u32 uw_ec_write_addr_direct(u8 addr_low, u8 addr_high, u8 data_low, u8 data_high, union uw_ec_write_return *output)
|
||||
static int uw_ec_write_addr_direct(u8 addr_low, u8 addr_high, u8 data_low, u8 data_high, union uw_ec_write_return *output)
|
||||
{
|
||||
u32 result = 0;
|
||||
int result = 0;
|
||||
u8 tmp, count, flags;
|
||||
bool ready;
|
||||
bool bflag = false;
|
||||
|
@ -239,9 +239,9 @@ static u32 uw_ec_write_addr_direct(u8 addr_low, u8 addr_high, u8 data_low, u8 da
|
|||
return result;
|
||||
}
|
||||
|
||||
u32 uw_wmi_read_ec_ram(u16 addr, u8 *data)
|
||||
int uw_wmi_read_ec_ram(u16 addr, u8 *data)
|
||||
{
|
||||
u32 result;
|
||||
int result;
|
||||
u8 addr_low, addr_high;
|
||||
union uw_ec_read_return output;
|
||||
|
||||
|
@ -261,9 +261,9 @@ u32 uw_wmi_read_ec_ram(u16 addr, u8 *data)
|
|||
return result;
|
||||
}
|
||||
|
||||
u32 uw_wmi_write_ec_ram(u16 addr, u8 data)
|
||||
int uw_wmi_write_ec_ram(u16 addr, u8 data)
|
||||
{
|
||||
u32 result;
|
||||
int result;
|
||||
u8 addr_low, addr_high, data_low, data_high;
|
||||
union uw_ec_write_return output;
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
options tuxedo-keyboard mode=0 brightness=75 color_left=0xFFFFFF color_center=0xFFFFFF color_right=0xFFFFFF
|
||||
options tuxedo-keyboard kbd_backlight_mode=0
|
||||
|
|
Loading…
Reference in a new issue