// SPDX-License-Identifier: GPL-2.0+ /* * System76 ACPI Driver * * Copyright (C) 2023 System76 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation.
*/
// Array of keyboard LED brightness levels staticconstenum led_brightness kb_levels[] = {
48,
72,
96,
144,
192,
255
};
// Array of keyboard LED colors in 24-bit RGB format staticconstint kb_colors[] = {
0xFFFFFF,
0x0000FF,
0xFF0000,
0xFF00FF,
0x00FF00,
0x00FFFF,
0xFFFF00
};
// Get a System76 ACPI device value by name staticint system76_get(struct system76_data *data, char *method)
{
acpi_handle handle;
acpi_status status; unsignedlonglong ret = 0;
handle = acpi_device_handle(data->acpi_dev);
status = acpi_evaluate_integer(handle, method, NULL, &ret); if (ACPI_SUCCESS(status)) return ret; return -ENODEV;
}
// Get a System76 ACPI device value by name with index staticint system76_get_index(struct system76_data *data, char *method, int index)
{ union acpi_object obj; struct acpi_object_list obj_list;
acpi_handle handle;
acpi_status status; unsignedlonglong ret = 0;
handle = acpi_device_handle(data->acpi_dev);
status = acpi_evaluate_integer(handle, method, &obj_list, &ret); if (ACPI_SUCCESS(status)) return ret; return -ENODEV;
}
// Get a System76 ACPI device object by name staticint system76_get_object(struct system76_data *data, char *method, union acpi_object **obj)
{
acpi_handle handle;
acpi_status status; struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
handle = acpi_device_handle(data->acpi_dev);
status = acpi_evaluate_object(handle, method, NULL, &buf); if (ACPI_SUCCESS(status)) {
*obj = buf.pointer; return 0;
}
return -ENODEV;
}
// Get a name from a System76 ACPI device object staticchar *system76_name(union acpi_object *obj, int index)
{ if (obj && obj->type == ACPI_TYPE_PACKAGE && index <= obj->package.count) { if (obj->package.elements[index].type == ACPI_TYPE_STRING) return obj->package.elements[index].string.pointer;
}
return NULL;
}
// Set a System76 ACPI device value by name staticint system76_set(struct system76_data *data, char *method, int value)
{ union acpi_object obj; struct acpi_object_list obj_list;
acpi_handle handle;
acpi_status status;
// Get the last set keyboard LED color static ssize_t kb_led_color_show( struct device *dev, struct device_attribute *dev_attr, char *buf)
{ struct led_classdev *led; struct system76_data *data;
led = dev_get_drvdata(dev);
data = container_of(led, struct system76_data, kb_led); return sysfs_emit(buf, "%06X\n", data->kb_color);
}
// Set the keyboard LED color static ssize_t kb_led_color_store( struct device *dev, struct device_attribute *dev_attr, constchar *buf,
size_t size)
{ struct led_classdev *led; struct system76_data *data; unsignedint val; int ret;
led = dev_get_drvdata(dev);
data = container_of(led, struct system76_data, kb_led);
ret = kstrtouint(buf, 16, &val); if (ret) return ret; if (val > 0xFFFFFF) return -EINVAL;
data->kb_color = (int)val;
system76_set(data, "SKBC", data->kb_color);
// Notify that the keyboard LED was changed by hardware staticvoid kb_led_notify(struct system76_data *data)
{
led_classdev_notify_brightness_hw_changed(
&data->kb_led,
data->kb_brightness
);
}
// Read keyboard LED brightness as set by hardware staticvoid kb_led_hotkey_hardware(struct system76_data *data)
{ int value;
if (acpi_has_method(acpi_device_handle(data->acpi_dev), "GKBK")) {
value = system76_get(data, "GKBB");
} else {
value = system76_get(data, "GKBL");
}
if (value < 0) return;
data->kb_brightness = value;
kb_led_notify(data);
}
// Toggle the keyboard LED staticvoid kb_led_hotkey_toggle(struct system76_data *data)
{ if (data->kb_brightness > 0) {
data->kb_toggle_brightness = data->kb_brightness;
kb_led_set(&data->kb_led, 0);
} else {
kb_led_set(&data->kb_led, data->kb_toggle_brightness);
}
kb_led_notify(data);
}
// Decrease the keyboard LED brightness staticvoid kb_led_hotkey_down(struct system76_data *data)
{ int i;
if (data->kb_brightness > 0) { for (i = ARRAY_SIZE(kb_levels); i > 0; i--) { if (kb_levels[i - 1] < data->kb_brightness) {
kb_led_set(&data->kb_led, kb_levels[i - 1]); break;
}
}
} else {
kb_led_set(&data->kb_led, data->kb_toggle_brightness);
}
kb_led_notify(data);
}
// Increase the keyboard LED brightness staticvoid kb_led_hotkey_up(struct system76_data *data)
{ int i;
if (data->kb_brightness > 0) { for (i = 0; i < ARRAY_SIZE(kb_levels); i++) { if (kb_levels[i] > data->kb_brightness) {
kb_led_set(&data->kb_led, kb_levels[i]); break;
}
}
} else {
kb_led_set(&data->kb_led, data->kb_toggle_brightness);
}
kb_led_notify(data);
}
// Cycle the keyboard LED color staticvoid kb_led_hotkey_color(struct system76_data *data)
{ int i;
if (data->kbled_type != KBLED_RGB) return;
if (data->kb_brightness > 0) { for (i = 0; i < ARRAY_SIZE(kb_colors); i++) { if (kb_colors[i] == data->kb_color) break;
}
i += 1; if (i >= ARRAY_SIZE(kb_colors))
i = 0;
data->kb_color = kb_colors[i];
system76_set(data, "SKBC", data->kb_color);
} else {
kb_led_set(&data->kb_led, data->kb_toggle_brightness);
}
kb_led_notify(data);
}
data = acpi_driver_data(acpi_dev); switch (event) { case 0x80:
kb_led_hotkey_hardware(data); break; case 0x81:
kb_led_hotkey_toggle(data); break; case 0x82:
kb_led_hotkey_down(data); break; case 0x83:
kb_led_hotkey_up(data); break; case 0x84:
kb_led_hotkey_color(data); break; case 0x85:
input_key(data, KEY_SCREENLOCK); break;
}
}
// Add a System76 ACPI device staticint system76_add(struct acpi_device *acpi_dev)
{ struct system76_data *data; int err;
data = devm_kzalloc(&acpi_dev->dev, sizeof(*data), GFP_KERNEL); if (!data) return -ENOMEM;
acpi_dev->driver_data = data;
data->acpi_dev = acpi_dev;
// Some models do not run open EC firmware. Check for an ACPI method // that only exists on open EC to guard functionality specific to it.
data->has_open_ec = acpi_has_method(acpi_device_handle(data->acpi_dev), "NFAN");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.