From nobody Fri Dec 19 18:53:55 2025 Received: from mail-pl1-f171.google.com (mail-pl1-f171.google.com [209.85.214.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 430B025F78B; Tue, 8 Apr 2025 01:28:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.171 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744075718; cv=none; b=D2bPkr0sBWJmUzIH3nREdaYGdoN60od64MrDgNlFtI95jGx965jeU7YxdiS75DL0LboLnlbrsJjW9Mv3igsA2LKLjPx3zQA2RTqIChiGzAe4qIrkMND/YtBc+SrzeV8klw9KUK/faykjZsvGxVSk9vxXJ1ci5XDlrMTOCBXSNd0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744075718; c=relaxed/simple; bh=rnNPBXhzEk16Y54/A19e+RJ7y3Q1HPbBOiCMPvbxv3c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=twJOmfKArgNvTHUkHdhquKX+jnruLlYQGcVOtzO2YTR2KVfq4mbXtiRQz+KM2hTqohia63SL0yt4zoz7IrIerHIYS30W1BoBV+cWLmvqUJ5SFog1E5ygu/qJ4i9WJmSuRnL7Q7zQm1d9DCSxQsulDEXM8Nvn20KWvZptZlDD6i8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=biNVmfpf; arc=none smtp.client-ip=209.85.214.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="biNVmfpf" Received: by mail-pl1-f171.google.com with SMTP id d9443c01a7336-22438c356c8so47917175ad.1; Mon, 07 Apr 2025 18:28:35 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1744075715; x=1744680515; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=+Qe/YE4w8xe7KudMW5XZzHk7Nk8IRkaRpKGX2azDFj8=; b=biNVmfpfA+E0kOuvzal8gk1E/dRyg4HKruW0kwRnH3p/AtsUfHT4jOE7pc/wqjt7pp InJbZa6LyUBqN95c8Yy6S2r5Xr/Iwwcw10bL28L7K0e0kzftXcaJIcpNKj9RumzCTN9S bBkJJtIs3qFX667DYnU2PiruOx2ktpB7Io8fMEP+IEIMkV7vlV3WAyNeZ+jnL2Aiq4rw u83ZibGgShiay38kms61iZX7DDlpsmLUmSvuR2i8Ahgb7We5B9IF2AheSVrYknCFqX5S ROP67Vj3NcnrZWC3AZ02wFObBcJDfFx/MF6VlYhHExh+65Lwc0utRRSDiz7mVqTJ63w9 VmUA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1744075715; x=1744680515; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=+Qe/YE4w8xe7KudMW5XZzHk7Nk8IRkaRpKGX2azDFj8=; b=fu7edk3A8EqLCeDD1OPYnDzJeEOLnBV/FCShrwZqAVHNIkWbQmsedqwEwGX7e3DgdB 6NdJoR/vwgOM4KyJIvOVshwBP2faY55+5KAX9Z7dJ+uCWaCH0jgLeZO232W2eKuUf+Pe iArgzqqYaclaWBmtxxbANOEkx09LEXlsZvGNonUWIXwKFQxNASz8SjK1P83JzQAbbEdf /sTGDbetBcZff3fa6LLgDaTUf1HIqTgiJSMS0QcFgvxdm7KVFJ4Vjs1sYJSQqP3o2ymx FfX/8jp21WJP6Sg5pB/ap2W7ZnwRqARIIHSNqW0Q6VyuwqRpgHgg1P+z7Bnuo6c3Y1N7 6QsQ== X-Forwarded-Encrypted: i=1; AJvYcCURMxfMep4pbAXRJtFWAjDPy/ZfXFIY2q7CWMLDLzXnUU1ErOXgd9tgxI2+PJTcfb+wnoEx7oKsnorn5rxa@vger.kernel.org, AJvYcCWjQhPUhqOQibo/tSk4YRcGy7Mpz6S+1XHvxxvujxtJ2DkV5Utpry6XFTITY1BK2Pne7zAUUQYZs+Xyy5ggspeM0/eCBw==@vger.kernel.org, AJvYcCXuLCVNJAj0VYuZW8Rd65PcObBzmd495aeBT0eN7Rj/thWFtRVc5qtF3xXPgdrA5O7GcCWW3HGC5YA=@vger.kernel.org X-Gm-Message-State: AOJu0YzaaiPRIoxVVWVshFJrbbVEM8+jx8JINtGVcjChBKokaafPe5ds aminHzCbKgLsUGkJEo7lYbh3yNR6zUO6RsAM/mpQdvpJYftgxpLQ X-Gm-Gg: ASbGnct7DlcA4XerxcWKfoUNWnG3tk7TmRTnPrvgGRDAiPMCbCX49TuNRRjAGUXzLxt ySXaMfIlGXVp+kDgyuMnZ9iUankJKQ/e9TSoUSmGOyRfRv4Ct489Q9j7ipTWwvquXdV64B72GTs +xkXqztQvPkcaEWJqlrznG8LT92chqXTTXJXVyaWKsy6v+ITktIIryUblz6pvALo0gUl6cfuUQM 6HH9a56DRQ5sZPeRGOPqb2EkNn7CFY8VhU3JjoTku/UIt4C548k9cnDeHay8BpNuHgjstTcL2Ga vxtyOwE43OJEtR4tdHnqNU0g1gc+TvppECUpUPI+bHMO6shXq/CGu41IST3WpvBBnWlNA4GPnC1 i/aqfI5TVxoe0oZEX8zSpR9IhJEyP7nhYsCFso36hDXA= X-Google-Smtp-Source: AGHT+IGEmU3c8ctKbsPJiABeKYQAlwGXSh5hecZsajDEHbqHQ8GM37Sv1QAmzN+2zv29MAZN86jOHw== X-Received: by 2002:a17:902:d4cc:b0:220:e338:8d2 with SMTP id d9443c01a7336-22a8a867491mr193785915ad.21.1744075715254; Mon, 07 Apr 2025 18:28:35 -0700 (PDT) Received: from localhost.localdomain (108-228-232-20.lightspeed.sndgca.sbcglobal.net. [108.228.232.20]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-229785c39c1sm87901255ad.85.2025.04.07.18.28.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Apr 2025 18:28:34 -0700 (PDT) From: "Derek J. Clark" To: Hans de Goede , =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Cc: Armin Wolf , Jonathan Corbet , Mario Limonciello , Luke Jones , Xino Ni , Zhixin Zhang , Mia Shao , Mark Pearson , "Pierre-Loup A . Griffais" , "Cody T . -H . Chiu" , John Martens , "Derek J . Clark" , platform-driver-x86@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [PATCH v5 4/6] platform/x86: Add Lenovo Capability Data 01 WMI Driver Date: Mon, 7 Apr 2025 18:28:13 -0700 Message-ID: <20250408012815.1032357-5-derekjohn.clark@gmail.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250408012815.1032357-1-derekjohn.clark@gmail.com> References: <20250408012815.1032357-1-derekjohn.clark@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Adds lenovo-wmi-capdata01 driver which provides the LENOVO_CAPABILITY_DATA_01 WMI data block that comes on "Other Mode" enabled hardware. Provides an interface for querying if a given attribute is supported by the hardware, as well as its default_value, max_value, min_value, and step increment. Signed-off-by: Derek J. Clark Reviewed-by: Armin Wolf --- v5: - Return to cache at device initialization. On component bind, pass a pointer to lenovo-wmi-other. - Fixes from v4 review. v4: - Make driver data a private struct, remove references from Other Mode driver. - Don't cache data at device initialization. Instead, on component bind, cache the data on a member variable of the Other Mode driver data passed as a void pointer. - Add header file for capdata01 structs. - Add new struct to pass capdata01 array data and array length to Other Mode. v3: - Add as component to lenovo-wmi-other driver. v2: - Use devm_kmalloc to ensure driver can be instanced, remove global reference. - Ensure reverse Christmas tree for all variable declarations. - Remove extra whitespace. - Use guard(mutex) in all mutex instances, global mutex. - Use pr_fmt instead of adding the driver name to each pr_err. - Remove noisy pr_info usage. - Rename capdata_wmi to lenovo_wmi_cd01_priv and cd01_wmi to priv. - Use list to get the lenovo_wmi_cd01_priv instance in lenovo_wmi_capdata01_get as none of the data provided by the macros that will use it can pass a member of the struct for use in container_of. --- MAINTAINERS | 2 + drivers/platform/x86/Kconfig | 4 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/lenovo-wmi-capdata01.c | 168 ++++++++++++++++++++ drivers/platform/x86/lenovo-wmi-capdata01.h | 28 ++++ 5 files changed, 203 insertions(+) create mode 100644 drivers/platform/x86/lenovo-wmi-capdata01.c create mode 100644 drivers/platform/x86/lenovo-wmi-capdata01.h diff --git a/MAINTAINERS b/MAINTAINERS index 6dde75922aaf..56ead241a053 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13164,6 +13164,8 @@ L: platform-driver-x86@vger.kernel.org S: Maintained F: Documentation/wmi/devices/lenovo-wmi-gamezone.rst F: Documentation/wmi/devices/lenovo-wmi-other.rst +F: drivers/platform/x86/lenovo-wmi-capdata01.c +F: drivers/platform/x86/lenovo-wmi-capdata01.h F: drivers/platform/x86/lenovo-wmi-events.c F: drivers/platform/x86/lenovo-wmi-events.h F: drivers/platform/x86/lenovo-wmi-helpers.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 13b8f4ac5dc5..64663667f0cb 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -467,6 +467,10 @@ config LENOVO_WMI_HELPERS tristate depends on ACPI_WMI =20 +config LENOVO_WMI_DATA01 + tristate + depends on ACPI_WMI + config IDEAPAD_LAPTOP tristate "Lenovo IdeaPad Laptop Extras" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index fc039839286a..7a35c77221b7 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_THINKPAD_LMI) +=3D think-lmi.o obj-$(CONFIG_YOGABOOK) +=3D lenovo-yogabook.o obj-$(CONFIG_YT2_1380) +=3D lenovo-yoga-tab2-pro-1380-fastcharger.o obj-$(CONFIG_LENOVO_WMI_CAMERA) +=3D lenovo-wmi-camera.o +obj-$(CONFIG_LENOVO_WMI_DATA01) +=3D lenovo-wmi-capdata01.o obj-$(CONFIG_LENOVO_WMI_EVENTS) +=3D lenovo-wmi-events.o obj-$(CONFIG_LENOVO_WMI_HELPERS) +=3D lenovo-wmi-helpers.o =20 diff --git a/drivers/platform/x86/lenovo-wmi-capdata01.c b/drivers/platform= /x86/lenovo-wmi-capdata01.c new file mode 100644 index 000000000000..a5255e080e87 --- /dev/null +++ b/drivers/platform/x86/lenovo-wmi-capdata01.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Lenovo Capability Data 01 WMI Data Block driver. + * + * Lenovo Capability Data 01 provides information on tunable attributes us= ed by + * the "Other Mode" WMI interface. The data includes if the attribute is + * supported by the hardware, the default_value, max_value, min_value, and= step + * increment. Each attibute has multiple pages, one for each of the thermal + * modes managed by the Gamezone interface. + * + * Copyright(C) 2025 Derek J. Clark + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lenovo-wmi-capdata01.h" + +#define LENOVO_CAPABILITY_DATA_01_GUID "7A8F5407-CB67-4D6E-B547-39B3BE0181= 54" + +struct lwmi_cd01_priv { + struct wmi_device *wdev; + struct cd01_list *list; +}; + +/** + * lwmi_cd01_component_bind() - Bind component to master device. + * @cd01_dev: Pointer to the lenovo-wmi-capdata01 driver parent device. + * @om_dev: Pointer to the lenovo-wmi-other driver parent device. + * @data: capdata01_list object pointer used to return the capability data. + * + * On lenovo-wmi-other's master bind, provide a pointer to the local capda= ta01 + * list. This is used to look up attribute data by the lenovo-wmi-other dr= iver. + * + * Return: 0 on success, or on error. + */ +static int lwmi_cd01_component_bind(struct device *cd01_dev, + struct device *om_dev, void *data) +{ + struct lwmi_cd01_priv *priv =3D dev_get_drvdata(cd01_dev); + struct cd01_list **cd01_list =3D data; + + if (!priv->list) + return -ENODEV; + + *cd01_list =3D priv->list; + + return 0; +} + +static const struct component_ops lwmi_cd01_component_ops =3D { + .bind =3D lwmi_cd01_component_bind, +}; + +/** + * lwmi_cd01_setup() - Cache all WMI data block information + * @priv: lenovo-wmi-capdata01 driver data. + * + * Allocate a cd01_list struct large enough to contain data from all WMI d= ata + * blocks provided by the interface. Then loop through each data block and + * cache the data. + * + * Return: 0 on success, or on error. + */ +static int lwmi_cd01_setup(struct lwmi_cd01_priv *priv) +{ + struct cd01_list *list; + size_t list_size; + int count, idx; + + count =3D wmidev_instance_count(priv->wdev); + list_size =3D struct_size(list, data, count); + + list =3D devm_kzalloc(&priv->wdev->dev, list_size, GFP_KERNEL); + if (!list) + return -ENOMEM; + + list->count =3D count; + + for (idx =3D 0; idx < count; idx++) { + union acpi_object *ret_obj __free(kfree) =3D NULL; + + ret_obj =3D wmidev_block_query(priv->wdev, idx); + if (!ret_obj) + return -ENODEV; + + if (ret_obj->type !=3D ACPI_TYPE_BUFFER || + ret_obj->buffer.length < sizeof(struct capdata01)) + continue; + + memcpy(&list->data[idx], ret_obj->buffer.pointer, + ret_obj->buffer.length); + } + + priv->list =3D list; + + return 0; +} + +static int lwmi_cd01_probe(struct wmi_device *wdev, const void *context) + +{ + struct lwmi_cd01_priv *priv; + int ret; + + priv =3D devm_kzalloc(&wdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->wdev =3D wdev; + dev_set_drvdata(&wdev->dev, priv); + + ret =3D lwmi_cd01_setup(priv); + if (ret) + return ret; + + return component_add(&wdev->dev, &lwmi_cd01_component_ops); +} + +static void lwmi_cd01_remove(struct wmi_device *wdev) +{ + component_del(&wdev->dev, &lwmi_cd01_component_ops); +} + +static const struct wmi_device_id lwmi_cd01_id_table[] =3D { + { LENOVO_CAPABILITY_DATA_01_GUID, NULL }, + {} +}; + +static struct wmi_driver lwmi_cd01_driver =3D { + .driver =3D { + .name =3D "lenovo_wmi_cd01", + .probe_type =3D PROBE_PREFER_ASYNCHRONOUS, + }, + .id_table =3D lwmi_cd01_id_table, + .probe =3D lwmi_cd01_probe, + .remove =3D lwmi_cd01_remove, + .no_singleton =3D true, +}; + +/** + * lwmi_cd01_match() - Match rule for the master driver. + * @dev: Pointer to the capability data 01 parent device. + * @data: Unused void pointer for passing match criteria. + * + * Return: bool. + */ +int lwmi_cd01_match(struct device *dev, void *data) +{ + return dev->driver =3D=3D &lwmi_cd01_driver.driver; +} +EXPORT_SYMBOL_NS_GPL(lwmi_cd01_match, "LENOVO_WMI_CD01"); + +module_wmi_driver(lwmi_cd01_driver); + +MODULE_DEVICE_TABLE(wmi, lwmi_cd01_id_table); +MODULE_AUTHOR("Derek J. Clark "); +MODULE_DESCRIPTION("Lenovo Capability Data 01 WMI Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/platform/x86/lenovo-wmi-capdata01.h b/drivers/platform= /x86/lenovo-wmi-capdata01.h new file mode 100644 index 000000000000..15974ce5e008 --- /dev/null +++ b/drivers/platform/x86/lenovo-wmi-capdata01.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* Copyright(C) 2025 Derek J. Clark */ + +#ifndef _LENOVO_WMI_CAPDATA01_H_ +#define _LENOVO_WMI_CAPDATA01_H_ + +#include + +struct device; + +struct capdata01 { + u32 id; + u32 supported; + u32 default_value; + u32 step; + u32 min_value; + u32 max_value; +}; + +struct cd01_list { + u8 count; + struct capdata01 data[]; +}; + +int lwmi_cd01_match(struct device *dev, void *data); + +#endif /* !_LENOVO_WMI_CAPDATA01_H_ */ --=20 2.49.0