[hp-wmi] Keyboard lighting
This commit is contained in:
parent
4dc14eb6f9
commit
db43bc3cf6
116
hp-wmi/hp-wmi.c
116
hp-wmi/hp-wmi.c
|
@ -27,6 +27,7 @@
|
||||||
#include <linux/rfkill.h>
|
#include <linux/rfkill.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/dmi.h>
|
#include <linux/dmi.h>
|
||||||
|
#include <linux/leds.h>
|
||||||
|
|
||||||
MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
|
MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
|
||||||
MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
|
MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
|
||||||
|
@ -143,6 +144,7 @@ enum hp_wmi_command {
|
||||||
HPWMI_WRITE = 0x02,
|
HPWMI_WRITE = 0x02,
|
||||||
HPWMI_ODM = 0x03,
|
HPWMI_ODM = 0x03,
|
||||||
HPWMI_GM = 0x20008,
|
HPWMI_GM = 0x20008,
|
||||||
|
HPWMI_KB = 0x20009,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum hp_wmi_hardware_mask {
|
enum hp_wmi_hardware_mask {
|
||||||
|
@ -274,6 +276,9 @@ static const char * const tablet_chassis_types[] = {
|
||||||
|
|
||||||
#define DEVICE_MODE_TABLET 0x06
|
#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 */
|
/* map output size to the corresponding WMI method id */
|
||||||
static inline int encode_outsize_for_pvsz(int outsize)
|
static inline int encode_outsize_for_pvsz(int outsize)
|
||||||
{
|
{
|
||||||
|
@ -781,12 +786,56 @@ static int camera_shutter_input_setup(void)
|
||||||
return err;
|
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);
|
||||||
|
|
||||||
|
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(display);
|
||||||
static DEVICE_ATTR_RO(hddtemp);
|
static DEVICE_ATTR_RO(hddtemp);
|
||||||
static DEVICE_ATTR_RW(als);
|
static DEVICE_ATTR_RW(als);
|
||||||
static DEVICE_ATTR_RO(dock);
|
static DEVICE_ATTR_RO(dock);
|
||||||
static DEVICE_ATTR_RO(tablet);
|
static DEVICE_ATTR_RO(tablet);
|
||||||
static DEVICE_ATTR_RW(postcode);
|
static DEVICE_ATTR_RW(postcode);
|
||||||
|
static DEVICE_ATTR_RW(zone_colors);
|
||||||
|
|
||||||
static struct attribute *hp_wmi_attrs[] = {
|
static struct attribute *hp_wmi_attrs[] = {
|
||||||
&dev_attr_display.attr,
|
&dev_attr_display.attr,
|
||||||
|
@ -799,6 +848,12 @@ static struct attribute *hp_wmi_attrs[] = {
|
||||||
};
|
};
|
||||||
ATTRIBUTE_GROUPS(hp_wmi);
|
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)
|
static void hp_wmi_notify(u32 value, void *context)
|
||||||
{
|
{
|
||||||
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
@ -910,6 +965,10 @@ static void hp_wmi_notify(u32 value, void *context)
|
||||||
case HPWMI_PROXIMITY_SENSOR:
|
case HPWMI_PROXIMITY_SENSOR:
|
||||||
break;
|
break;
|
||||||
case HPWMI_BACKLIT_KB_BRIGHTNESS:
|
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;
|
break;
|
||||||
case HPWMI_PEAKSHIFT_PERIOD:
|
case HPWMI_PEAKSHIFT_PERIOD:
|
||||||
break;
|
break;
|
||||||
|
@ -1448,6 +1507,60 @@ static int thermal_profile_setup(void)
|
||||||
|
|
||||||
static int hp_wmi_hwmon_init(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)
|
static int __init hp_wmi_bios_setup(struct platform_device *device)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -1475,6 +1588,9 @@ static int __init hp_wmi_bios_setup(struct platform_device *device)
|
||||||
|
|
||||||
thermal_profile_setup();
|
thermal_profile_setup();
|
||||||
|
|
||||||
|
if (is_omen_lighting_supported())
|
||||||
|
omen_backlight_init(&device->dev);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue