Compare commits
3 commits
888dd34e93
...
433401b8d5
Author | SHA1 | Date | |
---|---|---|---|
naoto | 433401b8d5 | ||
Norbert Bolanowski | db43bc3cf6 | ||
naoto | 4dc14eb6f9 |
226
hp-wmi/hp-wmi.c
226
hp-wmi/hp-wmi.c
|
@ -27,6 +27,7 @@
|
|||
#include <linux/rfkill.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
|
||||
MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
|
||||
|
@ -55,7 +56,7 @@ static const char * const omen_thermal_profile_boards[] = {
|
|||
"874A", "8603", "8604", "8748", "886B", "886C", "878A", "878B", "878C",
|
||||
"88C8", "88CB", "8786", "8787", "8788", "88D1", "88D2", "88F4", "88FD",
|
||||
"88F5", "88F6", "88F7", "88FE", "88FF", "8900", "8901", "8902", "8912",
|
||||
"8917", "8918", "8949", "894A", "89EB"
|
||||
"8917", "8918", "8949", "894A", "89EB", "8A42"
|
||||
};
|
||||
|
||||
/* DMI Board names of Omen laptops that are specifically set to be thermal
|
||||
|
@ -143,6 +144,7 @@ enum hp_wmi_command {
|
|||
HPWMI_WRITE = 0x02,
|
||||
HPWMI_ODM = 0x03,
|
||||
HPWMI_GM = 0x20008,
|
||||
HPWMI_KB = 0x20009,
|
||||
};
|
||||
|
||||
enum hp_wmi_hardware_mask {
|
||||
|
@ -274,6 +276,9 @@ static const char * const tablet_chassis_types[] = {
|
|||
|
||||
#define DEVICE_MODE_TABLET 0x06
|
||||
|
||||
#define OMEN_ZONE_COLOR_OFFSET 0x19
|
||||
#define OMEN_ZONE_COLOR_LEN 0x0c
|
||||
|
||||
/* map output size to the corresponding WMI method id */
|
||||
static inline int encode_outsize_for_pvsz(int outsize)
|
||||
{
|
||||
|
@ -290,6 +295,12 @@ static inline int encode_outsize_for_pvsz(int outsize)
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void omen_thermal_profile_refresh(struct work_struct *work);
|
||||
DECLARE_DELAYED_WORK(omen_profile_refresh, omen_thermal_profile_refresh);
|
||||
|
||||
static int omen_saved_thermal_profile_value = -1;
|
||||
|
||||
/*
|
||||
* hp_wmi_perform_query
|
||||
*
|
||||
|
@ -509,10 +520,61 @@ static int omen_thermal_profile_get(void)
|
|||
return data;
|
||||
}
|
||||
|
||||
static void omen_thermal_profile_refresh(struct work_struct *work) {
|
||||
int tp, err;
|
||||
|
||||
tp = omen_thermal_profile_get();
|
||||
if (tp < 0) {
|
||||
pr_warn("omen-refresh: Failed to get thermal profile, refreshing disabled [code: 0x%x]\n", tp);
|
||||
return;
|
||||
}
|
||||
err = omen_thermal_profile_set(tp);
|
||||
if (err < 0) {
|
||||
pr_warn("omen-refresh: Failed to set thermal profile to 0x%x, refreshing disabled [code: 0x%x]\n", tp, err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Run every 100 seconds
|
||||
schedule_delayed_work(&omen_profile_refresh, 100 * HZ);
|
||||
}
|
||||
|
||||
static void omen_setup_profile_refresh(void) {
|
||||
schedule_delayed_work(&omen_profile_refresh, 0);
|
||||
}
|
||||
|
||||
|
||||
static int omen_save_thermal_profile(void) {
|
||||
int tp;
|
||||
tp = omen_thermal_profile_get();
|
||||
if (tp < 0) {
|
||||
return tp;
|
||||
}
|
||||
omen_saved_thermal_profile_value = tp;
|
||||
return tp;
|
||||
}
|
||||
|
||||
static int omen_restore_thermal_profile(void) {
|
||||
int err, tp;
|
||||
|
||||
if (omen_saved_thermal_profile_value < 0) {
|
||||
pr_info("omen-pm: no saved thermal profile, restore skipped");
|
||||
return 0;
|
||||
}
|
||||
|
||||
tp = omen_saved_thermal_profile_value;
|
||||
omen_saved_thermal_profile_value = -1;
|
||||
|
||||
err = omen_thermal_profile_set(tp);
|
||||
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
return tp;
|
||||
}
|
||||
|
||||
static int hp_wmi_fan_speed_max_set(int enabled)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = hp_wmi_perform_query(HPWMI_FAN_SPEED_MAX_SET_QUERY, HPWMI_GM,
|
||||
&enabled, sizeof(enabled), 0);
|
||||
|
||||
|
@ -781,12 +843,61 @@ static int camera_shutter_input_setup(void)
|
|||
return err;
|
||||
}
|
||||
|
||||
static ssize_t zone_colors_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
|
||||
|
||||
|
||||
u8 val[128];
|
||||
|
||||
int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, HPWMI_KB, &val,
|
||||
zero_if_sup(val), sizeof(val));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
memcpy(buf, &val[OMEN_ZONE_COLOR_OFFSET], OMEN_ZONE_COLOR_LEN);
|
||||
|
||||
pr_info("READ COLOR");
|
||||
|
||||
return OMEN_ZONE_COLOR_LEN;
|
||||
}
|
||||
|
||||
static ssize_t zone_colors_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
u8 val[128];
|
||||
int ret;
|
||||
|
||||
ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, HPWMI_KB, &val,
|
||||
zero_if_sup(val), sizeof(val));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (count != OMEN_ZONE_COLOR_LEN)
|
||||
return -1;
|
||||
|
||||
memcpy(&val[OMEN_ZONE_COLOR_OFFSET], buf, count);
|
||||
|
||||
ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_KB, &val, sizeof(val),
|
||||
0);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return OMEN_ZONE_COLOR_LEN;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(display);
|
||||
static DEVICE_ATTR_RO(hddtemp);
|
||||
static DEVICE_ATTR_RW(als);
|
||||
static DEVICE_ATTR_RO(dock);
|
||||
static DEVICE_ATTR_RO(tablet);
|
||||
static DEVICE_ATTR_RW(postcode);
|
||||
static DEVICE_ATTR_RW(zone_colors);
|
||||
|
||||
static struct attribute *hp_wmi_attrs[] = {
|
||||
&dev_attr_display.attr,
|
||||
|
@ -799,6 +910,12 @@ static struct attribute *hp_wmi_attrs[] = {
|
|||
};
|
||||
ATTRIBUTE_GROUPS(hp_wmi);
|
||||
|
||||
static struct attribute *omen_kbd_led_attrs[] = {
|
||||
&dev_attr_zone_colors.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(omen_kbd_led);
|
||||
|
||||
static void hp_wmi_notify(u32 value, void *context)
|
||||
{
|
||||
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
|
@ -910,6 +1027,10 @@ static void hp_wmi_notify(u32 value, void *context)
|
|||
case HPWMI_PROXIMITY_SENSOR:
|
||||
break;
|
||||
case HPWMI_BACKLIT_KB_BRIGHTNESS:
|
||||
input_report_key(hp_wmi_input_dev, KEY_KBDILLUMTOGGLE, true);
|
||||
input_sync(hp_wmi_input_dev);
|
||||
input_report_key(hp_wmi_input_dev, KEY_KBDILLUMTOGGLE, false);
|
||||
input_sync(hp_wmi_input_dev);
|
||||
break;
|
||||
case HPWMI_PEAKSHIFT_PERIOD:
|
||||
break;
|
||||
|
@ -1392,10 +1513,19 @@ static int thermal_profile_setup(void)
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
// Set default profile to 0x30 - Balanced
|
||||
err = omen_thermal_profile_set(0x30);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
platform_profile_handler.profile_get = platform_profile_omen_get;
|
||||
platform_profile_handler.profile_set = platform_profile_omen_set;
|
||||
|
||||
set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices);
|
||||
// Disable cool profile
|
||||
/* set_bit(PLATFORM_PROFILE_COOL, platform_profile_handler.choices); */
|
||||
|
||||
omen_setup_profile_refresh();
|
||||
|
||||
} else if (is_victus_thermal_profile()) {
|
||||
tp = omen_thermal_profile_get();
|
||||
if (tp < 0)
|
||||
|
@ -1448,6 +1578,60 @@ static int thermal_profile_setup(void)
|
|||
|
||||
static int hp_wmi_hwmon_init(void);
|
||||
|
||||
static enum led_brightness get_omen_backlight_brightness(struct led_classdev *cdev)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, HPWMI_KB, &val, zero_if_sup(val), sizeof(val));
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return (val & 0x80) ? LED_ON : LED_OFF;
|
||||
}
|
||||
|
||||
static void set_omen_backlight_brightness(struct led_classdev *cdev, enum led_brightness value)
|
||||
{
|
||||
char buffer[4] = { (value == LED_OFF) ? 0x64 : 0xe4, 0, 0, 0 };
|
||||
|
||||
hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_KB, &buffer,
|
||||
sizeof(buffer), 0);
|
||||
}
|
||||
|
||||
static struct led_classdev omen_kbd_led = {
|
||||
.name = "hp_omen::kbd_backlight",
|
||||
.brightness_set = set_omen_backlight_brightness,
|
||||
.brightness_get = get_omen_backlight_brightness,
|
||||
.max_brightness = 1,
|
||||
.groups = omen_kbd_led_groups,
|
||||
};
|
||||
|
||||
static bool is_omen_lighting_supported(void)
|
||||
{
|
||||
u8 val;
|
||||
|
||||
int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, HPWMI_KB, &val, zero_if_sup(val), sizeof(val));
|
||||
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
return (val & 1) == 1;
|
||||
}
|
||||
|
||||
static int omen_backlight_init(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
input_set_capability(hp_wmi_input_dev, KE_KEY, KEY_KBDILLUMTOGGLE);
|
||||
|
||||
ret = devm_led_classdev_register(dev, &omen_kbd_led);
|
||||
|
||||
if (ret < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init hp_wmi_bios_setup(struct platform_device *device)
|
||||
{
|
||||
int err;
|
||||
|
@ -1475,6 +1659,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
|||
|
||||
thermal_profile_setup();
|
||||
|
||||
if (is_omen_lighting_supported())
|
||||
omen_backlight_init(&device->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1508,6 +1695,17 @@ static int __exit hp_wmi_bios_remove(struct platform_device *device)
|
|||
|
||||
static int hp_wmi_resume_handler(struct device *device)
|
||||
{
|
||||
int tp;
|
||||
|
||||
tp = omen_restore_thermal_profile();
|
||||
if (tp < 0) {
|
||||
pr_info("omen-tp: Failed to restore thermal profile value: code 0x%x\n", tp);
|
||||
pr_info("omen-tp: Using default profile value: 0x30");
|
||||
tp = 0x30;
|
||||
}
|
||||
|
||||
pr_info("omen-tp: Restored thermal profile: 0x%x", tp);
|
||||
|
||||
/*
|
||||
* Hardware state may have changed while suspended, so trigger
|
||||
* input events for the current state. As this is a switch,
|
||||
|
@ -1543,9 +1741,21 @@ static int hp_wmi_resume_handler(struct device *device)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int hp_wmi_suspend_handler(struct device *device) {
|
||||
int tp;
|
||||
tp = omen_save_thermal_profile();
|
||||
if (tp < 0) pr_info("omen-tp: Failed to save thermal profile value: code 0x%x", tp);
|
||||
|
||||
pr_info("omen-tp: Saved thermal profile: 0x%x", tp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops hp_wmi_pm_ops = {
|
||||
.resume = hp_wmi_resume_handler,
|
||||
.restore = hp_wmi_resume_handler,
|
||||
.suspend = hp_wmi_suspend_handler,
|
||||
.freeze = hp_wmi_suspend_handler
|
||||
};
|
||||
|
||||
static struct platform_driver hp_wmi_driver = {
|
||||
|
@ -1621,6 +1831,16 @@ static int hp_wmi_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
|||
case 2:
|
||||
/* 2 is automatic speed control, which is 0 for us */
|
||||
return hp_wmi_fan_speed_max_set(0);
|
||||
case 3:
|
||||
int ret;
|
||||
int value = 0x2828;
|
||||
ret = hp_wmi_perform_query(0x2E, HPWMI_GM,
|
||||
&value, sizeof(value), 0);
|
||||
if (ret)
|
||||
return ret < 0 ? ret : -EINVAL;
|
||||
|
||||
return value;
|
||||
|
||||
default:
|
||||
/* we don't support manual fan speed control */
|
||||
return -EINVAL;
|
||||
|
|
|
@ -4713,17 +4713,17 @@ static void alc245_fixup_hp_amp(struct hda_codec *codec,
|
|||
{{0x4c0, 0xb}, {0x400, 0x0}, {0x400, 0xbf}}
|
||||
};
|
||||
|
||||
if (action != HDA_FIXUP_ACT_PRE_PROBE) return;
|
||||
if (action != HDA_FIXUP_ACT_INIT) return;
|
||||
|
||||
for (i = 0; i < 9; i++) {
|
||||
snd_hda_codec_write(codec, 0x20, 0, 0x500, 0x26);
|
||||
msleep(20);
|
||||
msleep(50);
|
||||
for (j = 0; j < 3; j++) {
|
||||
snd_hda_codec_write(codec, 0x20, 0, frames[i][j][0], frames[i][j][1]);
|
||||
msleep(20);
|
||||
msleep(50);
|
||||
}
|
||||
snd_hda_codec_write(codec, 0x20, 0, 0x4b0, 0x23);
|
||||
msleep(20);
|
||||
msleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue