[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/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");
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -781,12 +786,56 @@ 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);
|
||||
|
||||
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 +848,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 +965,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;
|
||||
|
@ -1448,6 +1507,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 +1588,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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue