From patchwork Sun May 16 10:53:29 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440366 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-24.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 36D71C43462 for ; Sun, 16 May 2021 10:54:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 10B4D61185 for ; Sun, 16 May 2021 10:54:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231338AbhEPKzP (ORCPT ); Sun, 16 May 2021 06:55:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:47806 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230103AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id CFF1961186; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=AuVERok4KX/jUZLx1XW8gvHPzx66bBgJiH+lfN+zUjg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=o+qnwtEIjAN3CQZ0zNfGDlATQbKB7j/tblhszC4zS6OafNz2ZgkgOG7xALdptk6N7 iNpJHxuL6bhwUBds6+CFwqhKvIlMcuq2xZ8Y7PWPXpoSBPAVWVQcn5f7oP8EKxYOv0 UDkCdFZF/Nnq2JWsVHNPrQaElCwoISYEq5kbJYo5I1+djuFQDtE0ERhEKxBMpAi7p7 gSfmbztMgTVtgr5vhxlTVe11erO5yqo0LYZmgg+j4PwiZc+MNvj8tEB3mmEoIeQV/f 8Emrb+QXHkn++VAA+nbqsULfQyHTTyOdY3kLuHHaa986SuaVCVsuTjZbX+Ltmf94z/ fl8s5P+GPDOOw== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s80-LI; Sun, 16 May 2021 12:53:50 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 01/17] staging: add support for NUC WMI LEDs Date: Sun, 16 May 2021 12:53:29 +0200 Message-Id: <7cec257fcc6e5789e5620495674e442a727a766f.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Some Intel Next Unit of Computing (NUC) machines have software-configured LEDs that can be used to display a variety of events: - Power State - HDD Activity - Ethernet - WiFi - Power Limit They can even be controlled directly via software, without any hardware-specific indicator connected into them. Some devices have mono-colored LEDs, but the more advanced ones have RGB leds that can show any color. Different color and 4 blink states can be programmed for thee system states: - powered on (S0); - S3; - Standby. The NUC BIOSes allow to partially set them for S0, but doesn't provide any control for the other states, nor does allow changing the blinking logic. They all use a WMI interface using GUID: 8C5DA44C-CDC3-46b3-8619-4E26D34390B7 But there are 3 different revisions of the spec, all using the same GUID, but two different APIs: - the original one, for NUC6 and to NUCi7: - https://www.intel.com/content/www/us/en/support/articles/000023426/intel-nuc/intel-nuc-kits.html - a new one, starting with NUCi8, with two revisions: - https://raw.githubusercontent.com/nomego/intel_nuc_led/master/specs/INTEL_WMI_LED_0.64.pdf - https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI-Spec-Intel-NUC-NUC10ixFNx.pdf There are some OOT drivers for them, but they use procfs and use a messy interface to setup it. Also, there are different drivers with the same name, each with support for each NUC family. Let's start a new driver from scratch, using the x86 platform WMI core and the LED class. This initial version is compatible with NUCi8 and above, and it was tested with a Hades Canyon NUC (NUC8i7HNK). Signed-off-by: Mauro Carvalho Chehab --- MAINTAINERS | 6 + drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/nuc-led/Kconfig | 11 + drivers/staging/nuc-led/Makefile | 3 + drivers/staging/nuc-led/TODO | 6 + drivers/staging/nuc-led/nuc-wmi.c | 489 ++++++++++++++++++++++++++++++ 7 files changed, 518 insertions(+) create mode 100644 drivers/staging/nuc-led/Kconfig create mode 100644 drivers/staging/nuc-led/Makefile create mode 100644 drivers/staging/nuc-led/TODO create mode 100644 drivers/staging/nuc-led/nuc-wmi.c diff --git a/MAINTAINERS b/MAINTAINERS index bd7aff0c120f..50d181e1d745 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13063,6 +13063,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/aia21/ntfs.git F: Documentation/filesystems/ntfs.rst F: fs/ntfs/ +NUC LED DRIVER +M: Mauro Carvalho Chehab +L: devel@driverdev.osuosl.org +S: Maintained +F: drivers/staging/nuc-led + NUBUS SUBSYSTEM M: Finn Thain L: linux-m68k@lists.linux-m68k.org diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index b7ae5bdc4eb5..d1a8e3e08d00 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -84,6 +84,8 @@ source "drivers/staging/greybus/Kconfig" source "drivers/staging/vc04_services/Kconfig" +source "drivers/staging/nuc-led/Kconfig" + source "drivers/staging/pi433/Kconfig" source "drivers/staging/mt7621-pci/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 075c979bfe7c..de937f947edb 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_UNISYSSPAR) += unisys/ obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/ obj-$(CONFIG_FB_TFT) += fbtft/ obj-$(CONFIG_MOST) += most/ +obj-$(CONFIG_LEDS_NUC_WMI) += nuc-led/ obj-$(CONFIG_KS7010) += ks7010/ obj-$(CONFIG_GREYBUS) += greybus/ obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/ diff --git a/drivers/staging/nuc-led/Kconfig b/drivers/staging/nuc-led/Kconfig new file mode 100644 index 000000000000..0f870f45bf44 --- /dev/null +++ b/drivers/staging/nuc-led/Kconfig @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0 + +config LEDS_NUC_WMI + tristate "Intel NUC WMI support for LEDs" + depends on LEDS_CLASS + depends on ACPI_WMI + help + Enable this to support the Intel NUC WMI support for + LEDs, starting from NUCi8 and upper devices. + + To compile this driver as a module, choose M here. diff --git a/drivers/staging/nuc-led/Makefile b/drivers/staging/nuc-led/Makefile new file mode 100644 index 000000000000..abba9e305fa1 --- /dev/null +++ b/drivers/staging/nuc-led/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_LEDS_NUC_WMI) += nuc-wmi.o diff --git a/drivers/staging/nuc-led/TODO b/drivers/staging/nuc-led/TODO new file mode 100644 index 000000000000..d5296d7186a7 --- /dev/null +++ b/drivers/staging/nuc-led/TODO @@ -0,0 +1,6 @@ +- Add support for 6th gen NUCs, like Skull Canyon +- Improve LED core support to avoid it to try to manage the + LED brightness directly; +- Test it with 8th gen NUCs; +- Add more functionality to the driver; +- Stabilize and document its sysfs interface. diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c new file mode 100644 index 000000000000..15d956ad8556 --- /dev/null +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -0,0 +1,489 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Intel NUC WMI Control WMI Driver + * + * Currently, it implements only the LED support + * + * Copyright(c) 2021 Mauro Carvalho Chehab + * + * Inspired on WMI from https://github.com/nomego/intel_nuc_led + * + * It follows this spec: + * https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI-Spec-Intel-NUC-NUC10ixFNx.pdf + */ + +#include +#include +#include +#include +#include +#include +#include + +#define NUC_LED_WMI_GUID "8C5DA44C-CDC3-46B3-8619-4E26D34390B7" + +#define MAX_LEDS 7 +#define NUM_INPUT_ARGS 4 +#define NUM_OUTPUT_ARGS 3 + +enum led_cmds { + LED_QUERY = 0x03, + LED_NEW_GET_STATUS = 0x04, + LED_SET_INDICATOR = 0x05, + LED_SET_VALUE = 0x06, + LED_NOTIFICATION = 0x07, + LED_SWITCH_TYPE = 0x08, +}; + +enum led_query_subcmd { + LED_QUERY_LIST_ALL = 0x00, + LED_QUERY_COLOR_TYPE = 0x01, + LED_QUERY_INDICATOR_OPTIONS = 0x02, + LED_QUERY_CONTROL_ITEMS = 0x03, +}; + +enum led_new_get_subcmd { + LED_NEW_GET_CURRENT_INDICATOR = 0x00, + LED_NEW_GET_CONTROL_ITEM = 0x01, +}; + +/* LED color indicator */ +#define LED_BLUE_AMBER BIT(0) +#define LED_BLUE_WHITE BIT(1) +#define LED_RGB BIT(2) +#define LED_SINGLE_COLOR BIT(3) + +/* LED indicator options */ +#define LED_IND_POWER_STATE BIT(0) +#define LED_IND_HDD_ACTIVITY BIT(1) +#define LED_IND_ETHERNET BIT(2) +#define LED_IND_WIFI BIT(3) +#define LED_IND_SOFTWARE BIT(4) +#define LED_IND_POWER_LIMIT BIT(5) +#define LED_IND_DISABLE BIT(6) + +static const char * const led_names[] = { + "nuc::power", + "nuc::hdd", + "nuc::skull", + "nuc::eyes", + "nuc::front1", + "nuc::front2", + "nuc::front3", +}; + +struct nuc_nmi_led { + struct led_classdev cdev; + struct device *dev; + u8 id; + u8 indicator; + u32 color_type; + u32 avail_indicators; + u32 control_items; +}; + +struct nuc_wmi { + struct nuc_nmi_led led[MAX_LEDS * 3]; /* Worse case: RGB LEDs */ + int num_leds; + + /* Avoid concurrent access to WMI */ + struct mutex wmi_lock; +}; + +static int nuc_nmi_led_error(u8 error_code) +{ + switch (error_code) { + case 0: + return 0; + case 0xe1: /* Function not support */ + return -ENOENT; + case 0xe2: /* Undefined device */ + return -ENODEV; + case 0xe3: /* EC no respond */ + return -EIO; + case 0xe4: /* Invalid Parameter */ + return -EINVAL; + case 0xef: /* Unexpected error */ + return -EFAULT; + + /* Revision 1.0 Errors */ + case 0xe5: /* Node busy */ + return -EBUSY; + case 0xe6: /* Destination device is disabled or unavailable */ + return -EACCES; + case 0xe7: /* Invalid CEC Opcode */ + return -ENOENT; + case 0xe8: /* Data Buffer size is not enough */ + return -ENOSPC; + + default: /* Reserved */ + return -EPROTO; + } +} + +static int nuc_nmi_cmd(struct device *dev, + u8 cmd, + u8 input_args[NUM_INPUT_ARGS], + u8 output_args[NUM_OUTPUT_ARGS]) +{ + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + struct nuc_wmi *priv = dev_get_drvdata(dev); + struct acpi_buffer input; + union acpi_object *obj; + acpi_status status; + int size, ret; + u8 *p; + + input.length = NUM_INPUT_ARGS; + input.pointer = input_args; + + mutex_lock(&priv->wmi_lock); + status = wmi_evaluate_method(NUC_LED_WMI_GUID, 0, cmd, + &input, &output); + mutex_unlock(&priv->wmi_lock); + if (ACPI_FAILURE(status)) { + dev_warn(dev, "cmd %02x (%*ph): ACPI failure: %d\n", + cmd, (int)input.length, input_args, ret); + return status; + } + + obj = output.pointer; + if (!obj) { + dev_warn(dev, "cmd %02x (%*ph): no output\n", + cmd, (int)input.length, input_args); + return -EINVAL; + } + + if (obj->type == ACPI_TYPE_BUFFER) { + if (obj->buffer.length < NUM_OUTPUT_ARGS + 1) { + ret = -EINVAL; + goto err; + } + p = (u8 *)obj->buffer.pointer; + } else if (obj->type == ACPI_TYPE_INTEGER) { + p = (u8 *)&obj->integer.value; + } else { + return -EINVAL; + } + + ret = nuc_nmi_led_error(p[0]); + if (ret) { + dev_warn(dev, "cmd %02x (%*ph): WMI error code: %02x\n", + cmd, (int)input.length, input_args, p[0]); + goto err; + } + + size = NUM_OUTPUT_ARGS + 1; + + if (output_args) { + memcpy(output_args, p + 1, NUM_OUTPUT_ARGS); + + dev_info(dev, "cmd %02x (%*ph), return: %*ph\n", + cmd, (int)input.length, input_args, NUM_OUTPUT_ARGS, output_args); + } else { + dev_info(dev, "cmd %02x (%*ph)\n", + cmd, (int)input.length, input_args); + } + +err: + kfree(obj); + return ret; +} + +static int nuc_wmi_query_leds(struct device *dev) +{ + struct nuc_wmi *priv = dev_get_drvdata(dev); + u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int i, id, ret; + u8 leds; + + /* + * List all LED types support in the platform + * + * Should work with both NUC8iXXX and NUC10iXXX + * + * FIXME: Should add a fallback code for it to work with older NUCs, + * as LED_QUERY returns an error on older devices like Skull Canyon. + */ + cmd = LED_QUERY; + input[0] = LED_QUERY_LIST_ALL; + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d while listing all LEDs\n", ret); + return ret; + } + + leds = output[0]; + if (!leds) { + dev_warn(dev, "No LEDs found\n"); + return -ENODEV; + } + + for (id = 0; id < MAX_LEDS; id++) { + struct nuc_nmi_led *led = &priv->led[priv->num_leds]; + + if (!(leds & BIT(id))) + continue; + + led->id = id; + + cmd = LED_QUERY; + input[0] = LED_QUERY_COLOR_TYPE; + input[1] = id; + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->color_type = output[0] | + output[1] << 8 | + output[2] << 16; + + cmd = LED_NEW_GET_STATUS; + input[0] = LED_NEW_GET_CURRENT_INDICATOR; + input[1] = i; + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->indicator = output[0]; + + cmd = LED_QUERY; + input[0] = LED_QUERY_INDICATOR_OPTIONS; + input[1] = i; + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->avail_indicators = output[0] | + output[1] << 8 | + output[2] << 16; + + cmd = LED_QUERY; + input[0] = LED_QUERY_CONTROL_ITEMS; + input[1] = i; + input[2] = led->indicator; + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "error %d on led %i\n", ret, i); + return ret; + } + + led->control_items = output[0] | + output[1] << 8 | + output[2] << 16; + + dev_dbg(dev, "%s: id: %02x, color type: %06x, indicator: %06x, control items: %06x\n", + led_names[led->id], led->id, + led->color_type, led->indicator, led->control_items); + + priv->num_leds++; + } + + return 0; +} + +/* + * LED show/store routines + */ + +#define LED_ATTR_RW(_name) \ + DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) + +static const char * const led_indicators[] = { + "Power State", + "HDD Activity", + "Ethernet", + "WiFi", + "Software", + "Power Limit", + "Disable" +}; + +static ssize_t show_indicator(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + int size = PAGE_SIZE; + char *p = buf; + int i, n; + + for (i = 0; i < fls(led->avail_indicators); i++) { + if (!(led->avail_indicators & BIT(i))) + continue; + if (i == led->indicator) + n = scnprintf(p, size, "[%s] ", led_indicators[i]); + else + n = scnprintf(p, size, "%s ", led_indicators[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t store_indicator(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; + const char *tmp; + int ret, i; + + tmp = strsep((char **)&buf, "\n"); + + for (i = 0; i < fls(led->avail_indicators); i++) { + if (!(led->avail_indicators & BIT(i))) + continue; + + if (!strcasecmp(tmp, led_indicators[i])) { + cmd = LED_SET_INDICATOR; + input[0] = led->id; + input[1] = i; + + dev_dbg(dev, "set led %s indicator to %s\n", + cdev->name, led_indicators[i]); + + ret = nuc_nmi_cmd(dev, cmd, input, NULL); + if (ret) + return ret; + + led->indicator = i; + + return len; + } + } + + return -EINVAL; +} + +static LED_ATTR_RW(indicator); + +/* + * Attributes for multicolor LEDs + */ + +static struct attribute *nuc_wmi_multicolor_led_attr[] = { + &dev_attr_indicator.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_attribute_group = { + .attrs = nuc_wmi_multicolor_led_attr, +}; + +static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { + &nuc_wmi_led_attribute_group, + NULL +}; + +static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *led) +{ + led->cdev.name = led_names[led->id]; + + led->dev = dev; + led->cdev.groups = nuc_wmi_led_attribute_groups; + + /* + * It can't let the classdev to manage the brightness due to several + * reasons: + * + * 1) classdev has some internal logic to manage the brightness, + * at set_brightness_delayed(), which starts disabling the LEDs; + * While this makes sense on most cases, here, it would appear + * that the NUC was powered off, which is not what happens; + * 2) classdev unconditionally tries to set brightness for all + * leds, including the ones that were software-disabled or + * disabled disabled via BIOS menu; + * 3) There are 3 types of brightness values for each LED, depending + * on the CPU power state: S0, S3 and S5. + * + * So, the best seems to export everything via sysfs attributes + * directly. This would require some further changes at the + * LED class, though, or we would need to create our own LED + * class, which seems wrong. + */ + + return devm_led_classdev_register(dev, &led->cdev); +} + +static int nuc_wmi_leds_setup(struct device *dev) +{ + struct nuc_wmi *priv = dev_get_drvdata(dev); + int ret, i; + + ret = nuc_wmi_query_leds(dev); + if (ret) + return ret; + + for (i = 0; i < priv->num_leds; i++) { + ret = nuc_wmi_led_register(dev, &priv->led[i]); + if (ret) { + dev_err(dev, "Failed to register led %d: %s\n", + i, led_names[priv->led[i].id]); + while (--i >= 0) + devm_led_classdev_unregister(dev, &priv->led[i].cdev); + + return ret; + } + } + return 0; +} + +static int nuc_wmi_probe(struct wmi_device *wdev, const void *context) +{ + struct device *dev = &wdev->dev; + struct nuc_wmi *priv; + int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + mutex_init(&priv->wmi_lock); + + dev_set_drvdata(dev, priv); + + ret = nuc_wmi_leds_setup(dev); + if (ret) + return ret; + + dev_info(dev, "NUC WMI driver initialized.\n"); + return 0; +} + +static void nuc_wmi_remove(struct wmi_device *wdev) +{ + struct device *dev = &wdev->dev; + + dev_info(dev, "NUC WMI driver removed.\n"); +} + +static const struct wmi_device_id nuc_wmi_descriptor_id_table[] = { + { .guid_string = NUC_LED_WMI_GUID }, + { }, +}; + +static struct wmi_driver nuc_wmi_driver = { + .driver = { + .name = "nuc-wmi", + }, + .probe = nuc_wmi_probe, + .remove = nuc_wmi_remove, + .id_table = nuc_wmi_descriptor_id_table, +}; + +module_wmi_driver(nuc_wmi_driver); + +MODULE_DEVICE_TABLE(wmi, nuc_wmi_descriptor_id_table); +MODULE_AUTHOR("Mauro Carvalho Chehab "); +MODULE_DESCRIPTION("Intel NUC WMI driver"); +MODULE_LICENSE("GPL"); From patchwork Sun May 16 10:53:30 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439991 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E7BFAC433B4 for ; Sun, 16 May 2021 10:53:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id BB1F0613C1 for ; Sun, 16 May 2021 10:53:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230050AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: from mail.kernel.org ([198.145.29.99]:47668 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229454AbhEPKzH (ORCPT ); Sun, 16 May 2021 06:55:07 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id D41B361185; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=bQ3MnldJSx8+sco79kPklGNg7LH+HvdUVOXzNu/8s/I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=q28opKS/7NRZM/NCZVZkBIcKBjPAMhx4qof2EOdhzzDcPx+zuGFs0QPXdMIu0MNNV WHLbPQOvsLGkCXVbWA2S6PysQLbHS4wcRmL6oaAbm0ox4B/hWyh4EqatcKGHwCc3lu NO5TmD4+HZJRfj/KH9hdvVsoiWBn0iPf82LowooqYBhipK5L9j4hFCcHazngjdAIHK ApCvE9DDOiKBDTyO1JX3ug3YKw4O0DOz4eATPUjxEjrfNos1vXUULUQfZvxDtyQoqv OeaUOS6jVgnaf0PHwjYZfq8wNqspfzaslZjcyjA9QXmmSStEh7o1GnrT94GAV5qJZC CWnFmJI7GUUbg== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s84-NE; Sun, 16 May 2021 12:53:50 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 02/17] staging: nuc-wmi: detect WMI API detection Date: Sun, 16 May 2021 12:53:30 +0200 Message-Id: <602bd7c90e1e569f52db10bbe451af0436300b78.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org There are currently 3 known API releases: - https://www.intel.com/content/www/us/en/support/articles/000023426/intel-nuc/intel-nuc-kits.html - https://raw.githubusercontent.com/nomego/intel_nuc_led/master/specs/INTEL_WMI_LED_0.64.pdf - https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI-Spec-Intel-NUC-NUC10ixFNx.pdf Add a logic to detect between them, preventing the driver to work with an unsupported version. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 15d956ad8556..b75ddd47e443 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -26,6 +26,13 @@ #define NUM_INPUT_ARGS 4 #define NUM_OUTPUT_ARGS 3 +enum led_api_rev { + LED_API_UNKNOWN, + LED_API_NUC6, + LED_API_REV_0_64, + LED_API_REV_1_0, +}; + enum led_cmds { LED_QUERY = 0x03, LED_NEW_GET_STATUS = 0x04, @@ -33,6 +40,7 @@ enum led_cmds { LED_SET_VALUE = 0x06, LED_NOTIFICATION = 0x07, LED_SWITCH_TYPE = 0x08, + LED_VERSION_CONTROL = 0x09, }; enum led_query_subcmd { @@ -195,7 +203,7 @@ static int nuc_wmi_query_leds(struct device *dev) struct nuc_wmi *priv = dev_get_drvdata(dev); u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; u8 output[NUM_OUTPUT_ARGS]; - int i, id, ret; + int i, id, ret, ver = LED_API_UNKNOWN; u8 leds; /* @@ -209,12 +217,28 @@ static int nuc_wmi_query_leds(struct device *dev) cmd = LED_QUERY; input[0] = LED_QUERY_LIST_ALL; ret = nuc_nmi_cmd(dev, cmd, input, output); - if (ret) { + if (ret == -ENOENT) { + ver = LED_API_NUC6; + } else if (ret) { dev_warn(dev, "error %d while listing all LEDs\n", ret); return ret; + } else { + leds = output[0]; } - leds = output[0]; + if (ver != LED_API_NUC6) { + ret = nuc_nmi_cmd(dev, LED_VERSION_CONTROL, input, output); + ver = output[0] | output[1] << 16; + if (!ver) + ver = LED_API_REV_0_64; + else if (ver == 0x0126) + ver = LED_API_REV_1_0; + } + + /* Currently, only API Revision 0.64 is supported */ + if (ver != LED_API_REV_0_64) + return -ENODEV; + if (!leds) { dev_warn(dev, "No LEDs found\n"); return -ENODEV; From patchwork Sun May 16 10:53:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440373 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E6325C433ED for ; Sun, 16 May 2021 10:53:55 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id AC9A8611BF for ; Sun, 16 May 2021 10:53:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229704AbhEPKzH (ORCPT ); Sun, 16 May 2021 06:55:07 -0400 Received: from mail.kernel.org ([198.145.29.99]:47652 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229437AbhEPKzH (ORCPT ); Sun, 16 May 2021 06:55:07 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C115361182; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162432; bh=I1yV79WAicyardZtVgX3QIlFbOt2vtB/eAA+wO6deO0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IdkCWul9+GnWF754+OyB6u/hDlB9cqf4dv5gzVXxd5DQzZnr3fgT15bhj2+QT9fHQ fTlU5ui4CbCR7EcPeUd+mVL03x5GvSt7CcIeL1llne5A6IPAdxJQ/HUBThXqeVY07X 4JLT52GMubpN283bD7Ja9xjQUPaAExcICL+tTtciY1gqtko3LQX4KdlmxtgouH1Hq9 35+dOjRATVie3rlG0xB762A35PlllzfHtzqf+OEYI3N12imz4EjKv8lCpAW23Qcd9r P49eDGNiMU7bMvsGrEqHQn+/4WmcqmcuExUZEtsWxjxn2yV/6GRqNb5gQ3/muDsXs9 0Q5VbBD4sXsEQ== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s88-Ow; Sun, 16 May 2021 12:53:50 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 03/17] staging: nuc-wmi: add support for changing S0 brightness Date: Sun, 16 May 2021 12:53:31 +0200 Message-Id: <682adcb43cc67c95473a2706b54c023c70799942.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Now that the core logic is in place, let's add support to adjust the S0 brightness level. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 79 +++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index b75ddd47e443..62c2764814dd 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -392,7 +392,85 @@ static ssize_t store_indicator(struct device *dev, return -EINVAL; } +/* Get S0 brightness */ +static ssize_t show_s0_brightness(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ret; + + cmd = LED_NEW_GET_STATUS; + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = 0; + + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) + return ret; + + /* Multicolor uses a scale from 0 to 100 */ + if (led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB)) + return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0]); + + /* single color uses 0, 50% and 100% */ + return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0] * 50); +} + +/* Change S0 brightness */ +static ssize_t store_s0_brightness(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; + int ret; + u8 val; + + if (led->indicator == LED_IND_DISABLE) { + dev_dbg(dev, "Led %s is disabled. ignoring it.\n", cdev->name); + return -EACCES; + } + + if (kstrtou8(buf, 0, &val) || val > 100) + return -EINVAL; + + /* + * For single-color LEDs, the value should be between 0 to 2, but, + * in order to have a consistent API, let's always handle it as if + * it is a percentage, for both multicolor and single color LEDs. + * So: + * value == 0 will disable the LED + * value up to 74% will set it the brightness to 50% + * value equal or above 75% will use the maximum brightness. + */ + if (!(led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB))) { + if (val > 0 && val < 75) + val = 1; + if (val >= 75) + val = 2; + } + + cmd = LED_SET_VALUE; + input[0] = led->id; + input[1] = led->indicator; + input[2] = 0; /* FIXME: replace by an enum */ + input[3] = val; + + ret = nuc_nmi_cmd(dev, cmd, input, NULL); + if (ret) + return ret; + + return len; +} + static LED_ATTR_RW(indicator); +static LED_ATTR_RW(s0_brightness); /* * Attributes for multicolor LEDs @@ -400,6 +478,7 @@ static LED_ATTR_RW(indicator); static struct attribute *nuc_wmi_multicolor_led_attr[] = { &dev_attr_indicator.attr, + &dev_attr_s0_brightness.attr, NULL, }; From patchwork Sun May 16 10:53:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439987 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C5A2AC43611 for ; Sun, 16 May 2021 10:53:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A21D761183 for ; Sun, 16 May 2021 10:53:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230453AbhEPKzM (ORCPT ); Sun, 16 May 2021 06:55:12 -0400 Received: from mail.kernel.org ([198.145.29.99]:47714 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229541AbhEPKzH (ORCPT ); Sun, 16 May 2021 06:55:07 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id BE18A61166; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=YP1YAY7I8I6NWkfNmQO/5LZ0R2YCNPseIPrt3I7n3BI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=n2PeIr3gvyxTJwX9s/pPzzm1GxAO7c39uDSrmIYnhmnoKBiHN8KWtX5tndE9V/ilL X4JxS9L0K4vtiOgQajbo0QEG+Qe6GxNUss5hILTIQ3sS5PP8IQl78aEJVeDxuKu8z7 9SsOh6QUWSpzZOqe6mXT5ZZ2qcYUCtEYq7y71MINr7zvuNaEZxqeKqcwXqyWNlRuzv FpoMKGznBXy5uIDQaCc9FowgrP3sMNjoTc0opucFwW4/tqtmZIIMymMwiO9Ah4JiKc UG7KYj0mZZQoTFpWKjvSMY30eJGv4J826IIXomdkOHtv4zjXZpHAIJiM297DMfIDOm HcwYhP5G0PL0A== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s8C-Q7; Sun, 16 May 2021 12:53:50 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 04/17] staging: nuc-wmi: add all types of brightness Date: Sun, 16 May 2021 12:53:32 +0200 Message-Id: <1eca814da18f7261286dc2c08a009bf42ad1e31a.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Improve the logic in order to support not only S0 brightness, but also the brightness for other indicators and for all power states. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 369 ++++++++++++++++++++---------- 1 file changed, 249 insertions(+), 120 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 62c2764814dd..711897ba4666 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -55,21 +55,89 @@ enum led_new_get_subcmd { LED_NEW_GET_CONTROL_ITEM = 0x01, }; +enum led_function { + LED_FUNC_BRIGHTNESS, + LED_FUNC_COLOR1, + LED_FUNC_COLOR_GREEN, + LED_FUNC_COLOR_BLUE, + + LED_FUNC_BLINK_BEHAVIOR, + LED_FUNC_BLINK_FREQ, + + LED_FUNC_HDD_BEHAVIOR, + LED_FUNC_ETH_TYPE, + LED_FUNC_POWER_LIMIT_SCHEME, + + MAX_LED_FUNC +}; + +enum led_indicators { + LED_IND_POWER_STATE, + LED_IND_HDD_ACTIVITY, + LED_IND_ETHERNET, + LED_IND_WIFI, + LED_IND_SOFTWARE, + LED_IND_POWER_LIMIT, + LED_IND_DISABLE, + + MAX_IND = LED_IND_DISABLE +}; + +/* + * control items ID for each of the valid indicators on spec Rev 0.64. + */ +static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUNC] = { + [LED_IND_POWER_STATE] = { /* Offsets for each power state */ + [LED_FUNC_BRIGHTNESS] = 0x00, + [LED_FUNC_BLINK_BEHAVIOR] = 0x01, + [LED_FUNC_BLINK_FREQ] = 0x02, + [LED_FUNC_COLOR1] = 0x03, + [LED_FUNC_COLOR_GREEN] = 0x04, + [LED_FUNC_COLOR_BLUE] = 0x05 + }, + [LED_IND_HDD_ACTIVITY] = { + [LED_FUNC_BRIGHTNESS] = 0x00, + [LED_FUNC_COLOR1] = 0x01, + [LED_FUNC_COLOR_GREEN] = 0x02, + [LED_FUNC_COLOR_BLUE] = 0x03, + [LED_FUNC_HDD_BEHAVIOR] = 0x04 + }, + [LED_IND_ETHERNET] = { + [LED_FUNC_ETH_TYPE] = 0x00, + [LED_FUNC_BRIGHTNESS] = 0x01, + [LED_FUNC_COLOR1] = 0x02, + [LED_FUNC_COLOR_GREEN] = 0x03, + [LED_FUNC_COLOR_BLUE] = 0x04 + }, + [LED_IND_WIFI] = { + [LED_FUNC_BRIGHTNESS] = 0x00, + [LED_FUNC_COLOR1] = 0x01, + [LED_FUNC_COLOR_GREEN] = 0x02, + [LED_FUNC_COLOR_BLUE] = 0x03 + }, + [LED_IND_SOFTWARE] = { + [LED_FUNC_BRIGHTNESS] = 0x00, + [LED_FUNC_BLINK_BEHAVIOR] = 0x01, + [LED_FUNC_BLINK_FREQ] = 0x02, + [LED_FUNC_COLOR1] = 0x03, + [LED_FUNC_COLOR_GREEN] = 0x04, + [LED_FUNC_COLOR_BLUE] = 0x05 + }, + [LED_IND_POWER_LIMIT] = { + [LED_FUNC_POWER_LIMIT_SCHEME] = 0x00, + [LED_FUNC_BRIGHTNESS] = 0x01, + [LED_FUNC_COLOR1] = 0x02, + [LED_FUNC_COLOR_GREEN] = 0x03, + [LED_FUNC_COLOR_BLUE] = 0x04 + }, +}; + /* LED color indicator */ #define LED_BLUE_AMBER BIT(0) #define LED_BLUE_WHITE BIT(1) #define LED_RGB BIT(2) #define LED_SINGLE_COLOR BIT(3) -/* LED indicator options */ -#define LED_IND_POWER_STATE BIT(0) -#define LED_IND_HDD_ACTIVITY BIT(1) -#define LED_IND_ETHERNET BIT(2) -#define LED_IND_WIFI BIT(3) -#define LED_IND_SOFTWARE BIT(4) -#define LED_IND_POWER_LIMIT BIT(5) -#define LED_IND_DISABLE BIT(6) - static const char * const led_names[] = { "nuc::power", "nuc::hdd", @@ -87,7 +155,6 @@ struct nuc_nmi_led { u8 indicator; u32 color_type; u32 avail_indicators; - u32 control_items; }; struct nuc_wmi { @@ -201,9 +268,9 @@ static int nuc_nmi_cmd(struct device *dev, static int nuc_wmi_query_leds(struct device *dev) { struct nuc_wmi *priv = dev_get_drvdata(dev); - u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; + u8 input[NUM_INPUT_ARGS] = { 0 }; u8 output[NUM_OUTPUT_ARGS]; - int i, id, ret, ver = LED_API_UNKNOWN; + int id, ret, ver = LED_API_UNKNOWN; u8 leds; /* @@ -214,9 +281,8 @@ static int nuc_wmi_query_leds(struct device *dev) * FIXME: Should add a fallback code for it to work with older NUCs, * as LED_QUERY returns an error on older devices like Skull Canyon. */ - cmd = LED_QUERY; input[0] = LED_QUERY_LIST_ALL; - ret = nuc_nmi_cmd(dev, cmd, input, output); + ret = nuc_nmi_cmd(dev, LED_QUERY, input, output); if (ret == -ENOENT) { ver = LED_API_NUC6; } else if (ret) { @@ -252,12 +318,11 @@ static int nuc_wmi_query_leds(struct device *dev) led->id = id; - cmd = LED_QUERY; input[0] = LED_QUERY_COLOR_TYPE; input[1] = id; - ret = nuc_nmi_cmd(dev, cmd, input, output); + ret = nuc_nmi_cmd(dev, LED_QUERY, input, output); if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); + dev_warn(dev, "error %d on led %i\n", ret, id); return ret; } @@ -265,23 +330,11 @@ static int nuc_wmi_query_leds(struct device *dev) output[1] << 8 | output[2] << 16; - cmd = LED_NEW_GET_STATUS; - input[0] = LED_NEW_GET_CURRENT_INDICATOR; - input[1] = i; - ret = nuc_nmi_cmd(dev, cmd, input, output); - if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); - return ret; - } - - led->indicator = output[0]; - - cmd = LED_QUERY; input[0] = LED_QUERY_INDICATOR_OPTIONS; - input[1] = i; - ret = nuc_nmi_cmd(dev, cmd, input, output); + input[1] = id; + ret = nuc_nmi_cmd(dev, LED_QUERY, input, output); if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); + dev_warn(dev, "error %d on led %i\n", ret, id); return ret; } @@ -289,23 +342,18 @@ static int nuc_wmi_query_leds(struct device *dev) output[1] << 8 | output[2] << 16; - cmd = LED_QUERY; - input[0] = LED_QUERY_CONTROL_ITEMS; - input[1] = i; - input[2] = led->indicator; - ret = nuc_nmi_cmd(dev, cmd, input, output); + input[0] = LED_NEW_GET_CURRENT_INDICATOR; + input[1] = id; + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); if (ret) { - dev_warn(dev, "error %d on led %i\n", ret, i); + dev_warn(dev, "error %d on led %i\n", ret, id); return ret; } + led->indicator = output[0]; - led->control_items = output[0] | - output[1] << 8 | - output[2] << 16; - - dev_dbg(dev, "%s: id: %02x, color type: %06x, indicator: %06x, control items: %06x\n", - led_names[led->id], led->id, - led->color_type, led->indicator, led->control_items); + dev_dbg(dev, "%s: id: %02x, color type: %06x, indicator: %02x (avail %06x)\n", + led_names[led->id], led->id, led->color_type, + led->indicator, led->avail_indicators); priv->num_leds++; } @@ -313,6 +361,82 @@ static int nuc_wmi_query_leds(struct device *dev) return 0; } +static bool nuc_wmi_test_control(struct device *dev, + struct nuc_nmi_led *led, u8 ctrl) +{ + int ret, avail_ctrls; + u8 output[NUM_OUTPUT_ARGS]; + u8 input[NUM_INPUT_ARGS] = { + LED_QUERY_CONTROL_ITEMS, + led->id, + led->indicator + }; + + ret = nuc_nmi_cmd(dev, LED_QUERY, input, output); + if (ret) + return false; + + avail_ctrls = output[0] | + output[1] << 8 | + output[2] << 16; + + return avail_ctrls & BIT(ctrl); +} + +static int nuc_wmi_get_brightness_offset(struct device *dev, + struct nuc_nmi_led *led, u8 offset) +{ + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = ctrl; + + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + dev_dbg(dev, "%s: id: %02x, brightness: %02x\n", + led_names[led->id], led->id, output[0]); + + return output[0]; +} + +static ssize_t nuc_wmi_set_brightness_offset(struct device *dev, + struct nuc_nmi_led *led, + u8 offset, + u8 val) +{ + u8 input[NUM_INPUT_ARGS]; + int ctrl; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = val; + + return nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); +} + /* * LED show/store routines */ @@ -320,6 +444,21 @@ static int nuc_wmi_query_leds(struct device *dev) #define LED_ATTR_RW(_name) \ DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) +#define LED_ATTR_POWER_STATE_RW(_name, offset) \ + static ssize_t show_##_name(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ + { \ + return show_brightness_offset(dev, attr, offset, buf); \ + } \ + static ssize_t store_##_name(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t len) \ + { \ + return store_brightness_offset(dev, attr, offset, buf, len); \ + } \ + static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) + static const char * const led_indicators[] = { "Power State", "HDD Activity", @@ -392,98 +531,93 @@ static ssize_t store_indicator(struct device *dev, return -EINVAL; } -/* Get S0 brightness */ -static ssize_t show_s0_brightness(struct device *dev, - struct device_attribute *attr, - char *buf) +/* Get brightness */ +static ssize_t show_brightness_offset(struct device *dev, + struct device_attribute *attr, + u8 offset, + char *buf) { struct led_classdev *cdev = dev_get_drvdata(dev); struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); - u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; - u8 output[NUM_OUTPUT_ARGS]; int ret; - cmd = LED_NEW_GET_STATUS; - input[0] = LED_NEW_GET_CONTROL_ITEM; - input[1] = led->id; - input[2] = led->indicator; - input[3] = 0; + if (led->indicator != LED_IND_POWER_STATE) + return -ENODEV; - ret = nuc_nmi_cmd(dev, cmd, input, output); - if (ret) + ret = nuc_wmi_get_brightness_offset(dev, led, offset); + if (ret < 0) return ret; - /* Multicolor uses a scale from 0 to 100 */ - if (led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB)) - return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0]); - - /* single color uses 0, 50% and 100% */ - return scnprintf(buf, PAGE_SIZE, "%d%%\n", output[0] * 50); + return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } -/* Change S0 brightness */ -static ssize_t store_s0_brightness(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) +/* Change brightness */ +static ssize_t store_brightness_offset(struct device *dev, + struct device_attribute *attr, + u8 offset, + const char *buf, size_t len) { struct led_classdev *cdev = dev_get_drvdata(dev); struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); - u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; int ret; u8 val; - if (led->indicator == LED_IND_DISABLE) { - dev_dbg(dev, "Led %s is disabled. ignoring it.\n", cdev->name); - return -EACCES; - } + if (led->indicator != LED_IND_POWER_STATE) + return -ENODEV; if (kstrtou8(buf, 0, &val) || val > 100) return -EINVAL; - /* - * For single-color LEDs, the value should be between 0 to 2, but, - * in order to have a consistent API, let's always handle it as if - * it is a percentage, for both multicolor and single color LEDs. - * So: - * value == 0 will disable the LED - * value up to 74% will set it the brightness to 50% - * value equal or above 75% will use the maximum brightness. - */ - if (!(led->color_type & (LED_BLUE_AMBER | LED_BLUE_WHITE | LED_RGB))) { - if (val > 0 && val < 75) - val = 1; - if (val >= 75) - val = 2; - } - - cmd = LED_SET_VALUE; - input[0] = led->id; - input[1] = led->indicator; - input[2] = 0; /* FIXME: replace by an enum */ - input[3] = val; - - ret = nuc_nmi_cmd(dev, cmd, input, NULL); + ret = nuc_wmi_set_brightness_offset(dev, led, offset, val); if (ret) return ret; return len; } +static enum led_brightness nuc_wmi_get_brightness(struct led_classdev *cdev) +{ + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->indicator == LED_IND_POWER_STATE) + return -ENODEV; + + return nuc_wmi_get_brightness_offset(cdev->dev, led, 0); +} + +static int nuc_wmi_set_brightness(struct led_classdev *cdev, + enum led_brightness brightness) +{ + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->indicator == LED_IND_POWER_STATE) + return -ENODEV; + + return nuc_wmi_set_brightness_offset(cdev->dev, led, 0, brightness); +} + static LED_ATTR_RW(indicator); -static LED_ATTR_RW(s0_brightness); + +LED_ATTR_POWER_STATE_RW(s0_brightness, 0x00); +LED_ATTR_POWER_STATE_RW(s3_brightness, 0x06); +LED_ATTR_POWER_STATE_RW(s5_brightness, 0x0c); +LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 0x12); /* - * Attributes for multicolor LEDs + * Attributes for LEDs */ -static struct attribute *nuc_wmi_multicolor_led_attr[] = { +static struct attribute *nuc_wmi_led_attr[] = { &dev_attr_indicator.attr, &dev_attr_s0_brightness.attr, + &dev_attr_s3_brightness.attr, + &dev_attr_s5_brightness.attr, + &dev_attr_ready_mode_brightness.attr, NULL, }; static const struct attribute_group nuc_wmi_led_attribute_group = { - .attrs = nuc_wmi_multicolor_led_attr, + .attrs = nuc_wmi_led_attr, }; static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { @@ -493,30 +627,25 @@ static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *led) { + int brightness = nuc_wmi_get_brightness_offset(dev, led, 0); + led->cdev.name = led_names[led->id]; - led->dev = dev; led->cdev.groups = nuc_wmi_led_attribute_groups; + led->cdev.brightness_get = nuc_wmi_get_brightness; + led->cdev.brightness_set_blocking = nuc_wmi_set_brightness; - /* - * It can't let the classdev to manage the brightness due to several - * reasons: - * - * 1) classdev has some internal logic to manage the brightness, - * at set_brightness_delayed(), which starts disabling the LEDs; - * While this makes sense on most cases, here, it would appear - * that the NUC was powered off, which is not what happens; - * 2) classdev unconditionally tries to set brightness for all - * leds, including the ones that were software-disabled or - * disabled disabled via BIOS menu; - * 3) There are 3 types of brightness values for each LED, depending - * on the CPU power state: S0, S3 and S5. - * - * So, the best seems to export everything via sysfs attributes - * directly. This would require some further changes at the - * LED class, though, or we would need to create our own LED - * class, which seems wrong. - */ + if (led->color_type & LED_SINGLE_COLOR) + led->cdev.max_brightness = 2; + else + led->cdev.max_brightness = 100; + + /* Ensure that the current bright will be preserved */ + if (brightness >= 0) + led->cdev.delayed_set_value = brightness; + + /* Suppress warnings for the LED(s) indicating the power state */ + led->cdev.flags = LED_HW_PLUGGABLE | LED_UNREGISTERING; return devm_led_classdev_register(dev, &led->cdev); } From patchwork Sun May 16 10:53:33 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440371 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1EA7DC433B4 for ; Sun, 16 May 2021 10:53:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 01E92611BF for ; Sun, 16 May 2021 10:53:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230350AbhEPKzK (ORCPT ); Sun, 16 May 2021 06:55:10 -0400 Received: from mail.kernel.org ([198.145.29.99]:47750 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229910AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id DAB4D611BD; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=VffAjVEGj0KnqZ+dbqyEYxecX+Dvk1FJFfEgTWX3FtY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IOx1mooElKYtzRqYX8Volrk8T0GkXx2GaHSTpMBDqL2+/8GWoCqPNbsKbHaPNKoGG CwQzYBK7qlJ2pGFQh4G31jCRDPh3O73yJtWEqFQDigDDBZh8jQBQF1lJlLgoNU40/L 12cbx9sfxCGE5eR+FO82DpOavuiMv8X0A/Zgov9alk1eTMo93DPYI6UKClm28HV5dl OM62jb1ks9yi4vajoqTWR4O/fIOHocO1sZNjF955zp4ONdb1J/dZkRXiO2GLSpEQx1 u/deomzZv2gqSR1HXdNy6q111BdEVSyGnRZnYZOLqWqxZ3/Kvq6/r1B32x73jB//BI roVicJS4ZLMTg== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s8G-RT; Sun, 16 May 2021 12:53:50 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 05/17] staging: nuc-wmi: allow changing the LED colors Date: Sun, 16 May 2021 12:53:33 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Add routines to allow seeing and changing the LED colors. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 244 ++++++++++++++++++++++++++++-- 1 file changed, 228 insertions(+), 16 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 711897ba4666..07cf18e6f4c4 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -58,8 +58,6 @@ enum led_new_get_subcmd { enum led_function { LED_FUNC_BRIGHTNESS, LED_FUNC_COLOR1, - LED_FUNC_COLOR_GREEN, - LED_FUNC_COLOR_BLUE, LED_FUNC_BLINK_BEHAVIOR, LED_FUNC_BLINK_FREQ, @@ -92,43 +90,31 @@ static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUNC] = { [LED_FUNC_BLINK_BEHAVIOR] = 0x01, [LED_FUNC_BLINK_FREQ] = 0x02, [LED_FUNC_COLOR1] = 0x03, - [LED_FUNC_COLOR_GREEN] = 0x04, - [LED_FUNC_COLOR_BLUE] = 0x05 }, [LED_IND_HDD_ACTIVITY] = { [LED_FUNC_BRIGHTNESS] = 0x00, [LED_FUNC_COLOR1] = 0x01, - [LED_FUNC_COLOR_GREEN] = 0x02, - [LED_FUNC_COLOR_BLUE] = 0x03, [LED_FUNC_HDD_BEHAVIOR] = 0x04 }, [LED_IND_ETHERNET] = { [LED_FUNC_ETH_TYPE] = 0x00, [LED_FUNC_BRIGHTNESS] = 0x01, [LED_FUNC_COLOR1] = 0x02, - [LED_FUNC_COLOR_GREEN] = 0x03, - [LED_FUNC_COLOR_BLUE] = 0x04 }, [LED_IND_WIFI] = { [LED_FUNC_BRIGHTNESS] = 0x00, [LED_FUNC_COLOR1] = 0x01, - [LED_FUNC_COLOR_GREEN] = 0x02, - [LED_FUNC_COLOR_BLUE] = 0x03 }, [LED_IND_SOFTWARE] = { [LED_FUNC_BRIGHTNESS] = 0x00, [LED_FUNC_BLINK_BEHAVIOR] = 0x01, [LED_FUNC_BLINK_FREQ] = 0x02, [LED_FUNC_COLOR1] = 0x03, - [LED_FUNC_COLOR_GREEN] = 0x04, - [LED_FUNC_COLOR_BLUE] = 0x05 }, [LED_IND_POWER_LIMIT] = { [LED_FUNC_POWER_LIMIT_SCHEME] = 0x00, [LED_FUNC_BRIGHTNESS] = 0x01, [LED_FUNC_COLOR1] = 0x02, - [LED_FUNC_COLOR_GREEN] = 0x03, - [LED_FUNC_COLOR_BLUE] = 0x04 }, }; @@ -459,6 +445,8 @@ static ssize_t nuc_wmi_set_brightness_offset(struct device *dev, } \ static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) +/* Show/change the LED indicator */ + static const char * const led_indicators[] = { "Power State", "HDD Activity", @@ -531,7 +519,220 @@ static ssize_t store_indicator(struct device *dev, return -EINVAL; } -/* Get brightness */ +/* Show/change the LED color */ + +enum led_colors { + LED_COLOR_BLUE, + LED_COLOR_AMBER, + LED_COLOR_WHITE +}; + +struct led_color_name { + const char *name; + u8 r, g, b; +}; + +static const struct led_color_name led_colors[] = { + /* The first colors should match the dual-LED colorset */ + [LED_COLOR_BLUE] = { "blue", 0, 0, 0xff }, + [LED_COLOR_AMBER] = { "amber", 0xff, 0xbf, 0 }, + [LED_COLOR_WHITE] = { "white", 0xff, 0xff, 0xff }, + + /* Let's add a couple of common color names as well */ + { "red", 0xff, 0, 0 }, + { "green", 0, 0xff, 0 }, + { "yellow", 0xff, 0xff, 0 }, + { "cyan", 0, 0xff, 0xff }, + { "magenta", 0xff, 0, 0xff }, +}; + +static ssize_t show_color(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl; + int size = PAGE_SIZE; + char *p = buf; + int color, r, g, b; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = ctrl; + + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + if (led->color_type & LED_RGB) { + r = output[0]; + + input[3]++; + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + g = output[0]; + + input[3]++; + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + b = output[0]; + + for (color = 0; color < ARRAY_SIZE(led_colors); color++) + if (led_colors[color].r == r && + led_colors[color].g == g && + led_colors[color].b == b) + return scnprintf(p, size, "%s\n", + led_colors[color].name); + + return scnprintf(p, size, "%d,%d,%d\n", r, g, b); + } + + if (!output[0]) + return scnprintf(p, size, "%s\n", + led_colors[LED_COLOR_BLUE].name); + + if (led->color_type & LED_BLUE_AMBER) + return scnprintf(p, size, "%s\n", + led_colors[LED_COLOR_AMBER].name); + + return scnprintf(p, size, "%s\n", led_colors[LED_COLOR_WHITE].name); +} + +static ssize_t store_color(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + int ret, ctrl, color; + const char *tmp; + u8 r, g, b, val; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + tmp = strsep((char **)&buf, ",\n"); + + for (color = 0; color < ARRAY_SIZE(led_colors); color++) + if (!strcasecmp(tmp, led_colors[color].name)) + break; + + if (color < ARRAY_SIZE(led_colors)) { + r = led_colors[color].r; + g = led_colors[color].g; + b = led_colors[color].b; + } else { + if (kstrtou8(tmp, 0, &r) || r > 255) + return -EINVAL; + + tmp = strsep((char **)&buf, ",\n"); + if (kstrtou8(tmp, 0, &g) || g > 255) + return -EINVAL; + + tmp = strsep((char **)&buf, " \n"); + if (kstrtou8(tmp, 0, &b) || b > 255) + return -EINVAL; + + if (led->color_type & LED_SINGLE_COLOR) { + for (color = 0; color <= LED_COLOR_WHITE; color++) + if (led_colors[color].r == r && + led_colors[color].g == g && + led_colors[color].b == b) + break; + } + } + + ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + + /* Dual color LEDs */ + if (!(led->color_type & LED_RGB)) { + if (color == LED_COLOR_BLUE) + val = 0; + else { + if (led->color_type & LED_BLUE_AMBER && + color != LED_COLOR_AMBER) + return -EINVAL; + else if (color != LED_COLOR_WHITE) + return -EINVAL; + val =1; + } + + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = val; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; + } + + /* RGB LEDs */ + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = r; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + input[0] = led->id; + input[1] = led->indicator; + input[2]++; + input[3] = g; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + input[0] = led->id; + input[1] = led->indicator; + input[2]++; + input[3] = b; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; + + return -EINVAL; +} + +static umode_t nuc_wmi_led_color_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev = kobj_to_dev(kobj); + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + umode_t mode = attr->mode; + + if (led->color_type & LED_SINGLE_COLOR) + return 0; + + return mode; +} + +/* Show/store brightness */ static ssize_t show_brightness_offset(struct device *dev, struct device_attribute *attr, u8 offset, @@ -551,7 +752,6 @@ static ssize_t show_brightness_offset(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } -/* Change brightness */ static ssize_t store_brightness_offset(struct device *dev, struct device_attribute *attr, u8 offset, @@ -597,6 +797,7 @@ static int nuc_wmi_set_brightness(struct led_classdev *cdev, } static LED_ATTR_RW(indicator); +static LED_ATTR_RW(color); LED_ATTR_POWER_STATE_RW(s0_brightness, 0x00); LED_ATTR_POWER_STATE_RW(s3_brightness, 0x06); @@ -620,8 +821,19 @@ static const struct attribute_group nuc_wmi_led_attribute_group = { .attrs = nuc_wmi_led_attr, }; +static struct attribute *nuc_wmi_led_color_attr[] = { + &dev_attr_color.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_color_attribute_group = { + .is_visible = nuc_wmi_led_color_is_visible, + .attrs = nuc_wmi_led_color_attr, +}; + static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { &nuc_wmi_led_attribute_group, + &nuc_wmi_led_color_attribute_group, NULL }; From patchwork Sun May 16 10:53:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439986 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id C1F99C43617 for ; Sun, 16 May 2021 10:53:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id A6D6161182 for ; Sun, 16 May 2021 10:53:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230459AbhEPKzM (ORCPT ); Sun, 16 May 2021 06:55:12 -0400 Received: from mail.kernel.org ([198.145.29.99]:47724 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229628AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id DD3AA611BE; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=wcuh0LMsWu8QO2eXqeB4nI5u/nWk2rByYu1mqtWA8ck=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VCPRYBUMnp7CtDxIWoBGv3i/+roQ2BPBV5cISQQeRwy4+Xc5BP9Iw9/bX8ReJbkdx EfWCcwScc9HWBUMVkz/KYbTO/aMQGS23XvnhFFhXUJkpeUcesBJF0OUCJAy9UYTKi/ ROsLFmHl7H9iFpkx4W95tR954jOPqXf6xLJuAT830LtQXra0n4m/pIRJpmoATWAdvp DaCBlK6aEtagf4zckuHZVo9oi/9Qq2dLUQVCOUC+tHxAILmshs4eFbYbV61ueFF4y9 GJTDM79redNqGNhTy1X6Fb6idSQxIjzPJnDXten4Ivd1Wl9oMp4Ov+YekUKJCtVNFQ 7++GE+m56XMzg== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s8K-Sa; Sun, 16 May 2021 12:53:50 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 06/17] staging: nuc-wmi: add support for WMI API version 1.0 Date: Sun, 16 May 2021 12:53:34 +0200 Message-Id: <41692e55621f75a75b52ad3ed2f341833ebf3a78.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The control indicators for WMI version 1.0 (used on NUCi10 and above) are on different locations. The main difference is on single color LEDs. Also, the Power State brightness names are defined on a different way, and there are 3 groups instead of 4. As the driver was written with some tables to map the control option values, it is easy to extend it to support the new definitions: all we need to do is to add the V1.0 tables and ensure that the right table will be used. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 119 +++++++++++++++++++++++++----- 1 file changed, 99 insertions(+), 20 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 07cf18e6f4c4..e9c59f656283 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -62,6 +62,7 @@ enum led_function { LED_FUNC_BLINK_BEHAVIOR, LED_FUNC_BLINK_FREQ, + LED_FUNC_POWER_STATE_NUM_CTRLS, LED_FUNC_HDD_BEHAVIOR, LED_FUNC_ETH_TYPE, LED_FUNC_POWER_LIMIT_SCHEME, @@ -84,8 +85,11 @@ enum led_indicators { /* * control items ID for each of the valid indicators on spec Rev 0.64. */ -static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUNC] = { - [LED_IND_POWER_STATE] = { /* Offsets for each power state */ +static const u8 led_func_multicolor[MAX_IND][MAX_LED_FUNC] = { + [LED_IND_POWER_STATE] = { + [LED_FUNC_POWER_STATE_NUM_CTRLS] = 0x06, + + /* Offsets for each power state */ [LED_FUNC_BRIGHTNESS] = 0x00, [LED_FUNC_BLINK_BEHAVIOR] = 0x01, [LED_FUNC_BLINK_FREQ] = 0x02, @@ -118,6 +122,24 @@ static const u8 led_func_rev_0_64[MAX_IND][MAX_LED_FUNC] = { }, }; +static const u8 led_func_rev_1_0_singlecolor[MAX_IND][MAX_LED_FUNC] = { + [LED_IND_POWER_STATE] = { + [LED_FUNC_POWER_STATE_NUM_CTRLS] = 0x02, + + /* Offsets for each power state */ + [LED_FUNC_BRIGHTNESS] = 0x00, + [LED_FUNC_BLINK_BEHAVIOR] = 0x01, + }, + [LED_IND_HDD_ACTIVITY] = { + [LED_FUNC_BRIGHTNESS] = 0x00, + [LED_FUNC_HDD_BEHAVIOR] = 0x01 + }, + [LED_IND_SOFTWARE] = { + [LED_FUNC_BRIGHTNESS] = 0x00, + [LED_FUNC_BLINK_BEHAVIOR] = 0x01, + }, +}; + /* LED color indicator */ #define LED_BLUE_AMBER BIT(0) #define LED_BLUE_WHITE BIT(1) @@ -141,6 +163,9 @@ struct nuc_nmi_led { u8 indicator; u32 color_type; u32 avail_indicators; + enum led_api_rev api_rev; + + const u8 (*reg_table)[MAX_LED_FUNC]; }; struct nuc_wmi { @@ -251,7 +276,7 @@ static int nuc_nmi_cmd(struct device *dev, return ret; } -static int nuc_wmi_query_leds(struct device *dev) +static int nuc_wmi_query_leds(struct device *dev, enum led_api_rev *api_rev) { struct nuc_wmi *priv = dev_get_drvdata(dev); u8 input[NUM_INPUT_ARGS] = { 0 }; @@ -288,9 +313,11 @@ static int nuc_wmi_query_leds(struct device *dev) } /* Currently, only API Revision 0.64 is supported */ - if (ver != LED_API_REV_0_64) + if (ver != LED_API_REV_0_64 && ver != LED_API_REV_1_0) return -ENODEV; + *api_rev = ver; + if (!leds) { dev_warn(dev, "No LEDs found\n"); return -ENODEV; @@ -379,7 +406,7 @@ static int nuc_wmi_get_brightness_offset(struct device *dev, if (led->indicator == LED_IND_DISABLE) return -ENODEV; - ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + ctrl = led->reg_table[led->indicator][LED_FUNC_BRIGHTNESS] + offset; if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; @@ -410,7 +437,7 @@ static ssize_t nuc_wmi_set_brightness_offset(struct device *dev, if (led->indicator == LED_IND_DISABLE) return -ENODEV; - ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_BRIGHTNESS] + offset; + ctrl = led->reg_table[led->indicator][LED_FUNC_BRIGHTNESS] + offset; if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; @@ -561,7 +588,7 @@ static ssize_t show_color(struct device *dev, if (led->indicator == LED_IND_DISABLE) return -ENODEV; - ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + ctrl = led->reg_table[led->indicator][LED_FUNC_COLOR1]; if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; @@ -658,7 +685,7 @@ static ssize_t store_color(struct device *dev, } } - ctrl = led_func_rev_0_64[led->indicator][LED_FUNC_COLOR1]; + ctrl = led->reg_table[led->indicator][LED_FUNC_COLOR1]; /* Dual color LEDs */ if (!(led->color_type & LED_RGB)) { @@ -745,6 +772,8 @@ static ssize_t show_brightness_offset(struct device *dev, if (led->indicator != LED_IND_POWER_STATE) return -ENODEV; + offset *= led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + ret = nuc_wmi_get_brightness_offset(dev, led, offset); if (ret < 0) return ret; @@ -768,6 +797,8 @@ static ssize_t store_brightness_offset(struct device *dev, if (kstrtou8(buf, 0, &val) || val > 100) return -EINVAL; + offset *= led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + ret = nuc_wmi_set_brightness_offset(dev, led, offset, val); if (ret) return ret; @@ -796,13 +827,40 @@ static int nuc_wmi_set_brightness(struct led_classdev *cdev, return nuc_wmi_set_brightness_offset(cdev->dev, led, 0, brightness); } +static umode_t nuc_wmi_led_power_state_is_visible(struct kobject *kobj, + struct attribute *attr, + int idx) +{ + struct device *dev = kobj_to_dev(kobj); + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + umode_t mode = attr->mode; + + if (!strcmp(attr->name, "s0_brightness") || + !strcmp(attr->name, "s3_brightness")) + return mode; + + if (led->api_rev == LED_API_REV_0_64) { + if (!strcmp(attr->name, "s5_brightness") || + !strcmp(attr->name, "ready_mode_brightness")) + return mode; + } else { + if (!strcmp(attr->name, "standby_brightness")) + return mode; + } + + return 0; +} + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); -LED_ATTR_POWER_STATE_RW(s0_brightness, 0x00); -LED_ATTR_POWER_STATE_RW(s3_brightness, 0x06); -LED_ATTR_POWER_STATE_RW(s5_brightness, 0x0c); -LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 0x12); +LED_ATTR_POWER_STATE_RW(s0_brightness, 0); +LED_ATTR_POWER_STATE_RW(s3_brightness, 1); +LED_ATTR_POWER_STATE_RW(s5_brightness, 2); // Rev 0.64 +LED_ATTR_POWER_STATE_RW(standby_brightness, 2); // Rev 1.0 +LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 3); // Rev 1.0 /* * Attributes for LEDs @@ -810,15 +868,25 @@ LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 0x12); static struct attribute *nuc_wmi_led_attr[] = { &dev_attr_indicator.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_attribute_group = { + .attrs = nuc_wmi_led_attr, +}; + +static struct attribute *nuc_wmi_led_power_state_attr[] = { &dev_attr_s0_brightness.attr, &dev_attr_s3_brightness.attr, + &dev_attr_standby_brightness.attr, &dev_attr_s5_brightness.attr, &dev_attr_ready_mode_brightness.attr, NULL, }; -static const struct attribute_group nuc_wmi_led_attribute_group = { - .attrs = nuc_wmi_led_attr, +static const struct attribute_group nuc_wmi_led_power_state_group = { + .is_visible = nuc_wmi_led_power_state_is_visible, + .attrs = nuc_wmi_led_power_state_attr, }; static struct attribute *nuc_wmi_led_color_attr[] = { @@ -833,26 +901,36 @@ static const struct attribute_group nuc_wmi_led_color_attribute_group = { static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { &nuc_wmi_led_attribute_group, + &nuc_wmi_led_power_state_group, &nuc_wmi_led_color_attribute_group, NULL }; -static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *led) +static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *led, + enum led_api_rev api_rev) { - int brightness = nuc_wmi_get_brightness_offset(dev, led, 0); + int brightness; led->cdev.name = led_names[led->id]; led->dev = dev; led->cdev.groups = nuc_wmi_led_attribute_groups; led->cdev.brightness_get = nuc_wmi_get_brightness; led->cdev.brightness_set_blocking = nuc_wmi_set_brightness; + led->api_rev = api_rev; - if (led->color_type & LED_SINGLE_COLOR) + if (led->color_type & LED_SINGLE_COLOR) { + if (led->api_rev == LED_API_REV_1_0) + led->reg_table = led_func_rev_1_0_singlecolor; + else + led->reg_table = led_func_multicolor; led->cdev.max_brightness = 2; - else + } else { led->cdev.max_brightness = 100; + led->reg_table = led_func_multicolor; + } /* Ensure that the current bright will be preserved */ + brightness = nuc_wmi_get_brightness_offset(dev, led, 0); if (brightness >= 0) led->cdev.delayed_set_value = brightness; @@ -865,14 +943,15 @@ static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *led) static int nuc_wmi_leds_setup(struct device *dev) { struct nuc_wmi *priv = dev_get_drvdata(dev); + enum led_api_rev api_rev; int ret, i; - ret = nuc_wmi_query_leds(dev); + ret = nuc_wmi_query_leds(dev, &api_rev); if (ret) return ret; for (i = 0; i < priv->num_leds; i++) { - ret = nuc_wmi_led_register(dev, &priv->led[i]); + ret = nuc_wmi_led_register(dev, &priv->led[i], api_rev); if (ret) { dev_err(dev, "Failed to register led %d: %s\n", i, led_names[priv->led[i].id]); From patchwork Sun May 16 10:53:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440372 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-24.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, MENTIONS_GIT_HOSTING, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D55EFC43462 for ; Sun, 16 May 2021 10:53:56 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B203C61205 for ; Sun, 16 May 2021 10:53:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229437AbhEPKzK (ORCPT ); Sun, 16 May 2021 06:55:10 -0400 Received: from mail.kernel.org ([198.145.29.99]:47698 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229479AbhEPKzH (ORCPT ); Sun, 16 May 2021 06:55:07 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C498061183; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=W9Q0II8E1tQWmZf1EbKmOxyviDDnDvlIZCkYcXDLhpg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UydJGp/W7OgF5JRWp82GqIyuEb2nOlcYZx2FsxsEZ/sOZ+ETi50a8FuE4JhzSk23k KH5KLy3jWeB4/5/KVykMCdDvQkbRi0oYBQ/dFKF7FvI/DO4Zv83ghzdvXIN1hQ7iQm VFf0bb9s3cBL9fwwiVu4DLHEYQiDnkE4BPaMKbmgBeinQrjHnubMwHKWRfGTJERaSv K8wXKBJ8q0EJ6Eo8ADZdezt6NBSGZ5ROQmWB+R/DPtTGeyuQWw9XnGbb7/iO2kcKfb sGUTvj4qSsQCfOJNNyzjL28HFUWkghFvlA/tXEOpQa1uQyuiY5/tENQDkrtnwoWsbG AXIr+Z7UQN9lA== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s8O-Ud; Sun, 16 May 2021 12:53:50 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 07/17] staging: nuc-wmi: add basic support for NUC6 WMI Date: Sun, 16 May 2021 12:53:35 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The NUC6 and NUCi7 supports an earlier version of the LEDs WMI, as specified at: https://www.intel.com/content/www/us/en/support/articles/000023426/intel-nuc/intel-nuc-kits.html Implement the query part of the LED detection for those devices. Weird enough, at least with Skull Canyon (NUC6i7KYB) using the latest firmware release (KYSKLi70 0071), the WMI call return all zeros. It could well be due to a regression at the Intel's firmware, although this model was not announced as supporting this WMI. At the manufacturer's site, only NUC Kits NUC7i[x]BN and NUC6CAY are mentioned. Yet, it sounds to me that this is due to a firmware bug: $ sudo fwts wmi - ... Test 1 of 1: Windows Management Instrumentation test. ... \_SB_.WMTF._WDG (1 of 1) GUID: 86CCFD48-205E-4A77-9C48-2021CBEDE341 WMI Method: Flags : 0x02 (Method) Object ID : TF Instance : 0x01 Driver : intel-wmi-thunderbolt (Intel) FAILED [LOW] WMIMultipleMethod: Test 1, GUID 86CCFD48-205E-4A77-9C48-2021CBEDE341 has multiple associated methods WMTF defined, this is a firmware bug that leads to ambiguous behaviour. ... \AMW0._WDG (1 of 2) GUID: 8C5DA44C-CDC3-46B3-8619-4E26D34390B7 WMI Method: Flags : 0x02 (Method) Object ID : AA Instance : 0x01 PASSED: Test 1, 8C5DA44C-CDC3-46B3-8619-4E26D34390B7 has associated method \AMW0.WMAA ... Low failures: 1 wmi: GUID 86CCFD48-205E-4A77-9C48-2021CBEDE341 has multiple associated methods WMTF defined, this is a firmware bug that leads to ambiguous behaviour. Anyway, this was good enough to test that this patch will be producing exactly the WMI query as the NUC6 OOT driver at: https://github.com/milesp20/intel_nuc_led/ Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 134 +++++++++++++++++++++++------- 1 file changed, 106 insertions(+), 28 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index e9c59f656283..db38c40c223a 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -8,12 +8,15 @@ * * Inspired on WMI from https://github.com/nomego/intel_nuc_led * - * It follows this spec: - * https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI-Spec-Intel-NUC-NUC10ixFNx.pdf + * It follows those specs: + * https://www.intel.com/content/www/us/en/support/articles/000023426/intel-nuc/intel-nuc-kits.html + * https://raw.githubusercontent.com/nomego/intel_nuc_led/master/specs/INTEL_WMI_LED_0.64.pdf + * https://www.intel.com/content/dam/support/us/en/documents/intel-nuc/WMI-Spec-Intel-NUC-NUC10ixFNx.pdf */ #include #include +#include #include #include #include @@ -34,12 +37,21 @@ enum led_api_rev { }; enum led_cmds { + /* NUC6-specific cmds */ + LED_OLD_GET_STATUS = 0x01, + LED_OLD_SET_LED = 0x02, + + /* Rev 0.64 and 1.0 cmds */ + LED_QUERY = 0x03, LED_NEW_GET_STATUS = 0x04, LED_SET_INDICATOR = 0x05, LED_SET_VALUE = 0x06, LED_NOTIFICATION = 0x07, LED_SWITCH_TYPE = 0x08, + + /* Rev 1.0 cmds */ + LED_VERSION_CONTROL = 0x09, }; @@ -55,6 +67,11 @@ enum led_new_get_subcmd { LED_NEW_GET_CONTROL_ITEM = 0x01, }; +enum led_old_get_subcmd { + LED_OLD_GET_S0_POWER = 0x01, + LED_OLD_GET_S0_RING = 0x02, +}; + enum led_function { LED_FUNC_BRIGHTNESS, LED_FUNC_COLOR1, @@ -146,14 +163,19 @@ static const u8 led_func_rev_1_0_singlecolor[MAX_IND][MAX_LED_FUNC] = { #define LED_RGB BIT(2) #define LED_SINGLE_COLOR BIT(3) +#define POWER_LED 0 +#define RING_LED (MAX_LEDS + 1) + static const char * const led_names[] = { - "nuc::power", + [POWER_LED] = "nuc::power", "nuc::hdd", "nuc::skull", "nuc::eyes", "nuc::front1", "nuc::front2", "nuc::front3", + + [RING_LED] = "nuc::ring", // NUC6 models }; struct nuc_nmi_led { @@ -276,48 +298,98 @@ static int nuc_nmi_cmd(struct device *dev, return ret; } +static int nuc_wmi_query_leds_nuc6(struct device *dev) +{ + // FIXME: add a check for the specific models that are known to work + struct nuc_wmi *priv = dev_get_drvdata(dev); + u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + struct nuc_nmi_led *led; + int ret; + + cmd = LED_OLD_GET_STATUS; + input[0] = LED_OLD_GET_S0_POWER; + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "Get S0 Power: error %d\n", ret); + return ret; + } + + led = &priv->led[priv->num_leds]; + led->id = POWER_LED; + led->color_type = LED_BLUE_AMBER; + led->avail_indicators = LED_IND_POWER_STATE; + led->indicator = fls(led->avail_indicators); + priv->num_leds++; + + cmd = LED_OLD_GET_STATUS; + input[0] = LED_OLD_GET_S0_RING; + ret = nuc_nmi_cmd(dev, cmd, input, output); + if (ret) { + dev_warn(dev, "Get S0 Ring: error %d\n", ret); + return ret; + } + led = &priv->led[priv->num_leds]; + led->id = RING_LED; + led->color_type = LED_BLUE_AMBER; + led->avail_indicators = LED_IND_SOFTWARE; + led->indicator = fls(led->avail_indicators); + priv->num_leds++; + + return ret; +} + static int nuc_wmi_query_leds(struct device *dev, enum led_api_rev *api_rev) { struct nuc_wmi *priv = dev_get_drvdata(dev); u8 input[NUM_INPUT_ARGS] = { 0 }; u8 output[NUM_OUTPUT_ARGS]; - int id, ret, ver = LED_API_UNKNOWN; + int id, ret, ver = LED_API_UNKNOWN, nuc_ver = 0; u8 leds; + const char *dmi_name; + + dmi_name = dmi_get_system_info(DMI_PRODUCT_NAME); + if (!dmi_name || !*dmi_name) + dmi_name = dmi_get_system_info(DMI_BOARD_NAME); + + if (strncmp(dmi_name, "NUC", 3)) + return -ENODEV; + + dmi_name +=3; + while (*dmi_name) { + if (*dmi_name < '0' || *dmi_name > '9') + break; + nuc_ver = (*dmi_name - '0') + nuc_ver * 10; + dmi_name++; + } + + if (nuc_ver < 6) + return -ENODEV; + + if (nuc_ver < 8) { + *api_rev = LED_API_NUC6; + return nuc_wmi_query_leds_nuc6(dev); + } - /* - * List all LED types support in the platform - * - * Should work with both NUC8iXXX and NUC10iXXX - * - * FIXME: Should add a fallback code for it to work with older NUCs, - * as LED_QUERY returns an error on older devices like Skull Canyon. - */ input[0] = LED_QUERY_LIST_ALL; ret = nuc_nmi_cmd(dev, LED_QUERY, input, output); - if (ret == -ENOENT) { - ver = LED_API_NUC6; - } else if (ret) { + if (ret) { dev_warn(dev, "error %d while listing all LEDs\n", ret); return ret; } else { leds = output[0]; } - if (ver != LED_API_NUC6) { - ret = nuc_nmi_cmd(dev, LED_VERSION_CONTROL, input, output); - ver = output[0] | output[1] << 16; - if (!ver) - ver = LED_API_REV_0_64; - else if (ver == 0x0126) - ver = LED_API_REV_1_0; - } + ret = nuc_nmi_cmd(dev, LED_VERSION_CONTROL, input, output); + ver = output[0] | output[1] << 16; + if (!ver) + *api_rev = LED_API_REV_0_64; + else if (ver == 0x0126) + *api_rev = LED_API_REV_1_0; - /* Currently, only API Revision 0.64 is supported */ - if (ver != LED_API_REV_0_64 && ver != LED_API_REV_1_0) + if (*api_rev == LED_API_UNKNOWN) return -ENODEV; - *api_rev = ver; - if (!leds) { dev_warn(dev, "No LEDs found\n"); return -ENODEV; @@ -913,10 +985,16 @@ static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *led, led->cdev.name = led_names[led->id]; led->dev = dev; + led->api_rev = api_rev; + + if (led->api_rev == LED_API_NUC6) { + // FIXME: add NUC6-specific API bits here + return devm_led_classdev_register(dev, &led->cdev); + } + led->cdev.groups = nuc_wmi_led_attribute_groups; led->cdev.brightness_get = nuc_wmi_get_brightness; led->cdev.brightness_set_blocking = nuc_wmi_set_brightness; - led->api_rev = api_rev; if (led->color_type & LED_SINGLE_COLOR) { if (led->api_rev == LED_API_REV_1_0) From patchwork Sun May 16 10:53:36 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439989 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0068EC43600 for ; Sun, 16 May 2021 10:53:57 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id C5746613C1 for ; Sun, 16 May 2021 10:53:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230332AbhEPKzK (ORCPT ); Sun, 16 May 2021 06:55:10 -0400 Received: from mail.kernel.org ([198.145.29.99]:47704 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229506AbhEPKzH (ORCPT ); Sun, 16 May 2021 06:55:07 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id C84BB61184; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=aZccJ0bg/mMgG/HBTCLEB1mjUvqzsT/zeGhH0Y0dcso=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lkqdUBTy526rucId3KtQ5MCl4lXEcDc5LNLl4NTtmNNqzIrbmTShG9v2bUGaHKBsn M90QREspNhIVy0SlIY06u78EJTMfHAzMOwJveeG6Zm3+5nbKSacWG9oegLK3iZ7iEz POt8ZpQR334yGCvV7SPNOU13dBQCT53KeJs2e+Ax+Pj/DuPYEVHDlruGBvh6KbRGuq 44mY/4tcBMJHGeQHNM+0vsfc2c19WVEzqE1DlYAnI9B8uM2Mv3wtfmT69xIcOklIZn TQRIbQQGX2I9fLlQqE1PQPo1uvXemeNQ6+gu/O1ZBjjIOP5+3dQciZ8v/1xnTPDumw FCSznUCoa8tNA== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP8-003s8S-Vu; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 08/17] staging: muc-wmi: add brightness and color for NUC6 API Date: Sun, 16 May 2021 12:53:36 +0200 Message-Id: <58e10bcb33ea936a7971c222a57b03f79e60302f.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The NUC6 WMI API is really simple: it has just 2 messages, that retrieves everything for a LED, and it has just 2 LEDs. Add support for retrieving and set brightness and color. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 198 ++++++++++++++++++++++++++++-- 1 file changed, 191 insertions(+), 7 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index db38c40c223a..a365a8603182 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -302,14 +302,13 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) { // FIXME: add a check for the specific models that are known to work struct nuc_wmi *priv = dev_get_drvdata(dev); - u8 cmd, input[NUM_INPUT_ARGS] = { 0 }; + u8 input[NUM_INPUT_ARGS] = { 0 }; u8 output[NUM_OUTPUT_ARGS]; struct nuc_nmi_led *led; int ret; - cmd = LED_OLD_GET_STATUS; input[0] = LED_OLD_GET_S0_POWER; - ret = nuc_nmi_cmd(dev, cmd, input, output); + ret = nuc_nmi_cmd(dev, LED_OLD_GET_STATUS, input, output); if (ret) { dev_warn(dev, "Get S0 Power: error %d\n", ret); return ret; @@ -322,9 +321,8 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) led->indicator = fls(led->avail_indicators); priv->num_leds++; - cmd = LED_OLD_GET_STATUS; input[0] = LED_OLD_GET_S0_RING; - ret = nuc_nmi_cmd(dev, cmd, input, output); + ret = nuc_nmi_cmd(dev, LED_OLD_GET_STATUS, input, output); if (ret) { dev_warn(dev, "Get S0 Ring: error %d\n", ret); return ret; @@ -544,6 +542,167 @@ static ssize_t nuc_wmi_set_brightness_offset(struct device *dev, } \ static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) +/* + * NUC6 specific logic + */ + +static int nuc_wmi_nuc6_led_get_set(struct device *dev, + struct nuc_nmi_led *led, int *brightness, + int *blink_fade, int *color_state) +{ + u8 input[NUM_INPUT_ARGS] = { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ret; + + if (led->id == POWER_LED) + input[0] = LED_OLD_GET_S0_POWER; + else + input[0] = LED_OLD_GET_S0_RING; + + ret = nuc_nmi_cmd(dev, LED_OLD_GET_STATUS, input, output); + if (ret) { + dev_warn(dev, "Get %s: error %d\n", led_names[led->id], ret); + return ret; + } + + if (brightness && *brightness >= 0) + input[1] = *brightness; + else + input[1] = output[0]; + + if (blink_fade && *blink_fade >= 0) + input[2] = *blink_fade; + else + input[2] = output[1]; + + if (color_state && *color_state >= 0) + input[3] = *color_state; + else + input[3] = output[2]; + + ret = nuc_nmi_cmd(dev, LED_OLD_SET_LED, input, output); + if (ret) { + dev_warn(dev, "Get %s: error %d\n", led_names[led->id], ret); + return ret; + } + + if (brightness) + *brightness = output[0]; + if (blink_fade) + *blink_fade = output[1]; + if (color_state) + *color_state = output[2]; + + return 0; +} + +static enum led_brightness nuc_wmi_nuc6_get_brightness(struct led_classdev *cdev) +{ + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + int ret, brightness = -1; + + ret = nuc_wmi_nuc6_led_get_set(cdev->dev, led, &brightness, NULL, NULL); + if (ret) + return ret; + + return brightness; +} + +static int nuc_wmi_nuc6_set_brightness(struct led_classdev *cdev, + enum led_brightness bright) +{ + int brightness = bright; + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + return nuc_wmi_nuc6_led_get_set(cdev->dev, led, &brightness, + NULL, NULL); +} + +static const char * const nuc6_power_colors[] = { + "disable", + "blue", + "amber" +}; + +static const char * const nuc6_ring_colors[] = { + "disable", + "cyan", + "pink", + "yellow", + "blue", + "red", + "green", + "white" +}; + +static ssize_t nuc6_show_color(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + int color = -1, ret, arr_size, i, n; + const char * const*color_names; + int size = PAGE_SIZE; + char *p = buf; + + ret = nuc_wmi_nuc6_led_get_set(dev, led, NULL, NULL, &color); + if (ret) + return ret; + + if (led->id == POWER_LED) { + color_names = nuc6_power_colors; + arr_size = ARRAY_SIZE(nuc6_power_colors); + } else { + color_names = nuc6_ring_colors; + arr_size = ARRAY_SIZE(nuc6_ring_colors); + } + + for (i = 0; i < arr_size; i++) { + if (i == color) + n = scnprintf(p, size, "[%s] ", color_names[i]); + else + n = scnprintf(p, size, "%s ", color_names[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; + +} + +static ssize_t nuc6_store_color(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + const char *tmp; + int ret, color; + + tmp = strsep((char **)&buf, ",\n"); + + if (led->id == POWER_LED) { + for (color = ARRAY_SIZE(nuc6_power_colors)+1; color >= 0; color--) + if (!strcasecmp(tmp, nuc6_power_colors[color])) + break; + } else { + for (color = ARRAY_SIZE(nuc6_ring_colors)+1; color >= 0; color--) + if (!strcasecmp(tmp, nuc6_ring_colors[color])) + break; + } + + if (color < 0) + return -EINVAL; + + ret = nuc_wmi_nuc6_led_get_set(dev, led, NULL, NULL, &color); + if (ret) + return ret; + + return len; +} + /* Show/change the LED indicator */ static const char * const led_indicators[] = { @@ -657,6 +816,9 @@ static ssize_t show_color(struct device *dev, char *p = buf; int color, r, g, b; + if (led->api_rev == LED_API_NUC6) + return nuc6_show_color(dev, attr, buf); + if (led->indicator == LED_IND_DISABLE) return -ENODEV; @@ -723,6 +885,9 @@ static ssize_t store_color(struct device *dev, const char *tmp; u8 r, g, b, val; + if (led->api_rev == LED_API_NUC6) + return nuc6_store_color(dev, attr, buf, len); + if (led->indicator == LED_IND_DISABLE) return -ENODEV; @@ -825,6 +990,9 @@ static umode_t nuc_wmi_led_color_is_visible(struct kobject *kobj, struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); umode_t mode = attr->mode; + if (led->api_rev == LED_API_NUC6) + return mode; + if (led->color_type & LED_SINGLE_COLOR) return 0; @@ -978,17 +1146,33 @@ static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { NULL }; +static const struct attribute_group *nuc_wmi_nuc6_led_attribute_groups[] = { + &nuc_wmi_led_color_attribute_group, + NULL +}; + static int nuc_wmi_led_register(struct device *dev, struct nuc_nmi_led *led, enum led_api_rev api_rev) { - int brightness; + int ret, brightness; led->cdev.name = led_names[led->id]; led->dev = dev; led->api_rev = api_rev; if (led->api_rev == LED_API_NUC6) { - // FIXME: add NUC6-specific API bits here + brightness = -1; + ret = nuc_wmi_nuc6_led_get_set(dev, led, &brightness, + NULL, NULL); + if (ret) + return ret; + + led->cdev.groups = nuc_wmi_nuc6_led_attribute_groups; + led->cdev.delayed_set_value = brightness; + led->cdev.max_brightness = 100; + led->cdev.brightness_get = nuc_wmi_nuc6_get_brightness; + led->cdev.brightness_set_blocking = nuc_wmi_nuc6_set_brightness; + return devm_led_classdev_register(dev, &led->cdev); } From patchwork Sun May 16 10:53:37 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439988 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 7AC29C433ED for ; Sun, 16 May 2021 10:53:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 502B161183 for ; Sun, 16 May 2021 10:53:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230393AbhEPKzL (ORCPT ); Sun, 16 May 2021 06:55:11 -0400 Received: from mail.kernel.org ([198.145.29.99]:47738 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229891AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id CB02461155; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=Citw8kcHjBqb4RX/1vLsy0daJP7QuWPWuADaCtqEKTQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=YXC0WIuoGpkjkt4xUxii7ReuYuTwmBzlyjp6QtY/oKZ4vLKGxliAfn6VtEUsbkVF0 FPjPwghyupmN3KbzCMK15C2elFYVJgkH45Wr82IXrrLdiRmY7G5uSGJHP7NJqfEKpl DaGI/DDwgJZ++Ixdk9s3v3KWxtIaESLf6JIY1Ar5mwkw2U/oD3SEQOqNGnOu3JcJJM Oy7t0iNxSA3Cay2sr7t9/5Z9l4Anb6R4LbeYBYHPmWzlrYUw95LSaPNwYIzxywJFaE 4HpOXh8xdj2tkJw571RzBygP8sIfEivO75Up1bqn5e2/xXWv3yGECY/euxnT2UA4uv L0q93YByeKSBg== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8W-0o; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 09/17] staging: nuc-wmi: Add support to blink behavior for NUC8/10 Date: Sun, 16 May 2021 12:53:37 +0200 Message-Id: <9f7b5e0f3fd726802a9cd3b9b921cc2bb13101ef.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The hardware blink logic works for both Power State and Software controlled LEDs. Just like brightness, there is one different blink behavior per different power state. Due to that, the logic is somewhat more complex than what it would be expected otherwise. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 347 +++++++++++++++++++++++++++--- 1 file changed, 322 insertions(+), 25 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index a365a8603182..8967c8d54dac 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -527,18 +527,30 @@ static ssize_t nuc_wmi_set_brightness_offset(struct device *dev, #define LED_ATTR_RW(_name) \ DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) -#define LED_ATTR_POWER_STATE_RW(_name, offset) \ +#define LED_ATTR_POWER_STATE_RW(_name, _offname, _offset) \ static ssize_t show_##_name(struct device *dev, \ struct device_attribute *attr, \ char *buf) \ { \ - return show_brightness_offset(dev, attr, offset, buf); \ + struct led_classdev *cdev = dev_get_drvdata(dev); \ + struct nuc_nmi_led *led; \ + \ + led = container_of(cdev, struct nuc_nmi_led, cdev); \ + if (led->indicator != LED_IND_POWER_STATE) \ + return -ENODEV; \ + return offset_show_##_offname(dev, attr, _offset, buf); \ } \ static ssize_t store_##_name(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t len) \ + struct device_attribute *attr, \ + const char *buf, size_t len) \ { \ - return store_brightness_offset(dev, attr, offset, buf, len); \ + struct led_classdev *cdev = dev_get_drvdata(dev); \ + struct nuc_nmi_led *led; \ + \ + led = container_of(cdev, struct nuc_nmi_led, cdev); \ + if (led->indicator != LED_IND_POWER_STATE) \ + return -ENODEV; \ + return offset_store_##_offname(dev, attr, _offset, buf, len); \ } \ static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name) @@ -681,7 +693,7 @@ static ssize_t nuc6_store_color(struct device *dev, const char *tmp; int ret, color; - tmp = strsep((char **)&buf, ",\n"); + tmp = strsep((char **)&buf, "\n"); if (led->id == POWER_LED) { for (color = ARRAY_SIZE(nuc6_power_colors)+1; color >= 0; color--) @@ -1000,7 +1012,7 @@ static umode_t nuc_wmi_led_color_is_visible(struct kobject *kobj, } /* Show/store brightness */ -static ssize_t show_brightness_offset(struct device *dev, +static ssize_t offset_show_brightness(struct device *dev, struct device_attribute *attr, u8 offset, char *buf) @@ -1009,9 +1021,6 @@ static ssize_t show_brightness_offset(struct device *dev, struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); int ret; - if (led->indicator != LED_IND_POWER_STATE) - return -ENODEV; - offset *= led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; ret = nuc_wmi_get_brightness_offset(dev, led, offset); @@ -1021,7 +1030,7 @@ static ssize_t show_brightness_offset(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%d\n", ret); } -static ssize_t store_brightness_offset(struct device *dev, +static ssize_t offset_store_brightness(struct device *dev, struct device_attribute *attr, u8 offset, const char *buf, size_t len) @@ -1031,9 +1040,6 @@ static ssize_t store_brightness_offset(struct device *dev, int ret; u8 val; - if (led->indicator != LED_IND_POWER_STATE) - return -ENODEV; - if (kstrtou8(buf, 0, &val) || val > 100) return -EINVAL; @@ -1067,6 +1073,8 @@ static int nuc_wmi_set_brightness(struct led_classdev *cdev, return nuc_wmi_set_brightness_offset(cdev->dev, led, 0, brightness); } +#define cmp_attr_prefix(a, b) strncmp(a, b, strlen(b)) + static umode_t nuc_wmi_led_power_state_is_visible(struct kobject *kobj, struct attribute *attr, int idx) @@ -1074,33 +1082,297 @@ static umode_t nuc_wmi_led_power_state_is_visible(struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct led_classdev *cdev = dev_get_drvdata(dev); struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); - umode_t mode = attr->mode; - if (!strcmp(attr->name, "s0_brightness") || - !strcmp(attr->name, "s3_brightness")) + if (!cmp_attr_prefix(attr->name, "s0_") || + !cmp_attr_prefix(attr->name, "s3_")) return mode; if (led->api_rev == LED_API_REV_0_64) { - if (!strcmp(attr->name, "s5_brightness") || - !strcmp(attr->name, "ready_mode_brightness")) + if (!cmp_attr_prefix(attr->name, "s5_") || + !cmp_attr_prefix(attr->name, "ready_mode_")) return mode; } else { - if (!strcmp(attr->name, "standby_brightness")) + if (!cmp_attr_prefix(attr->name, "standby_")) return mode; } return 0; } +/* Blink */ +static const char * const led_blink_behaviors[] = { + "solid", + "breathing", + "pulsing", + "strobing" +}; + +static const char * const led_blink_frequencies[] = { + "0.1", + "0.2", + "0.3", + "0.4", + "0.5", + "0.6", + "0.7", + "0.8", + "0.9", + "1.0", +}; + +static ssize_t offset_show_blink_behavior(struct device *dev, + struct device_attribute *attr, + u8 offset, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl, val, i, n; + int size = PAGE_SIZE; + char *p = buf; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + offset *= led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + ctrl = led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = ctrl; + + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val = output[0]; + + for (i = 0; i < ARRAY_SIZE(led_blink_behaviors); i++) { + if (i == val) + n = scnprintf(p, size, "[%s] ", led_blink_behaviors[i]); + else + n = scnprintf(p, size, "%s ", led_blink_behaviors[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t offset_store_blink_behavior(struct device *dev, + struct device_attribute *attr, + u8 offset, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + + if (led->id != LED_IND_SOFTWARE && led->id != LED_IND_POWER_STATE) + return -ENODEV; + + offset *= led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + ctrl = led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp = strsep((char **)&buf, "\n"); + + for (val = 0; val < ARRAY_SIZE(led_blink_behaviors); val++) + if (!strcasecmp(tmp, led_blink_behaviors[val])) + break; + + if (val >= ARRAY_SIZE(led_blink_behaviors)) + return -EINVAL; + + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = val; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + +static ssize_t show_blink_behavior(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return offset_show_blink_behavior(dev, attr, 0, buf); +} + +static ssize_t store_blink_behavior(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return offset_store_blink_behavior(dev, attr, 0, buf, len); +} + +static ssize_t offset_show_blink_frequency(struct device *dev, + struct device_attribute *attr, + u8 offset, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS]; + u8 output[NUM_OUTPUT_ARGS]; + int ret, ctrl, val, i, n; + int size = PAGE_SIZE; + char *p = buf; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + offset *= led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + ctrl = led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = ctrl; + + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val = output[0]; + + for (i = 0; i < ARRAY_SIZE(led_blink_frequencies); i++) { + if (i == val) + n = scnprintf(p, size, "[%s] ", led_blink_frequencies[i]); + else + n = scnprintf(p, size, "%s ", led_blink_frequencies[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t offset_store_blink_frequency(struct device *dev, + struct device_attribute *attr, + u8 offset, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator == LED_IND_DISABLE) + return -ENODEV; + + + if (led->id != LED_IND_SOFTWARE && led->id != LED_IND_POWER_STATE) + return -ENODEV; + + offset *= led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + ctrl = led->reg_table[led->indicator][LED_FUNC_BLINK_BEHAVIOR] + offset; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp = strsep((char **)&buf, "\n"); + + for (val = 0; val < ARRAY_SIZE(led_blink_frequencies); val++) + if (!strcasecmp(tmp, led_blink_frequencies[val])) + break; + + if (val >= ARRAY_SIZE(led_blink_frequencies)) + return -EINVAL; + + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = val + 1; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + +static ssize_t show_blink_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return offset_show_blink_frequency(dev, attr, 0, buf); +} + +static ssize_t store_blink_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + return offset_store_blink_frequency(dev, attr, 0, buf, len); +} + +static umode_t nuc_wmi_led_blink_is_visible(struct kobject *kobj, + struct attribute *attr, int idx) +{ + struct device *dev = kobj_to_dev(kobj); + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + umode_t mode = attr->mode; + + // TODO: implement for NUC6 API + if (led->api_rev == LED_API_NUC6) + return 0; + + if (led->id == LED_IND_SOFTWARE) + return mode; + + return 0; +} + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); +static LED_ATTR_RW(blink_behavior); +static LED_ATTR_RW(blink_frequency); -LED_ATTR_POWER_STATE_RW(s0_brightness, 0); -LED_ATTR_POWER_STATE_RW(s3_brightness, 1); -LED_ATTR_POWER_STATE_RW(s5_brightness, 2); // Rev 0.64 -LED_ATTR_POWER_STATE_RW(standby_brightness, 2); // Rev 1.0 -LED_ATTR_POWER_STATE_RW(ready_mode_brightness, 3); // Rev 1.0 +LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); +LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); +LED_ATTR_POWER_STATE_RW(s0_blink_frequency, blink_frequency, 0); +LED_ATTR_POWER_STATE_RW(s3_brightness, brightness, 1); +LED_ATTR_POWER_STATE_RW(s3_blink_behavior, blink_behavior, 1); +LED_ATTR_POWER_STATE_RW(s3_blink_frequency, blink_frequency, 1); + +/* Rev 0.64 */ +LED_ATTR_POWER_STATE_RW(s5_brightness, brightness, 2); +LED_ATTR_POWER_STATE_RW(s5_blink_behavior, blink_behavior, 2); +LED_ATTR_POWER_STATE_RW(s5_blink_frequency, blink_frequency, 2); +LED_ATTR_POWER_STATE_RW(ready_mode_brightness, brightness, 3); +LED_ATTR_POWER_STATE_RW(ready_mode_blink_behavior, blink_behavior, 3); +LED_ATTR_POWER_STATE_RW(ready_mode_blink_frequency, blink_frequency, 3); + +/* Rev 1.0 */ +LED_ATTR_POWER_STATE_RW(standby_brightness, brightness, 2); +LED_ATTR_POWER_STATE_RW(standby_blink_behavior, blink_behavior, 2); +LED_ATTR_POWER_STATE_RW(standby_blink_frequency, blink_frequency, 2); /* * Attributes for LEDs @@ -1121,6 +1393,19 @@ static struct attribute *nuc_wmi_led_power_state_attr[] = { &dev_attr_standby_brightness.attr, &dev_attr_s5_brightness.attr, &dev_attr_ready_mode_brightness.attr, + + &dev_attr_s0_blink_behavior.attr, + &dev_attr_s3_blink_behavior.attr, + &dev_attr_standby_blink_behavior.attr, + &dev_attr_s5_blink_behavior.attr, + &dev_attr_ready_mode_blink_behavior.attr, + + &dev_attr_s0_blink_frequency.attr, + &dev_attr_s3_blink_frequency.attr, + &dev_attr_standby_blink_frequency.attr, + &dev_attr_s5_blink_frequency.attr, + &dev_attr_ready_mode_blink_frequency.attr, + NULL, }; @@ -1139,10 +1424,22 @@ static const struct attribute_group nuc_wmi_led_color_attribute_group = { .attrs = nuc_wmi_led_color_attr, }; +static struct attribute *nuc_wmi_led_blink_behavior_attr[] = { + &dev_attr_blink_behavior.attr, + &dev_attr_blink_frequency.attr, + NULL, +}; + +static const struct attribute_group nuc_wmi_led_blink_attribute_group = { + .is_visible = nuc_wmi_led_blink_is_visible, + .attrs = nuc_wmi_led_blink_behavior_attr, +}; + static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { &nuc_wmi_led_attribute_group, &nuc_wmi_led_power_state_group, &nuc_wmi_led_color_attribute_group, + &nuc_wmi_led_blink_attribute_group, NULL }; From patchwork Sun May 16 10:53:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440369 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CDEDFC43603 for ; Sun, 16 May 2021 10:53:59 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B6E2161183 for ; Sun, 16 May 2021 10:53:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230478AbhEPKzM (ORCPT ); Sun, 16 May 2021 06:55:12 -0400 Received: from mail.kernel.org ([198.145.29.99]:47712 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229600AbhEPKzH (ORCPT ); Sun, 16 May 2021 06:55:07 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id F2971611C2; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=6OJg+K2TbVrabosKaDhINUNxeweXhLVzeNm4qRXzVlA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=KDHxZiC8syfSVl4jRHZlSzHvDQIDBni7K+kT4T9s82fFYgHZ7jnBe2PJn5MzGhn65 N7tOeVPifZsQx/TUSf7MKrL0FFjyTS+3P7h9pZSUE7Y1VLrZNp+UOnRVQuh5stYIgO gKBdI/sQIrf5LF6VvWQLZOvUN7Jpo/Kmd8qEjEQP+xKWHjTn4M0lkL+CLVJKTgZbD5 nXIyhsZH6sfTunkLEgvY01IO+33//imp6086zZgyHal0Jn4xuCTYeOyfn8RS63gH+j VXXXK1obvZ8M5o+HeQcXcdn52X/8Nupw3SemWqbRxsVXeka7aJMIHAm1xGGSdGqfRJ HH9DLn+Zxm/QQ== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8a-23; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 10/17] staging: nuc-wmi: get rid of an unused variable Date: Sun, 16 May 2021 12:53:38 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org drivers/staging/nuc-led/nuc-wmi.c: In function ‘nuc_nmi_cmd’: drivers/staging/nuc-led/nuc-wmi.c:242:6: warning: variable ‘size’ set but not used [-Wunused-but-set-variable] 242 | int size, ret; | ^~~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 8967c8d54dac..78b0a3279f25 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -239,7 +239,7 @@ static int nuc_nmi_cmd(struct device *dev, struct acpi_buffer input; union acpi_object *obj; acpi_status status; - int size, ret; + int ret; u8 *p; input.length = NUM_INPUT_ARGS; @@ -281,8 +281,6 @@ static int nuc_nmi_cmd(struct device *dev, goto err; } - size = NUM_OUTPUT_ARGS + 1; - if (output_args) { memcpy(output_args, p + 1, NUM_OUTPUT_ARGS); From patchwork Sun May 16 10:53:39 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440370 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 80E6FC4360C for ; Sun, 16 May 2021 10:53:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 62954611BF for ; Sun, 16 May 2021 10:53:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230411AbhEPKzL (ORCPT ); Sun, 16 May 2021 06:55:11 -0400 Received: from mail.kernel.org ([198.145.29.99]:47726 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229845AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id EBC5C611AD; Sun, 16 May 2021 10:53:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=60ix63Nu6D2Dul5CtMoNGAh9PQM0tFOKH8GuGgj6JCU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cK1Qh+kUPk5zyPWqPQbCTok4Kujw6wB76kcF/DP8naXCecFTUGbxridA0+3gCtOJd TC4/5/iIWPtwekb+osUK2nCH9Le4T7Q0JLBK5vwgStk9mZd5xSW70UJt+Rr5FSjNJ4 DsmoCtuSG8QyBiHDzibvy+9Y3ys6t5G6XVdeOFeQGUvbFYk0cHzJ3wbjD0TwqKKd+c I864fGlFc5nljNUnRCDf+MPn+WfestQ1nmxTxfiXt3BVkJ6DFCS335Y5n+kErbR0S6 HfWthvfYzhLy/8UW2uyPUdAKL377ABEFQguOYJdrIExFU4Cnf8ZJFtAs2jwI1d4eSz h9K2mPbrGAvXA== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8e-32; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 11/17] staging: nuc-wmi: implement blink control for NUC6 Date: Sun, 16 May 2021 12:53:39 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The blink control logic for NUC6 API is somewhat messy, as it uses a single register for controlling both the blink type and the frequency, using a random order. Let's use the same API as defined for other versions, splitting this setting on two different properties. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 269 +++++++++++++++++++++++++++++- 1 file changed, 267 insertions(+), 2 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 78b0a3279f25..5bc4dcec3ea8 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -713,6 +713,247 @@ static ssize_t nuc6_store_color(struct device *dev, return len; } +enum nuc6_blink_mode_freq { + NUC6_BLINK_MODE_BLINK_1HZ = 0x01, + NUC6_BLINK_MODE_BLINK_0_25HZ = 0x02, + NUC6_BLINK_MODE_FADE_1HZ = 0x03, + NUC6_BLINK_MODE_DONT_BLINK = 0x04, + + /* BIOS equal or upper AY0038 or BN0043 */ + NUC6_BLINK_MODE_BLINK_0_5HZ = 0x05, + NUC6_BLINK_MODE_FADE_0_25HZ = 0x06, + NUC6_BLINK_MODE_FADE_0_5HZ = 0x07 +}; + +enum nuc6_blink_mode { + NUC6_BLINK_MODE_SOLID, + NUC6_BLINK_MODE_BLINK, + NUC6_BLINK_MODE_FADE +}; + +static const char * const nuc6_blink_behavior[] = { + "solid", + "blink", + "fade", +}; + +enum nuc6_blink_freq { + NUC6_BLINK_FREQ_1HZ, + NUC6_BLINK_FREQ_0_5HZ, + NUC6_BLINK_FREQ_0_25HZ, +}; + +static const char * const nuc6_blink_frequency[] = { + "1", + "0.5", + "0.25", +}; + +static int nuc_wmi_nuc6_set_blink(struct device *dev, + struct nuc_nmi_led *led, + int freq, enum nuc6_blink_mode mode) +{ + int val; + + switch(mode) { + case NUC6_BLINK_MODE_SOLID: + val = NUC6_BLINK_MODE_DONT_BLINK; + break; + case NUC6_BLINK_MODE_BLINK: + if (freq == NUC6_BLINK_FREQ_0_25HZ) + val = NUC6_BLINK_MODE_BLINK_0_25HZ; + else if (freq == NUC6_BLINK_FREQ_0_5HZ) + val = NUC6_BLINK_MODE_BLINK_0_5HZ; + else + val = NUC6_BLINK_MODE_BLINK_1HZ; + break; + case NUC6_BLINK_MODE_FADE: + if (freq == NUC6_BLINK_FREQ_0_25HZ) + val = NUC6_BLINK_MODE_FADE_0_25HZ; + else if (freq == NUC6_BLINK_FREQ_0_5HZ) + val = NUC6_BLINK_MODE_FADE_0_5HZ; + else + val = NUC6_BLINK_MODE_FADE_1HZ; + break; + default: + return -EINVAL; + } + + return nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); +} + +static ssize_t nuc6_show_blink_behavior(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + int val = -1, mode = -1, ret, i, n; + int size = PAGE_SIZE; + char *p = buf; + + ret = nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + switch (val) { + case NUC6_BLINK_MODE_BLINK_1HZ: + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_BLINK_0_5HZ: + mode = NUC6_BLINK_MODE_BLINK; + break; + case NUC6_BLINK_MODE_FADE_1HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + mode = NUC6_BLINK_MODE_FADE; + break; + case NUC6_BLINK_MODE_DONT_BLINK: + mode = NUC6_BLINK_MODE_SOLID; + break; + } + + for (i = 0; i < ARRAY_SIZE(nuc6_blink_behavior); i++) { + if (i == mode) + n = scnprintf(p, size, "[%s] ", nuc6_blink_behavior[i]); + else + n = scnprintf(p, size, "%s ", nuc6_blink_behavior[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; + +} + +static ssize_t nuc6_store_blink_behavior(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + int ret, val = -1, freq; + const char *tmp; + + tmp = strsep((char **)&buf, "\n"); + + ret = nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + /* Preserve the frequency */ + switch (val) { + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + freq = NUC6_BLINK_FREQ_0_25HZ; + break; + case NUC6_BLINK_MODE_BLINK_0_5HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + freq = NUC6_BLINK_FREQ_0_5HZ; + break; + default: + freq = NUC6_BLINK_FREQ_1HZ; + break; + } + + for (val = ARRAY_SIZE(nuc6_blink_behavior)+1; val >= 0; val--) + if (!strcasecmp(tmp, nuc6_blink_behavior[val])) + break; + if (val < 0) + return -EINVAL; + + ret = nuc_wmi_nuc6_set_blink(dev, led, val, freq); + if (ret) + return ret; + + return len; +} + +static ssize_t nuc6_show_blink_frequency(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + int val = -1, freq = -1, ret, i, n; + int size = PAGE_SIZE; + char *p = buf; + + ret = nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + switch (val) { + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + freq = NUC6_BLINK_FREQ_0_25HZ; + break; + case NUC6_BLINK_MODE_BLINK_0_5HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + freq = NUC6_BLINK_FREQ_0_5HZ; + break; + default: + freq = NUC6_BLINK_FREQ_1HZ; + } + + for (i = 0; i < ARRAY_SIZE(nuc6_blink_frequency); i++) { + if (i == freq) + n = scnprintf(p, size, "[%s] ", nuc6_blink_frequency[i]); + else + n = scnprintf(p, size, "%s ", nuc6_blink_frequency[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t nuc6_store_blink_frequency(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + enum nuc6_blink_mode mode; + int ret, freq, val = -1; + const char *tmp; + + tmp = strsep((char **)&buf, "\n"); + + ret = nuc_wmi_nuc6_led_get_set(dev, led, NULL, &val, NULL); + if (ret) + return ret; + + /* Preserve the blink mode */ + switch (val) { + case NUC6_BLINK_MODE_BLINK_1HZ: + case NUC6_BLINK_MODE_BLINK_0_25HZ: + case NUC6_BLINK_MODE_BLINK_0_5HZ: + mode = NUC6_BLINK_MODE_BLINK; + break; + case NUC6_BLINK_MODE_FADE_1HZ: + case NUC6_BLINK_MODE_FADE_0_25HZ: + case NUC6_BLINK_MODE_FADE_0_5HZ: + mode = NUC6_BLINK_MODE_FADE; + break; + default: /* setting frequency NUC6_BLINK_MODE_SOLID won't make sense */ + return -EINVAL; + } + + for (freq = ARRAY_SIZE(nuc6_blink_frequency)+1; freq >= 0; freq--) + if (!strcasecmp(tmp, nuc6_blink_frequency[freq])) + break; + if (freq < 0) + return -EINVAL; + + ret = nuc_wmi_nuc6_set_blink(dev, led, mode, freq); + if (ret) + return ret; + + return len; +} + /* Show/change the LED indicator */ static const char * const led_indicators[] = { @@ -1214,6 +1455,12 @@ static ssize_t show_blink_behavior(struct device *dev, struct device_attribute *attr, char *buf) { + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev == LED_API_NUC6) + return nuc6_show_blink_behavior(dev, attr, buf); + return offset_show_blink_behavior(dev, attr, 0, buf); } @@ -1221,6 +1468,12 @@ static ssize_t store_blink_behavior(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev == LED_API_NUC6) + return nuc6_store_blink_behavior(dev, attr, buf, len); + return offset_store_blink_behavior(dev, attr, 0, buf, len); } @@ -1319,6 +1572,12 @@ static ssize_t show_blink_frequency(struct device *dev, struct device_attribute *attr, char *buf) { + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev == LED_API_NUC6) + return nuc6_show_blink_frequency(dev, attr, buf); + return offset_show_blink_frequency(dev, attr, 0, buf); } @@ -1326,6 +1585,12 @@ static ssize_t store_blink_frequency(struct device *dev, struct device_attribute *attr, const char *buf, size_t len) { + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + + if (led->api_rev == LED_API_NUC6) + return nuc6_store_blink_frequency(dev, attr, buf, len); + return offset_store_blink_frequency(dev, attr, 0, buf, len); } @@ -1337,9 +1602,8 @@ static umode_t nuc_wmi_led_blink_is_visible(struct kobject *kobj, struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); umode_t mode = attr->mode; - // TODO: implement for NUC6 API if (led->api_rev == LED_API_NUC6) - return 0; + return mode; if (led->id == LED_IND_SOFTWARE) return mode; @@ -1443,6 +1707,7 @@ static const struct attribute_group *nuc_wmi_led_attribute_groups[] = { static const struct attribute_group *nuc_wmi_nuc6_led_attribute_groups[] = { &nuc_wmi_led_color_attribute_group, + &nuc_wmi_led_blink_attribute_group, NULL }; From patchwork Sun May 16 10:53:40 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439983 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D5E9FC433ED for ; Sun, 16 May 2021 10:54:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B97E761182 for ; Sun, 16 May 2021 10:54:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231421AbhEPKzQ (ORCPT ); Sun, 16 May 2021 06:55:16 -0400 Received: from mail.kernel.org ([198.145.29.99]:47714 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230156AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 2738A61206; Sun, 16 May 2021 10:53:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=nW7fKI5PUZp/UFI+qdts0R8ZO5545PmLjbtP18ZvdUY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=lwK2y20RmkTHDsgizXnSMAd6PWGlj5TCMzfS72fOYQSXFDUIiJZbphFFFLl8Ri+x4 kodfzbhHL/J3Dhd4sVdcHtycssqt7FnSN9W8RbmjgvgmKIKthwkYRdHa11AQ8mOOyS X2x2z6Rg2aYOdPJj07Gn/P6u1l7taF+7gV95IrI1v+GMW3Mn6UGBi6CQsmFZhrpBAr W5DIbegL0Ihpwz+CprlNP1qKI8vaMGhZdaTWjHpTNu90CqTMJFdy++92ENL2T2Xa+l ZPzsgSv3HCe5qP6gsQ/bw5Pgt/jI0X5t/X7M5CElWWwRdm2mqoWXMlGTLUWeld8LVy dyMByQCKcYxrQ== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8i-4w; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 12/17] staging: nuc-wmi: better detect NUC6/NUC7 devices Date: Sun, 16 May 2021 12:53:40 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org There's no documented way to detect if the WMI API is valid, as, when it is not valid, it just returns 4 zeros. However, as having a value of 0x00 for the blinking state is not valid, we can check for it at detection time, in order to disable LEDs control on devices that won't support it. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 5bc4dcec3ea8..1a6e2b17c888 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -312,6 +312,13 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) return ret; } + /* + * Detect if NUC6/NUC7 supports the WMI API by checking the + * returned blink state, as valid values range from 0x01 to 0x07. + */ + if (output[1] == 0x00) + return -ENODEV; + led = &priv->led[priv->num_leds]; led->id = POWER_LED; led->color_type = LED_BLUE_AMBER; @@ -325,6 +332,14 @@ static int nuc_wmi_query_leds_nuc6(struct device *dev) dev_warn(dev, "Get S0 Ring: error %d\n", ret); return ret; } + + /* + * Detect if NUC6/NUC7 supports the WMI API by checking the + * returned blink state, as valid values range from 0x01 to 0x07. + */ + if (output[1] == 0x00) + return -ENODEV; + led = &priv->led[priv->num_leds]; led->id = RING_LED; led->color_type = LED_BLUE_AMBER; From patchwork Sun May 16 10:53:41 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439985 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C032C43460 for ; Sun, 16 May 2021 10:54:01 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 191C161182 for ; Sun, 16 May 2021 10:54:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231258AbhEPKzN (ORCPT ); Sun, 16 May 2021 06:55:13 -0400 Received: from mail.kernel.org ([198.145.29.99]:47796 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230032AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 2A8C161221; Sun, 16 May 2021 10:53:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=Zwfc7j9efHMjOQ95FQowFtkZnRbepFXiueRLmwb0dSU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=h8hK2cTxu3yUhpkVOFxXJ2rZE7FWYPtNo09bb+tPOG1HSmBOa+6mrwqQUeXaNlkgF BniqIJW1AcaIWAzQ9PEXwBuudao0SyKspIrbERhrt7xLuVIKgmfE2jyKFHgsyHAjbC f/7J9g5+FOgijog5s1NAmW7PmBq5bNtl4n8OeO9rsBgIxCMJJiwhysUGJDkjm5fhiN AwC69hh9Sl+NIlnOTfAh9ENMhp0jCGqbQKQRRFRlJG1bQl6VNk/h78MHSevGqI+tas 67pON+wX1GH3mzGWxzzHTfu/kF4VzH6fyb8Gm3OZ3DuE5ZvzDiW7bt6nK5VzXQHrkx vun6WWx9/UhJw== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8m-6c; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 13/17] staging: nuc-led: add support for HDD activity default Date: Sun, 16 May 2021 12:53:41 +0200 Message-Id: <3e6c8001d221f724edc28107dbb8d05bf6a6801f.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org There are two possible values for HDD activity behavior: - 0 Normally off, ON when active - 1 Normally on, OFF when active Implement a logic to set it. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 77 +++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 1a6e2b17c888..68143d45c34c 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -1626,10 +1626,86 @@ static umode_t nuc_wmi_led_blink_is_visible(struct kobject *kobj, return 0; } +/* HDD activity behavior */ +static ssize_t show_hdd_default(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ctrl, ret, val; + + if (led->indicator != LED_IND_HDD_ACTIVITY) + return -EINVAL; + + ctrl = led->reg_table[led->indicator][LED_FUNC_HDD_BEHAVIOR]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = ctrl; + + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val = output[0]; + + if (val == 0) + return scnprintf(buf, PAGE_SIZE, "off\n"); + + return scnprintf(buf, PAGE_SIZE, "on\n"); +} + +static ssize_t store_hdd_default(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator != LED_IND_HDD_ACTIVITY) + return -EINVAL; + + ctrl = led->reg_table[led->indicator][LED_FUNC_HDD_BEHAVIOR]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp = strsep((char **)&buf, "\n"); + if (!strcmp(tmp, "on")) + val = 1; + else if (!strcmp(tmp, "off")) + val = 0; + else + return -EINVAL; + + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = val; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); static LED_ATTR_RW(blink_behavior); static LED_ATTR_RW(blink_frequency); +static LED_ATTR_RW(hdd_default); LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); @@ -1657,6 +1733,7 @@ LED_ATTR_POWER_STATE_RW(standby_blink_frequency, blink_frequency, 2); static struct attribute *nuc_wmi_led_attr[] = { &dev_attr_indicator.attr, + &dev_attr_hdd_default.attr, NULL, }; From patchwork Sun May 16 10:53:42 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440368 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1598EC43461 for ; Sun, 16 May 2021 10:54:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id DECBC61182 for ; Sun, 16 May 2021 10:54:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231287AbhEPKzO (ORCPT ); Sun, 16 May 2021 06:55:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:47792 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229982AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 29F3F6121E; Sun, 16 May 2021 10:53:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=h9vGksfsYN6Uc32fL0WmjObXqS0pXNKpGROEG1V8hCI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fVqYMWjlFEM6FXpHotP/eCe8oIJyI3bhbpgSByvZ2c8zcM3NQBw3rQc4OG5RojroU 9dH9u9ZxpHCwcE8GPcK58IrQpYqdsX48A4VuUsfdH6gIqQ4TCkzfFjhRIOibkfoiOo QgUyOL4HiryvJaidHwvG6XhRw3N0ASBulWLQLzLBDD7rAR9LKDNnV1nOvCQb+tEfZ0 CdUtdyulIYM6f8TwThOhRvfuRoUsRc5vx+mmh/70SbqjJiZ3/l/JWTw/InbpSx25ei vmEwy55e+owxNkPln9OPyozrfBSE1KQKoyJmaSjogwm5JYEWepzjSM5tqw4Ah8Dgp1 eTIA4EJTCXUzw== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8q-8D; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 14/17] staging: nuc-wmi: fix software blink behavior logic Date: Sun, 16 May 2021 12:53:42 +0200 Message-Id: <26d3ab7a03cb83ec56205add6cd80b8738cd96b0.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The is_visible logic for it is plain wrong: 1. it is used only during devnode creation; 2. it was using the wrong field (id, instead of indicator). Fix it. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 68143d45c34c..fab0094a20e4 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -1476,6 +1476,9 @@ static ssize_t show_blink_behavior(struct device *dev, if (led->api_rev == LED_API_NUC6) return nuc6_show_blink_behavior(dev, attr, buf); + if (led->indicator != LED_IND_SOFTWARE) + return -EINVAL; + return offset_show_blink_behavior(dev, attr, 0, buf); } @@ -1489,6 +1492,9 @@ static ssize_t store_blink_behavior(struct device *dev, if (led->api_rev == LED_API_NUC6) return nuc6_store_blink_behavior(dev, attr, buf, len); + if (led->indicator != LED_IND_SOFTWARE) + return -EINVAL; + return offset_store_blink_behavior(dev, attr, 0, buf, len); } @@ -1593,6 +1599,9 @@ static ssize_t show_blink_frequency(struct device *dev, if (led->api_rev == LED_API_NUC6) return nuc6_show_blink_frequency(dev, attr, buf); + if (led->indicator != LED_IND_SOFTWARE) + return -EINVAL; + return offset_show_blink_frequency(dev, attr, 0, buf); } @@ -1606,26 +1615,12 @@ static ssize_t store_blink_frequency(struct device *dev, if (led->api_rev == LED_API_NUC6) return nuc6_store_blink_frequency(dev, attr, buf, len); + if (led->indicator != LED_IND_SOFTWARE) + return -EINVAL; + return offset_store_blink_frequency(dev, attr, 0, buf, len); } -static umode_t nuc_wmi_led_blink_is_visible(struct kobject *kobj, - struct attribute *attr, int idx) -{ - struct device *dev = kobj_to_dev(kobj); - struct led_classdev *cdev = dev_get_drvdata(dev); - struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); - umode_t mode = attr->mode; - - if (led->api_rev == LED_API_NUC6) - return mode; - - if (led->id == LED_IND_SOFTWARE) - return mode; - - return 0; -} - /* HDD activity behavior */ static ssize_t show_hdd_default(struct device *dev, struct device_attribute *attr, @@ -1785,7 +1780,6 @@ static struct attribute *nuc_wmi_led_blink_behavior_attr[] = { }; static const struct attribute_group nuc_wmi_led_blink_attribute_group = { - .is_visible = nuc_wmi_led_blink_is_visible, .attrs = nuc_wmi_led_blink_behavior_attr, }; From patchwork Sun May 16 10:53:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440367 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 47A68C43618 for ; Sun, 16 May 2021 10:54:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 2660B61182 for ; Sun, 16 May 2021 10:54:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231314AbhEPKzO (ORCPT ); Sun, 16 May 2021 06:55:14 -0400 Received: from mail.kernel.org ([198.145.29.99]:47798 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230075AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 265C9611CC; Sun, 16 May 2021 10:53:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=WM2iuSvtezDRaqlgdmB17sPpg7zZn+j42PMcFTrt4bc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Zy3yle/WKZ/2DtE5a1+AK57yCx/N6Fsxeibn9zbKF+5m1B+Fldqt66JDuNQsbAL1B zx+yBoHi40Dd59RRINh/GxSSiGNccluyTFfwQEiCTGZXuEVms0whCcE7R3j2K328Y6 iQ0dRqwCV8nfdMUQdxGylVUhgXiL+rHM+GNOoXoxYhbp1Ueb1naQw74SB/z+Vx1H17 3s58zevf+0x0E1RDkMQWgMl7nZxzCQidgdKQ4KiZBr1I4soAq2WjGYg8PpwxoJ52EW O34XAzT6KUz+gUJZ4AX7L7rijQ3geC5PKPXlz2y4k1WT4MAQPbRodk4nTP3dFmqk9C bmpCEFWpBg5/g== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8u-9X; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 15/17] staging: nuc-wmi: add support for changing the ethernet type indicator Date: Sun, 16 May 2021 12:53:43 +0200 Message-Id: <9cbbdd508f0769221fa43be0c3fb6f7910f5a331.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The Ethernet type indicator can be configured to show the status of LAN1, LAN1 or both. Add support for it. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 89 +++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index fab0094a20e4..9e8164cd77ec 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -1695,12 +1695,100 @@ static ssize_t store_hdd_default(struct device *dev, return len; } +/* Ethernet type */ +static const char * const ethernet_type[] = { + "LAN1", + "LAN2", + "LAN1+LAN2" +}; + +static ssize_t show_ethernet_type(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ctrl, ret, val, i, n; + int size = PAGE_SIZE; + char *p = buf; + + if (led->indicator != LED_IND_ETHERNET) + return -EINVAL; + + ctrl = led->reg_table[led->indicator][LED_FUNC_ETH_TYPE]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = ctrl; + + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val = output[0]; + + for (i = 0; i < ARRAY_SIZE(ethernet_type); i++) { + if (i == val) + n = scnprintf(p, size, "[%s] ", ethernet_type[i]); + else + n = scnprintf(p, size, "%s ", ethernet_type[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t store_ethernet_type(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator != LED_IND_ETHERNET) + return -EINVAL; + + ctrl = led->reg_table[led->indicator][LED_FUNC_ETH_TYPE]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + for (val = 0; val < ARRAY_SIZE(ethernet_type); val++) + if (!strcasecmp(tmp, ethernet_type[val])) + break; + + if (val >= ARRAY_SIZE(ethernet_type)) + return -EINVAL; + + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = val; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); static LED_ATTR_RW(blink_behavior); static LED_ATTR_RW(blink_frequency); static LED_ATTR_RW(hdd_default); +static LED_ATTR_RW(ethernet_type); LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); @@ -1729,6 +1817,7 @@ LED_ATTR_POWER_STATE_RW(standby_blink_frequency, blink_frequency, 2); static struct attribute *nuc_wmi_led_attr[] = { &dev_attr_indicator.attr, &dev_attr_hdd_default.attr, + &dev_attr_ethernet_type.attr, NULL, }; From patchwork Sun May 16 10:53:44 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 439984 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.5 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id BFDA1C433B4 for ; Sun, 16 May 2021 10:54:02 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9B8BE61182 for ; Sun, 16 May 2021 10:54:02 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231387AbhEPKzP (ORCPT ); Sun, 16 May 2021 06:55:15 -0400 Received: from mail.kernel.org ([198.145.29.99]:47712 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230152AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 29A046120D; Sun, 16 May 2021 10:53:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=6H8AU2caE1C+L+ZOJtRM+ecRO1FZ+rCeLy8Yj1PSqfM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=SX9w7hkCLiPkTo+Zq04uxebLUUgPcjy9asbuJ1SwqL30ES+6+w9S8Z96n2DWP1Wn8 /uet8/6RVqsIbGKCgXj3PFQ2JPHyFnRYhvgDstT6Myg3Wfz2hrH/Jk/NanI5fgyC0X DK3oeLJTMEw6Y48gllCSgKPxTwI93zyj97RtuVJ94TmMEccJWbH9PzkfQIXzKqp7PQ 8GOzrTvpos0dNn2jx61snHcBxEyk8ymnGEtEWmUJMuqGoD+Aln7SgA5z975r+44ici QXlV5M5nfgLVqVEq3x/WmDxjFgZ12cGajm3VtJaz340VYfuz3uqa7oBqUNyxpwimNL KjnybdX29qJXQ== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s8y-Am; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 16/17] staging: nuc-wmi: add support for changing the power limit scheme Date: Sun, 16 May 2021 12:53:44 +0200 Message-Id: <10df69ed906079c400d3f262102c8f3f05423243.1621161037.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org The power limit indicator may have 2 behaviors: 1. Its color gradually changes from green to red; 2. It displays a single color Add support for it. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/nuc-wmi.c | 93 +++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 9e8164cd77ec..2d9c49d72703 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -1764,6 +1764,8 @@ static ssize_t store_ethernet_type(struct device *dev, if (!nuc_wmi_test_control(dev, led, ctrl)) return -ENODEV; + tmp = strsep((char **)&buf, "\n"); + for (val = 0; val < ARRAY_SIZE(ethernet_type); val++) if (!strcasecmp(tmp, ethernet_type[val])) break; @@ -1783,12 +1785,102 @@ static ssize_t store_ethernet_type(struct device *dev, return len; } +/* Power Limit Indication scheme */ +static const char * const power_limit_scheme[] = { + "green to red", + "single color" +}; + +static ssize_t show_power_limit_scheme(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + u8 output[NUM_OUTPUT_ARGS]; + int ctrl, ret, val, i, n; + int size = PAGE_SIZE; + char *p = buf; + + if (led->indicator != LED_IND_POWER_LIMIT) + return -EINVAL; + + ctrl = led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + input[0] = LED_NEW_GET_CONTROL_ITEM; + input[1] = led->id; + input[2] = led->indicator; + input[3] = ctrl; + + ret = nuc_nmi_cmd(dev, LED_NEW_GET_STATUS, input, output); + if (ret) + return ret; + + val = output[0]; + + for (i = 0; i < ARRAY_SIZE(power_limit_scheme); i++) { + if (i == val) + n = scnprintf(p, size, "[%s] ", power_limit_scheme[i]); + else + n = scnprintf(p, size, "%s ", power_limit_scheme[i]); + p += n; + size -= n; + } + size -= scnprintf(p, size, "\n"); + + return PAGE_SIZE - size; +} + +static ssize_t store_power_limit_scheme(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t len) +{ + struct led_classdev *cdev = dev_get_drvdata(dev); + struct nuc_nmi_led *led = container_of(cdev, struct nuc_nmi_led, cdev); + u8 input[NUM_INPUT_ARGS] = { 0 }; + int ctrl, val, ret; + const char *tmp; + + if (led->indicator != LED_IND_POWER_LIMIT) + return -EINVAL; + + ctrl = led->reg_table[led->indicator][LED_FUNC_POWER_STATE_NUM_CTRLS]; + + if (!nuc_wmi_test_control(dev, led, ctrl)) + return -ENODEV; + + tmp = strsep((char **)&buf, "\n"); + + for (val = 0; val < ARRAY_SIZE(power_limit_scheme); val++) + if (!strcasecmp(tmp, power_limit_scheme[val])) + break; + + if (val >= ARRAY_SIZE(power_limit_scheme)) + return -EINVAL; + + input[0] = led->id; + input[1] = led->indicator; + input[2] = ctrl; + input[3] = val; + + ret = nuc_nmi_cmd(dev, LED_SET_VALUE, input, NULL); + if (ret) + return ret; + + return len; +} + static LED_ATTR_RW(indicator); static LED_ATTR_RW(color); static LED_ATTR_RW(blink_behavior); static LED_ATTR_RW(blink_frequency); static LED_ATTR_RW(hdd_default); static LED_ATTR_RW(ethernet_type); +static LED_ATTR_RW(power_limit_scheme); LED_ATTR_POWER_STATE_RW(s0_brightness, brightness, 0); LED_ATTR_POWER_STATE_RW(s0_blink_behavior, blink_behavior, 0); @@ -1818,6 +1910,7 @@ static struct attribute *nuc_wmi_led_attr[] = { &dev_attr_indicator.attr, &dev_attr_hdd_default.attr, &dev_attr_ethernet_type.attr, + &dev_attr_power_limit_scheme.attr, NULL, }; From patchwork Sun May 16 10:53:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mauro Carvalho Chehab X-Patchwork-Id: 440365 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-19.3 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id EE6D0C43461 for ; Sun, 16 May 2021 10:54:14 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D34D561185 for ; Sun, 16 May 2021 10:54:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231455AbhEPKzQ (ORCPT ); Sun, 16 May 2021 06:55:16 -0400 Received: from mail.kernel.org ([198.145.29.99]:47724 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230158AbhEPKzI (ORCPT ); Sun, 16 May 2021 06:55:08 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id 5CAC761352; Sun, 16 May 2021 10:53:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1621162433; bh=21CCoTvk0P2nJNZOW0CE5KdGJy4Om6wkSpbdQjM6tQE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Jh0QJfnixOHk8arKkDDHxCVbP5npvVzJVxnUcpLmtf2vx5NPm3v2DwoJuA0iu+k0N Ly/4kjcqVUm+0rrnWc/GpHIEzjoOXPGQOLtAoFinU1rJo54Bs6UJ/mEe/bLcx6iUrH QhVk9XC+JJ9UDFHEBn2cB8T/VxaWoEnI1xydgmfixhnm/lcwgOhElhbGRmLFPfeNU9 0g0Yvc6yIWtkfBo2XRFouGgINFsDC9DmiooFNQ6lMlumoy+3iL5cFSwwcBwC0qR9T3 A7wBnpZA6Ncm7AW8Ll4cRB8Bn2sATVlPdvUDGIiryp6MsTATZ7nJgE4DB0nkq55zgl GpvHyWEnTChOg== Received: by mail.kernel.org with local (Exim 4.94.2) (envelope-from ) id 1liEP9-003s92-C4; Sun, 16 May 2021 12:53:51 +0200 From: Mauro Carvalho Chehab To: gregkh@linuxfoundation.org Cc: linuxarm@huawei.com, mauro.chehab@huawei.com, Mauro Carvalho Chehab , "Pavel Machek" , Mauro Carvalho Chehab , devel@driverdev.osuosl.org, linux-kernel@vger.kernel.org, linux-leds@vger.kernel.org, linux-staging@lists.linux.dev Subject: [PATCH 17/17] staging: nuc-led: update the TODOs Date: Sun, 16 May 2021 12:53:45 +0200 Message-Id: X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Sender: Mauro Carvalho Chehab Precedence: bulk List-ID: X-Mailing-List: linux-leds@vger.kernel.org Now that most functionality were merged at the driver, update its TODO list, and add a "TODO" comment for the two WMI API commands that are currently not implemented. In summary: - on Rev 0.64, command 0x07 (LED_NOTIFICATION) is meant to store all config settings at EEPROM. That doesn't seem to be needed on Skull Canyon, but tests with different hardware would be nice in order to double-check it. Also, maybe Rev 1.00 would make it mandatory; - Rev 1.00 added command 0x08 to switch the LED type (LED_SWITCH_TYPE at the driver's nomenclature) between single color LED and multi color LED). Not sure how this should be properly implemented (if this is the case); - The tests for NUC6 version were using a Skull Canyon NUC. It allowed to check that the driver's logic runs, but it is not enough to see if everything is really working. Tests on NUC6 or NUC7 are required; - On a suspend test, I noticed that some controls were reset to the default at resume time. It is required to check what's happening there and address it properly. - Need to validate the uAPI and document it before moving this driver out of staging. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/nuc-led/TODO | 12 +++++++----- drivers/staging/nuc-led/nuc-wmi.c | 6 ++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/staging/nuc-led/TODO b/drivers/staging/nuc-led/TODO index d5296d7186a7..df6f3f653eb0 100644 --- a/drivers/staging/nuc-led/TODO +++ b/drivers/staging/nuc-led/TODO @@ -1,6 +1,8 @@ -- Add support for 6th gen NUCs, like Skull Canyon -- Improve LED core support to avoid it to try to manage the - LED brightness directly; -- Test it with 8th gen NUCs; -- Add more functionality to the driver; +- Test it with 6th gen and 10th NUCs; +- Add support for LED_NOTIFICATION; +- Add support for LED_SWITCH_TYPE; +- Some LED parameters are changing after returning + from suspend. Need to check what's happening there + (hardware bug?) and ensure that the parameters will + be properly restored after resume. - Stabilize and document its sysfs interface. diff --git a/drivers/staging/nuc-led/nuc-wmi.c b/drivers/staging/nuc-led/nuc-wmi.c index 2d9c49d72703..e87e97d56364 100644 --- a/drivers/staging/nuc-led/nuc-wmi.c +++ b/drivers/staging/nuc-led/nuc-wmi.c @@ -42,16 +42,14 @@ enum led_cmds { LED_OLD_SET_LED = 0x02, /* Rev 0.64 and 1.0 cmds */ - LED_QUERY = 0x03, LED_NEW_GET_STATUS = 0x04, LED_SET_INDICATOR = 0x05, LED_SET_VALUE = 0x06, - LED_NOTIFICATION = 0x07, - LED_SWITCH_TYPE = 0x08, + LED_NOTIFICATION = 0x07, // TODO: add support for it /* Rev 1.0 cmds */ - + LED_SWITCH_TYPE = 0x08, // TODO: add support for it LED_VERSION_CONTROL = 0x09, };