lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <20260121132243.1256019-2-rf@opensource.cirrus.com>
Date: Wed, 21 Jan 2026 13:22:39 +0000
From: Richard Fitzgerald <rf@...nsource.cirrus.com>
To: broonie@...nel.org
Cc: linux-sound@...r.kernel.org, linux-kernel@...r.kernel.org,
        patches@...nsource.cirrus.com
Subject: [PATCH 1/5] ASoC: cs-amp-lib: Support Dell SSIDExV2 UEFI variable

Add a function cs_amp_devm_get_vendor_specific_variant_id() to return
a vendor-specific hardware identifier string (if there is one) and use
it to fetch an identifier from Dell SSIDExV2 UEFI variable content.

Dell use the same PCI SSID on multiple products that might have different
audio hardware and thus need different firmware for the amplifier DSP.
The SSIDExV2 string contains additional system identifiers, and the
second field is a 2-character audio hardware identifier.

There are older Dell models with Cirrus Logic amplifiers that have the
SSIDExV2 UEFI variable but do not have the 2-character audio ID in the
second field. The SSIDExV2 is ignored if the second field is not
2 characters.

Signed-off-by: Richard Fitzgerald <rf@...nsource.cirrus.com>
---
 include/sound/cs-amp-lib.h    |   3 +
 sound/soc/codecs/cs-amp-lib.c | 111 ++++++++++++++++++++++++++++++++++
 2 files changed, 114 insertions(+)

diff --git a/include/sound/cs-amp-lib.h b/include/sound/cs-amp-lib.h
index 61e00017c9aa..e9aa86d76049 100644
--- a/include/sound/cs-amp-lib.h
+++ b/include/sound/cs-amp-lib.h
@@ -58,6 +58,9 @@ int cs_amp_get_efi_calibration_data(struct device *dev, u64 target_uid, int amp_
 int cs_amp_set_efi_calibration_data(struct device *dev, int amp_index, int num_amps,
 				    const struct cirrus_amp_cal_data *in_data);
 int cs_amp_get_vendor_spkid(struct device *dev);
+const char *cs_amp_devm_get_vendor_specific_variant_id(struct device *dev,
+						       int ssid_vendor,
+						       int ssid_device);
 struct dentry *cs_amp_create_debugfs(struct device *dev);
 
 static inline u64 cs_amp_cal_target_u64(const struct cirrus_amp_cal_data *data)
diff --git a/sound/soc/codecs/cs-amp-lib.c b/sound/soc/codecs/cs-amp-lib.c
index b4d183e7501d..9f8c99dfb798 100644
--- a/sound/soc/codecs/cs-amp-lib.c
+++ b/sound/soc/codecs/cs-amp-lib.c
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/mutex.h>
 #include <linux/overflow.h>
+#include <linux/pci_ids.h>
 #include <linux/slab.h>
 #include <linux/timekeeping.h>
 #include <linux/types.h>
@@ -36,6 +37,10 @@
 #define HP_CALIBRATION_EFI_GUID \
 	EFI_GUID(0x53559579, 0x8753, 0x4f5c, 0x91, 0x30, 0xe8, 0x2a, 0xcf, 0xb8, 0xd8, 0x93)
 
+#define DELL_SSIDEXV2_EFI_NAME L"SSIDexV2Data"
+#define DELL_SSIDEXV2_EFI_GUID \
+	EFI_GUID(0x6a5f35df, 0x1432, 0x4656, 0x85, 0x97, 0x31, 0x04, 0xd5, 0xbf, 0x3a, 0xb0)
+
 static const struct cs_amp_lib_cal_efivar {
 	efi_char16_t *name;
 	efi_guid_t *guid;
@@ -304,6 +309,29 @@ static int cs_amp_convert_efi_status(efi_status_t status)
 	}
 }
 
+static void *cs_amp_alloc_get_efi_variable(efi_char16_t *name,
+					   efi_guid_t *guid,
+					   u32 *returned_attr)
+{
+	efi_status_t status;
+	unsigned long size = 0;
+
+	status = cs_amp_get_efi_variable(name, guid, NULL, &size, NULL);
+	if (status != EFI_BUFFER_TOO_SMALL)
+		return ERR_PTR(cs_amp_convert_efi_status(status));
+
+	/* Over-alloc to ensure strings are always NUL-terminated */
+	void *buf __free(kfree) = kzalloc(size + 1, GFP_KERNEL);
+	if (!buf)
+		return ERR_PTR(-ENOMEM);
+
+	status = cs_amp_get_efi_variable(name, guid, returned_attr, &size, buf);
+	if (status != EFI_SUCCESS)
+		return ERR_PTR(cs_amp_convert_efi_status(status));
+
+	return_ptr(buf);
+}
+
 static struct cirrus_amp_efi_data *cs_amp_get_cal_efi_buffer(struct device *dev,
 							     efi_char16_t **name,
 							     efi_guid_t **guid,
@@ -705,6 +733,89 @@ int cs_amp_get_vendor_spkid(struct device *dev)
 }
 EXPORT_SYMBOL_NS_GPL(cs_amp_get_vendor_spkid, "SND_SOC_CS_AMP_LIB");
 
+static const char *cs_amp_devm_get_dell_ssidex(struct device *dev,
+					       int ssid_vendor, int ssid_device)
+{
+	unsigned int hex_prefix;
+	char audio_id[4];
+	char delim;
+	char *p;
+	int ret;
+
+	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE) &&
+	    !IS_ENABLED(CONFIG_SND_SOC_CS_AMP_LIB_TEST))
+		return ERR_PTR(-ENOENT);
+
+	char *ssidex_buf __free(kfree) = cs_amp_alloc_get_efi_variable(DELL_SSIDEXV2_EFI_NAME,
+								       &DELL_SSIDEXV2_EFI_GUID,
+								       NULL);
+	ret = PTR_ERR_OR_ZERO(ssidex_buf);
+	if (ret == -ENOENT)
+		return ERR_PTR(-ENOENT);
+	else if (ret < 0)
+		return ssidex_buf;
+
+	/*
+	 * SSIDExV2 string is a series of underscore delimited fields.
+	 * First field is all or part of the SSID. Second field should be
+	 * a 2-character audio hardware id, followed by other identifiers.
+	 * Older models did not have the 2-character audio id, so reject
+	 * the string if the second field is not 2 characters.
+	 */
+	ret = sscanf(ssidex_buf, "%8x_%2s%c", &hex_prefix, audio_id, &delim);
+	if (ret < 2)
+		return ERR_PTR(-ENOENT);
+
+	if ((ret == 3) && (delim != '_'))
+		return ERR_PTR(-ENOENT);
+
+	if (strlen(audio_id) != 2)
+		return ERR_PTR(-ENOENT);
+
+	p = devm_kstrdup(dev, audio_id, GFP_KERNEL);
+	if (!p)
+		return ERR_PTR(-ENOMEM);
+
+	return p;
+}
+
+/**
+ * cs_amp_devm_get_vendor_specific_variant_id - get variant ID string
+ * @dev:	 pointer to struct device
+ * @ssid_vendor: PCI Subsystem Vendor (-1 if unknown)
+ * @ssid_device: PCI Subsystem Device (-1 if unknown)
+ *
+ * Known vendor-specific hardware identifiers are checked and if one is
+ * found its content is returned as a NUL-terminated string. The returned
+ * string is devm-managed.
+ *
+ * The returned string is not guaranteed to be globally unique.
+ * Generally it should be combined with some other qualifier, such as
+ * PCI SSID, to create a globally unique ID.
+ *
+ * If the caller has a PCI SSID it should pass it in @ssid_vendor and
+ * @ssid_device. If the vendor-spefic ID contains this SSID it will be
+ * stripped from the returned string to prevent duplication.
+ *
+ * If the caller does not have a PCI SSID, pass -1 for @ssid_vendor and
+ * @ssid_device.
+ *
+ * Return:
+ * * a pointer to a devm-managed string
+ * * ERR_PTR(-ENOENT) if no vendor-specific qualifier
+ * * ERR_PTR error value
+ */
+const char *cs_amp_devm_get_vendor_specific_variant_id(struct device *dev,
+						       int ssid_vendor,
+						       int ssid_device)
+{
+	if ((ssid_vendor == PCI_VENDOR_ID_DELL) || (ssid_vendor < 0))
+		return cs_amp_devm_get_dell_ssidex(dev, ssid_vendor, ssid_device);
+
+	return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL_NS_GPL(cs_amp_devm_get_vendor_specific_variant_id, "SND_SOC_CS_AMP_LIB");
+
 /**
  * cs_amp_create_debugfs - create a debugfs directory for a device
  *
-- 
2.47.3


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ