* [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531)
@ 2025-12-15 12:53 DevExalt
[not found] ` <CAJaUH_8A70=_Cb8yCWqJxbjpW-BnK958fExnC1kSgyhVaydbUw@mail.gmail.com>
2026-03-09 9:53 ` Bastien Nocera
0 siblings, 2 replies; 7+ messages in thread
From: DevExalt @ 2025-12-15 12:53 UTC (permalink / raw)
To: jikos, bentiss
Cc: lains, hadess, linux-input, linux-kernel, sari.kreitem, hbarnor,
Baraa Atta (Dev Exalt)
From: "Baraa Atta (Dev Exalt)" <exalt.dev.team@gmail.com>
Add support in the Logitech HID++ driver for the HID++ Multi-Platform
feature (0x4531), which enables HID++ devices to adjust their behavior
based on the host operating system (Linux, ChromeOS, Android).
This patch:
* Adds device IDs for MX Keys S (046d:b378) and Casa Keys (046d:b371).
* Introduces the module parameter "hidpp_platform" to allow selecting a
target platform.
* Detects whether a device implements feature 0x4531.
* Validates that the requested platform is supported by the device.
* Applies the platform index when valid, otherwise leaves the device
unchanged.
* Keeps default behavior when "hidpp_platform" is unset or invalid.
Supported values for hidpp_platform:
Android, Linux, Chrome
TEST=Pair MX Keys S and Casa Keys over Bluetooth and verify:
* Feature 0x4531 is detected.
* Valid platform values are accepted and applied.
* Invalid platform values result in no update.
* Devices without 0x4531 retain default behavior.
* Platform-specific key behavior is observed once applied.
Signed-off-by: Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com>
---
drivers/hid/hid-ids.h | 2 +
drivers/hid/hid-logitech-hidpp.c | 280 +++++++++++++++++++++++++++++++
drivers/hid/hid-quirks.c | 2 +
3 files changed, 284 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index d31711f1aaec..12de1194d7fa 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -866,6 +866,8 @@
#define USB_DEVICE_ID_LOGITECH_T651 0xb00c
#define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309
#define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00
+#define USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD 0xb371
+#define USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD 0xb378
#define USB_DEVICE_ID_LOGITECH_C007 0xc007
#define USB_DEVICE_ID_LOGITECH_C077 0xc077
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index d5011a5d0890..e94daed31981 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -4373,6 +4373,280 @@ static bool hidpp_application_equals(struct hid_device *hdev,
return report && report->application == application;
}
+/* -------------------------------------------------------------------------- */
+/* 0x4531: Multi-Platform Support */
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Some Logitech devices expose the HID++ feature 0x4531 (Multi-Platform) allowing
+ * the host to specify which operating system platform to use on the device. Changing device's
+ * platform may alter the behavior of the device to match the specified platform.
+ */
+
+static char *hidpp_platform;
+module_param(hidpp_platform, charp, 0644);
+MODULE_PARM_DESC(hidpp_platform, "Select host platform type for Logitech HID++ Multi-Platform feature "
+ "0x4531, valid values: (linux|chrome|android). If unset, no "
+ "change is applied.");
+
+#define HIDPP_MULTIPLATFORM_FEAT_ID 0x4531
+#define HIDPP_MULTIPLATFORM_GET_FEATURE_INFO 0x0F
+#define HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR 0x1F
+#define HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM 0x3F
+
+#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX BIT(10)
+#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME BIT(11)
+#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID BIT(12)
+
+struct hidpp_platform_desc {
+ u8 plat_idx;
+ u8 desc_idx;
+ u16 plat_mask;
+};
+
+/**
+ * hidpp_multiplatform_mask_from_str() - Convert platform name to an HID++ platform mask
+ * @pname: Platform name string
+ *
+ * Converts a platform name string to its corresponding HID++ platform mask based on
+ * the Multi-Platform feature specification.
+ *
+ * Return: Platform mask corresponding to @pname on success,
+ * or 0 if @pname is NULL or unsupported.
+ */
+static u16 hidpp_multiplatform_mask_from_str(const char *pname)
+{
+ if (!pname)
+ return 0;
+
+ if (!strcasecmp(pname, "linux"))
+ return HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX;
+ if (!strcasecmp(pname, "chrome"))
+ return HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME;
+ if (!strcasecmp(pname, "android"))
+ return HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID;
+
+ return 0;
+}
+
+/**
+ * hidpp_multiplatform_get_num_pdesc() - Retrieve number of platform descriptors
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @num_desc: Pointer to store the number of platform descriptors
+ *
+ * Retrieves the number of platform descriptors supported by the device through
+ * the Multi-Platform feature and stores it in @num_desc.
+ *
+ * Return: 0 on success, or non-zero on failure.
+ */
+static int hidpp_multiplatform_get_num_pdesc(struct hidpp_device *hidpp,
+ u8 feat_index, u8 *num_desc)
+{
+ int ret;
+ struct hidpp_report response;
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ ret = hidpp_send_fap_command_sync(hidpp, feat_index,
+ HIDPP_MULTIPLATFORM_GET_FEATURE_INFO,
+ NULL, 0, &response);
+ if (ret) {
+ hid_warn(hdev, "Multiplatform: GET_FEATURE_INFO failed (err=%d)", ret);
+ return ret;
+ }
+
+ *num_desc = response.fap.params[3];
+ hid_dbg(hdev, "Multiplatform: Device supports %d platform descriptors", *num_desc);
+
+ return 0;
+}
+
+/**
+ * hidpp_multiplatform_get_platform_desc() - Retrieve a platform descriptor entry
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @platform_idx: Index of the platform descriptor to retrieve
+ * @pdesc: Pointer to store the retrieved platform descriptor
+ *
+ * Retrieves a single platform descriptor identified by @platform_idx from the
+ * device and stores the parsed descriptor fields in @pdesc.
+ *
+ * Return: 0 on success, or non-zero on failure.
+ */
+static int hidpp_multiplatform_get_platform_desc(struct hidpp_device *hidpp, u8 feat_index,
+ u8 platform_idx, struct hidpp_platform_desc *pdesc)
+{
+ int ret;
+ struct hidpp_report response;
+ u8 params[1] = { platform_idx };
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ ret = hidpp_send_fap_command_sync(hidpp, feat_index,
+ HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR,
+ params, sizeof(params), &response);
+
+ if (ret) {
+ hid_warn(hdev,
+ "Multiplatform: GET_PLATFORM_DESCRIPTOR failed for index %d (err=%d)",
+ platform_idx, ret);
+ return ret;
+ }
+
+ pdesc->plat_idx = response.fap.params[0];
+ pdesc->desc_idx = response.fap.params[1];
+ pdesc->plat_mask = get_unaligned_be16(&response.fap.params[2]);
+
+ hid_dbg(hdev,
+ "Multiplatform: descriptor %d: plat_idx=%d, desc_idx=%d, plat_mask=0x%04x",
+ platform_idx, pdesc->plat_idx, pdesc->desc_idx, pdesc->plat_mask);
+
+ return 0;
+}
+
+/**
+ * hidpp_multiplatform_get_platform_index() - Find platform index for a mask
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @plat_mask: Platform mask to search for
+ * @plat_index: Pointer to store the matched platform index
+ *
+ * Iterates through all platform descriptors exposed by the device via the
+ * Multi-Platform feature, retrieving each descriptor and comparing its
+ * platform mask to @plat_mask. A descriptor matches if its mask overlaps with
+ * the requested @plat_mask (i.e. (pdesc.plat_mask & plat_mask) is non-zero).
+ *
+ * When a matching descriptor is found, its platform index (plat_idx) is
+ * written to @plat_index and the function returns success.
+ *
+ * If no descriptor matches, -ENOENT is returned.
+ *
+ * Return: 0 on success; -ENOENT if no matching descriptor exists;
+ * or non-zero on failure.
+ */
+static int hidpp_multiplatform_get_platform_index(struct hidpp_device *hidpp,
+ u8 feat_index, u16 plat_mask,
+ u8 *plat_index)
+{
+ int i;
+ int ret;
+ u8 num_desc;
+ struct hidpp_platform_desc pdesc;
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ ret = hidpp_multiplatform_get_num_pdesc(hidpp, feat_index, &num_desc);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_desc; i++) {
+ ret = hidpp_multiplatform_get_platform_desc(hidpp, feat_index, i, &pdesc);
+ if (ret)
+ return ret;
+
+ if (pdesc.plat_mask & plat_mask) {
+ *plat_index = pdesc.plat_idx;
+ hid_dbg(hdev,
+ "Multiplatform: Selected platform index %d for platform '%s'",
+ *plat_index, hidpp_platform);
+ return 0;
+ }
+ }
+
+ hid_dbg(hdev,
+ "Multiplatform: No matching platform descriptor found for platform '%s'",
+ hidpp_platform);
+ return -ENOENT;
+}
+
+/**
+ * hidpp_multiplatform_update_device_platform() - Update the device platform
+ * @hidpp: Pointer to the hidpp_device instance
+ * @feat_index: Feature index of the Multi-Platform feature
+ * @plat_index: Platform index to set on the device
+ *
+ * Sends the HID++ Multi-Platform 'SET_CURRENT_PLATFORM' command to the device to
+ * update its platform index to @plat_index.
+ *
+ * Return: 0 on success, or non-zero on failure.
+ */
+static int hidpp_multiplatform_update_device_platform(struct hidpp_device *hidpp,
+ u8 feat_index, u8 plat_index)
+{
+ int ret;
+ struct hidpp_report response;
+ /* Byte 0 (hostIndex): 0xFF selects the current host. */
+ u8 params[2] = { 0xFF, plat_index };
+
+ ret = hidpp_send_fap_command_sync(hidpp, feat_index,
+ HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM,
+ params, sizeof(params), &response);
+
+ if (ret)
+ hid_warn(hidpp->hid_dev,
+ "Multiplatform: SET_CURRENT_PLATFORM failed for index %d (err=%d)",
+ plat_index, ret);
+
+ return ret;
+}
+
+/**
+ * hidpp_multiplatform_init() - Apply the HID++ Multi-Platform (0x4531) feature
+ * @hidpp: Pointer to the hidpp_device instance
+ *
+ * Initializes the Multi-Platform feature by selecting the device platform
+ * corresponding to the module parameter @hidpp_platform, if provided.
+ *
+ * The function performs the following steps:
+ * 1. Convert the @hidpp_platform string into a platform mask.
+ * 2. Check whether the device supports the Multi-Platform feature (0x4531).
+ * 3. Look up the device's platform index whose mask matches the host
+ * platform mask.
+ * 4. Apply that platform index to the device via 'SET_CURRENT_PLATFORM'.
+ *
+ * If the module parameter is unset or invalid, or the device does not support
+ * the feature, or no matching platform descriptor is found, the function exits
+ * silently without modifying the device state.
+ *
+ * On success, the device's platform configuration is updated.
+ */
+static void hidpp_multiplatform_init(struct hidpp_device *hidpp)
+{
+ int ret;
+ u8 feat_index;
+ u8 plat_index;
+ u16 host_plat_mask;
+ struct hid_device *hdev = hidpp->hid_dev;
+
+ if (!hidpp_platform)
+ return;
+
+ host_plat_mask = hidpp_multiplatform_mask_from_str(hidpp_platform);
+ if (!host_plat_mask) {
+ hid_warn(hdev,
+ "Multiplatform: Invalid or unsupported platform name '%s'",
+ hidpp_platform);
+ return;
+ }
+
+ ret = hidpp_root_get_feature(hidpp, HIDPP_MULTIPLATFORM_FEAT_ID, &feat_index);
+ if (ret) {
+ hid_warn(hdev,
+ "Multiplatform: Failed to get the HID++ multiplatform feature 0x4531");
+ return;
+ }
+
+ ret = hidpp_multiplatform_get_platform_index(hidpp, feat_index, host_plat_mask,
+ &plat_index);
+ if (ret)
+ return;
+
+ ret = hidpp_multiplatform_update_device_platform(hidpp, feat_index, plat_index);
+ if (ret)
+ return;
+
+ hid_info(hdev,
+ "Multiplatform: Device platform successfully set to '%s'", hidpp_platform);
+}
+
static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct hidpp_device *hidpp;
@@ -4467,6 +4741,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
connect_mask &= ~HID_CONNECT_HIDINPUT;
+ hidpp_multiplatform_init(hidpp);
+
/* Now export the actual inputs and hidraw nodes to the world */
hid_device_io_stop(hdev);
ret = hid_connect(hdev, connect_mask);
@@ -4664,6 +4940,10 @@ static const struct hid_device_id hidpp_devices[] = {
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) },
{ /* MX Anywhere 3SB mouse over Bluetooth */
HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) },
+ { /* Casa Keys keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) },
+ { /* MX Keys S keyboard over Bluetooth */
+ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) },
{}
};
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index c89a015686c0..99ca04b61bda 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -520,6 +520,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
#endif
#if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP)
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) },
#endif
#if IS_ENABLED(CONFIG_HID_MAGICMOUSE)
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
--
2.34.1
^ permalink raw reply related [flat|nested] 7+ messages in thread[parent not found: <CAJaUH_8A70=_Cb8yCWqJxbjpW-BnK958fExnC1kSgyhVaydbUw@mail.gmail.com>]
* Re: [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) [not found] ` <CAJaUH_8A70=_Cb8yCWqJxbjpW-BnK958fExnC1kSgyhVaydbUw@mail.gmail.com> @ 2026-03-08 8:08 ` dev exalt 0 siblings, 0 replies; 7+ messages in thread From: dev exalt @ 2026-03-08 8:08 UTC (permalink / raw) To: jikos, bentiss Cc: lains, hadess, linux-input, linux-kernel, sari.kreitem, hbarnor Dear maintainers, We would like to kindly follow up on this patch sent on Dec 15, 2025, as we haven't received feedback yet. Patch link: https://lore.kernel.org/linux-input/20251215125319.33261-1-exalt.dev.team@gmail.com/T/#u We understand maintainers are busy, so just sending a gentle reminder in case this slipped. Thank you for your time and review. Best regards, Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> On Sun, Mar 8, 2026 at 10:01 AM dev exalt <exalt.dev.team@gmail.com> wrote: > > Dear maintainers, > > > We would like to kindly follow up on this patch sent on Dec 15, 2025, as we haven't received feedback yet. > > Patch link: > https://lore.kernel.org/linux-input/20251215125319.33261-1-exalt.dev.team@gmail.com/T/#u > > We understand maintainers are busy, so just sending a gentle reminder in case this slipped. > > Thank you for your time and review. > > > Best regards, > > Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> > > > On Mon, Dec 15, 2025 at 2:53 PM DevExalt <exalt.dev.team@gmail.com> wrote: >> >> From: "Baraa Atta (Dev Exalt)" <exalt.dev.team@gmail.com> >> >> Add support in the Logitech HID++ driver for the HID++ Multi-Platform >> feature (0x4531), which enables HID++ devices to adjust their behavior >> based on the host operating system (Linux, ChromeOS, Android). >> >> This patch: >> * Adds device IDs for MX Keys S (046d:b378) and Casa Keys (046d:b371). >> * Introduces the module parameter "hidpp_platform" to allow selecting a >> target platform. >> * Detects whether a device implements feature 0x4531. >> * Validates that the requested platform is supported by the device. >> * Applies the platform index when valid, otherwise leaves the device >> unchanged. >> * Keeps default behavior when "hidpp_platform" is unset or invalid. >> >> Supported values for hidpp_platform: >> Android, Linux, Chrome >> >> TEST=Pair MX Keys S and Casa Keys over Bluetooth and verify: >> * Feature 0x4531 is detected. >> * Valid platform values are accepted and applied. >> * Invalid platform values result in no update. >> * Devices without 0x4531 retain default behavior. >> * Platform-specific key behavior is observed once applied. >> >> Signed-off-by: Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> >> --- >> drivers/hid/hid-ids.h | 2 + >> drivers/hid/hid-logitech-hidpp.c | 280 +++++++++++++++++++++++++++++++ >> drivers/hid/hid-quirks.c | 2 + >> 3 files changed, 284 insertions(+) >> >> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h >> index d31711f1aaec..12de1194d7fa 100644 >> --- a/drivers/hid/hid-ids.h >> +++ b/drivers/hid/hid-ids.h >> @@ -866,6 +866,8 @@ >> #define USB_DEVICE_ID_LOGITECH_T651 0xb00c >> #define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 >> #define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00 >> +#define USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD 0xb371 >> +#define USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD 0xb378 >> #define USB_DEVICE_ID_LOGITECH_C007 0xc007 >> #define USB_DEVICE_ID_LOGITECH_C077 0xc077 >> #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 >> diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c >> index d5011a5d0890..e94daed31981 100644 >> --- a/drivers/hid/hid-logitech-hidpp.c >> +++ b/drivers/hid/hid-logitech-hidpp.c >> @@ -4373,6 +4373,280 @@ static bool hidpp_application_equals(struct hid_device *hdev, >> return report && report->application == application; >> } >> >> +/* -------------------------------------------------------------------------- */ >> +/* 0x4531: Multi-Platform Support */ >> +/* -------------------------------------------------------------------------- */ >> + >> +/* >> + * Some Logitech devices expose the HID++ feature 0x4531 (Multi-Platform) allowing >> + * the host to specify which operating system platform to use on the device. Changing device's >> + * platform may alter the behavior of the device to match the specified platform. >> + */ >> + >> +static char *hidpp_platform; >> +module_param(hidpp_platform, charp, 0644); >> +MODULE_PARM_DESC(hidpp_platform, "Select host platform type for Logitech HID++ Multi-Platform feature " >> + "0x4531, valid values: (linux|chrome|android). If unset, no " >> + "change is applied."); >> + >> +#define HIDPP_MULTIPLATFORM_FEAT_ID 0x4531 >> +#define HIDPP_MULTIPLATFORM_GET_FEATURE_INFO 0x0F >> +#define HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR 0x1F >> +#define HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM 0x3F >> + >> +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX BIT(10) >> +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME BIT(11) >> +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID BIT(12) >> + >> +struct hidpp_platform_desc { >> + u8 plat_idx; >> + u8 desc_idx; >> + u16 plat_mask; >> +}; >> + >> +/** >> + * hidpp_multiplatform_mask_from_str() - Convert platform name to an HID++ platform mask >> + * @pname: Platform name string >> + * >> + * Converts a platform name string to its corresponding HID++ platform mask based on >> + * the Multi-Platform feature specification. >> + * >> + * Return: Platform mask corresponding to @pname on success, >> + * or 0 if @pname is NULL or unsupported. >> + */ >> +static u16 hidpp_multiplatform_mask_from_str(const char *pname) >> +{ >> + if (!pname) >> + return 0; >> + >> + if (!strcasecmp(pname, "linux")) >> + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX; >> + if (!strcasecmp(pname, "chrome")) >> + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME; >> + if (!strcasecmp(pname, "android")) >> + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID; >> + >> + return 0; >> +} >> + >> +/** >> + * hidpp_multiplatform_get_num_pdesc() - Retrieve number of platform descriptors >> + * @hidpp: Pointer to the hidpp_device instance >> + * @feat_index: Feature index of the Multi-Platform feature >> + * @num_desc: Pointer to store the number of platform descriptors >> + * >> + * Retrieves the number of platform descriptors supported by the device through >> + * the Multi-Platform feature and stores it in @num_desc. >> + * >> + * Return: 0 on success, or non-zero on failure. >> + */ >> +static int hidpp_multiplatform_get_num_pdesc(struct hidpp_device *hidpp, >> + u8 feat_index, u8 *num_desc) >> +{ >> + int ret; >> + struct hidpp_report response; >> + struct hid_device *hdev = hidpp->hid_dev; >> + >> + ret = hidpp_send_fap_command_sync(hidpp, feat_index, >> + HIDPP_MULTIPLATFORM_GET_FEATURE_INFO, >> + NULL, 0, &response); >> + if (ret) { >> + hid_warn(hdev, "Multiplatform: GET_FEATURE_INFO failed (err=%d)", ret); >> + return ret; >> + } >> + >> + *num_desc = response.fap.params[3]; >> + hid_dbg(hdev, "Multiplatform: Device supports %d platform descriptors", *num_desc); >> + >> + return 0; >> +} >> + >> +/** >> + * hidpp_multiplatform_get_platform_desc() - Retrieve a platform descriptor entry >> + * @hidpp: Pointer to the hidpp_device instance >> + * @feat_index: Feature index of the Multi-Platform feature >> + * @platform_idx: Index of the platform descriptor to retrieve >> + * @pdesc: Pointer to store the retrieved platform descriptor >> + * >> + * Retrieves a single platform descriptor identified by @platform_idx from the >> + * device and stores the parsed descriptor fields in @pdesc. >> + * >> + * Return: 0 on success, or non-zero on failure. >> + */ >> +static int hidpp_multiplatform_get_platform_desc(struct hidpp_device *hidpp, u8 feat_index, >> + u8 platform_idx, struct hidpp_platform_desc *pdesc) >> +{ >> + int ret; >> + struct hidpp_report response; >> + u8 params[1] = { platform_idx }; >> + struct hid_device *hdev = hidpp->hid_dev; >> + >> + ret = hidpp_send_fap_command_sync(hidpp, feat_index, >> + HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR, >> + params, sizeof(params), &response); >> + >> + if (ret) { >> + hid_warn(hdev, >> + "Multiplatform: GET_PLATFORM_DESCRIPTOR failed for index %d (err=%d)", >> + platform_idx, ret); >> + return ret; >> + } >> + >> + pdesc->plat_idx = response.fap.params[0]; >> + pdesc->desc_idx = response.fap.params[1]; >> + pdesc->plat_mask = get_unaligned_be16(&response.fap.params[2]); >> + >> + hid_dbg(hdev, >> + "Multiplatform: descriptor %d: plat_idx=%d, desc_idx=%d, plat_mask=0x%04x", >> + platform_idx, pdesc->plat_idx, pdesc->desc_idx, pdesc->plat_mask); >> + >> + return 0; >> +} >> + >> +/** >> + * hidpp_multiplatform_get_platform_index() - Find platform index for a mask >> + * @hidpp: Pointer to the hidpp_device instance >> + * @feat_index: Feature index of the Multi-Platform feature >> + * @plat_mask: Platform mask to search for >> + * @plat_index: Pointer to store the matched platform index >> + * >> + * Iterates through all platform descriptors exposed by the device via the >> + * Multi-Platform feature, retrieving each descriptor and comparing its >> + * platform mask to @plat_mask. A descriptor matches if its mask overlaps with >> + * the requested @plat_mask (i.e. (pdesc.plat_mask & plat_mask) is non-zero). >> + * >> + * When a matching descriptor is found, its platform index (plat_idx) is >> + * written to @plat_index and the function returns success. >> + * >> + * If no descriptor matches, -ENOENT is returned. >> + * >> + * Return: 0 on success; -ENOENT if no matching descriptor exists; >> + * or non-zero on failure. >> + */ >> +static int hidpp_multiplatform_get_platform_index(struct hidpp_device *hidpp, >> + u8 feat_index, u16 plat_mask, >> + u8 *plat_index) >> +{ >> + int i; >> + int ret; >> + u8 num_desc; >> + struct hidpp_platform_desc pdesc; >> + struct hid_device *hdev = hidpp->hid_dev; >> + >> + ret = hidpp_multiplatform_get_num_pdesc(hidpp, feat_index, &num_desc); >> + if (ret) >> + return ret; >> + >> + for (i = 0; i < num_desc; i++) { >> + ret = hidpp_multiplatform_get_platform_desc(hidpp, feat_index, i, &pdesc); >> + if (ret) >> + return ret; >> + >> + if (pdesc.plat_mask & plat_mask) { >> + *plat_index = pdesc.plat_idx; >> + hid_dbg(hdev, >> + "Multiplatform: Selected platform index %d for platform '%s'", >> + *plat_index, hidpp_platform); >> + return 0; >> + } >> + } >> + >> + hid_dbg(hdev, >> + "Multiplatform: No matching platform descriptor found for platform '%s'", >> + hidpp_platform); >> + return -ENOENT; >> +} >> + >> +/** >> + * hidpp_multiplatform_update_device_platform() - Update the device platform >> + * @hidpp: Pointer to the hidpp_device instance >> + * @feat_index: Feature index of the Multi-Platform feature >> + * @plat_index: Platform index to set on the device >> + * >> + * Sends the HID++ Multi-Platform 'SET_CURRENT_PLATFORM' command to the device to >> + * update its platform index to @plat_index. >> + * >> + * Return: 0 on success, or non-zero on failure. >> + */ >> +static int hidpp_multiplatform_update_device_platform(struct hidpp_device *hidpp, >> + u8 feat_index, u8 plat_index) >> +{ >> + int ret; >> + struct hidpp_report response; >> + /* Byte 0 (hostIndex): 0xFF selects the current host. */ >> + u8 params[2] = { 0xFF, plat_index }; >> + >> + ret = hidpp_send_fap_command_sync(hidpp, feat_index, >> + HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM, >> + params, sizeof(params), &response); >> + >> + if (ret) >> + hid_warn(hidpp->hid_dev, >> + "Multiplatform: SET_CURRENT_PLATFORM failed for index %d (err=%d)", >> + plat_index, ret); >> + >> + return ret; >> +} >> + >> +/** >> + * hidpp_multiplatform_init() - Apply the HID++ Multi-Platform (0x4531) feature >> + * @hidpp: Pointer to the hidpp_device instance >> + * >> + * Initializes the Multi-Platform feature by selecting the device platform >> + * corresponding to the module parameter @hidpp_platform, if provided. >> + * >> + * The function performs the following steps: >> + * 1. Convert the @hidpp_platform string into a platform mask. >> + * 2. Check whether the device supports the Multi-Platform feature (0x4531). >> + * 3. Look up the device's platform index whose mask matches the host >> + * platform mask. >> + * 4. Apply that platform index to the device via 'SET_CURRENT_PLATFORM'. >> + * >> + * If the module parameter is unset or invalid, or the device does not support >> + * the feature, or no matching platform descriptor is found, the function exits >> + * silently without modifying the device state. >> + * >> + * On success, the device's platform configuration is updated. >> + */ >> +static void hidpp_multiplatform_init(struct hidpp_device *hidpp) >> +{ >> + int ret; >> + u8 feat_index; >> + u8 plat_index; >> + u16 host_plat_mask; >> + struct hid_device *hdev = hidpp->hid_dev; >> + >> + if (!hidpp_platform) >> + return; >> + >> + host_plat_mask = hidpp_multiplatform_mask_from_str(hidpp_platform); >> + if (!host_plat_mask) { >> + hid_warn(hdev, >> + "Multiplatform: Invalid or unsupported platform name '%s'", >> + hidpp_platform); >> + return; >> + } >> + >> + ret = hidpp_root_get_feature(hidpp, HIDPP_MULTIPLATFORM_FEAT_ID, &feat_index); >> + if (ret) { >> + hid_warn(hdev, >> + "Multiplatform: Failed to get the HID++ multiplatform feature 0x4531"); >> + return; >> + } >> + >> + ret = hidpp_multiplatform_get_platform_index(hidpp, feat_index, host_plat_mask, >> + &plat_index); >> + if (ret) >> + return; >> + >> + ret = hidpp_multiplatform_update_device_platform(hidpp, feat_index, plat_index); >> + if (ret) >> + return; >> + >> + hid_info(hdev, >> + "Multiplatform: Device platform successfully set to '%s'", hidpp_platform); >> +} >> + >> static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) >> { >> struct hidpp_device *hidpp; >> @@ -4467,6 +4741,8 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) >> if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) >> connect_mask &= ~HID_CONNECT_HIDINPUT; >> >> + hidpp_multiplatform_init(hidpp); >> + >> /* Now export the actual inputs and hidraw nodes to the world */ >> hid_device_io_stop(hdev); >> ret = hid_connect(hdev, connect_mask); >> @@ -4664,6 +4940,10 @@ static const struct hid_device_id hidpp_devices[] = { >> HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) }, >> { /* MX Anywhere 3SB mouse over Bluetooth */ >> HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, >> + { /* Casa Keys keyboard over Bluetooth */ >> + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, >> + { /* MX Keys S keyboard over Bluetooth */ >> + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, >> {} >> }; >> >> diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c >> index c89a015686c0..99ca04b61bda 100644 >> --- a/drivers/hid/hid-quirks.c >> +++ b/drivers/hid/hid-quirks.c >> @@ -520,6 +520,8 @@ static const struct hid_device_id hid_have_special_driver[] = { >> #endif >> #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP) >> { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) }, >> + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, >> + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, >> #endif >> #if IS_ENABLED(CONFIG_HID_MAGICMOUSE) >> { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, >> -- >> 2.34.1 >> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) 2025-12-15 12:53 [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) DevExalt [not found] ` <CAJaUH_8A70=_Cb8yCWqJxbjpW-BnK958fExnC1kSgyhVaydbUw@mail.gmail.com> @ 2026-03-09 9:53 ` Bastien Nocera 2026-03-19 10:05 ` dev exalt 1 sibling, 1 reply; 7+ messages in thread From: Bastien Nocera @ 2026-03-09 9:53 UTC (permalink / raw) To: DevExalt, jikos, bentiss Cc: lains, linux-input, linux-kernel, sari.kreitem, hbarnor Hey, Sorry for not looking at this earlier, it slipped through the cracks as it arrived on the mailing-list as I was away. On Mon, 2025-12-15 at 14:53 +0200, DevExalt wrote: > From: "Baraa Atta (Dev Exalt)" <exalt.dev.team@gmail.com> > > Add support in the Logitech HID++ driver for the HID++ Multi-Platform > feature (0x4531), which enables HID++ devices to adjust their > behavior > based on the host operating system (Linux, ChromeOS, Android). Can you please explain what the feature actually does ? (the Logitech docs say "Set the right keyboard layout for your computer operating system" and mention that some multimedia keys are inoperable unless a compatible OS is set). > > This patch: > * Adds device IDs for MX Keys S (046d:b378) and Casa Keys > (046d:b371). > * Introduces the module parameter "hidpp_platform" to allow > selecting a > target platform. > * Detects whether a device implements feature 0x4531. > * Validates that the requested platform is supported by the device. > * Applies the platform index when valid, otherwise leaves the device > unchanged. > * Keeps default behavior when "hidpp_platform" is unset or invalid. Can you explain the benefits of setting this module parameter, compared to using the keyboard shortcuts to switch to a specific OS configuration? What happens when 2 Logitech devices with different supported OSes are used? > Supported values for hidpp_platform: > Android, Linux, Chrome Any reason why there aren't more supported OSes? The Logitech docs[1] lists: WebOS iOS MacOS Android Chrome Linux WinEmb Windows Tizen as possible values. [1]: https://drive.google.com/file/d/1KyiBA5m_5V1s6jQ9eQrgRJN0SbbbI9_I/view I recently got a K980 which has this functionality, it only documents Windows, macOS and Chrome, but Solaar also lists Linux as an option. So my questions would be: - why not support the whole range of possible OSes in this option? - why is it a module option instead of, say, a sysfs attribute that could be changed per device? - why not implement this in user-space through a udev callout? Cheers > > TEST=Pair MX Keys S and Casa Keys over Bluetooth and verify: > * Feature 0x4531 is detected. > * Valid platform values are accepted and applied. > * Invalid platform values result in no update. > * Devices without 0x4531 retain default behavior. > * Platform-specific key behavior is observed once applied. > > Signed-off-by: Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> > --- > drivers/hid/hid-ids.h | 2 + > drivers/hid/hid-logitech-hidpp.c | 280 > +++++++++++++++++++++++++++++++ > drivers/hid/hid-quirks.c | 2 + > 3 files changed, 284 insertions(+) > > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index d31711f1aaec..12de1194d7fa 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -866,6 +866,8 @@ > #define USB_DEVICE_ID_LOGITECH_T651 0xb00c > #define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 > #define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00 > +#define USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD 0xb371 > +#define USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD 0xb378 > #define USB_DEVICE_ID_LOGITECH_C007 0xc007 > #define USB_DEVICE_ID_LOGITECH_C077 0xc077 > #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid- > logitech-hidpp.c > index d5011a5d0890..e94daed31981 100644 > --- a/drivers/hid/hid-logitech-hidpp.c > +++ b/drivers/hid/hid-logitech-hidpp.c > @@ -4373,6 +4373,280 @@ static bool hidpp_application_equals(struct > hid_device *hdev, > return report && report->application == application; > } > > +/* ----------------------------------------------------------------- > --------- */ > +/* 0x4531: Multi-Platform > Support */ > +/* ----------------------------------------------------------------- > --------- */ > + > +/* > + * Some Logitech devices expose the HID++ feature 0x4531 (Multi- > Platform) allowing > + * the host to specify which operating system platform to use on the > device. Changing device's > + * platform may alter the behavior of the device to match the > specified platform. > + */ > + > +static char *hidpp_platform; > +module_param(hidpp_platform, charp, 0644); > +MODULE_PARM_DESC(hidpp_platform, "Select host platform type for > Logitech HID++ Multi-Platform feature " > + "0x4531, valid values: (linux|chrome|android). If > unset, no " > + "change is applied."); > + > +#define HIDPP_MULTIPLATFORM_FEAT_ID 0x4531 > +#define HIDPP_MULTIPLATFORM_GET_FEATURE_INFO 0x0F > +#define HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR 0x1F > +#define HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM 0x3F > + > +#define > HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX BIT(10) > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME BIT(11) > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID BIT(12) > + > +struct hidpp_platform_desc { > + u8 plat_idx; > + u8 desc_idx; > + u16 plat_mask; > +}; > + > +/** > + * hidpp_multiplatform_mask_from_str() - Convert platform name to an > HID++ platform mask > + * @pname: Platform name string > + * > + * Converts a platform name string to its corresponding HID++ > platform mask based on > + * the Multi-Platform feature specification. > + * > + * Return: Platform mask corresponding to @pname on success, > + * or 0 if @pname is NULL or unsupported. > + */ > +static u16 hidpp_multiplatform_mask_from_str(const char *pname) > +{ > + if (!pname) > + return 0; > + > + if (!strcasecmp(pname, "linux")) > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX; > + if (!strcasecmp(pname, "chrome")) > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME; > + if (!strcasecmp(pname, "android")) > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID; > + > + return 0; > +} > + > +/** > + * hidpp_multiplatform_get_num_pdesc() - Retrieve number of platform > descriptors > + * @hidpp: Pointer to the hidpp_device instance > + * @feat_index: Feature index of the Multi-Platform feature > + * @num_desc: Pointer to store the number of platform descriptors > + * > + * Retrieves the number of platform descriptors supported by the > device through > + * the Multi-Platform feature and stores it in @num_desc. > + * > + * Return: 0 on success, or non-zero on failure. > + */ > +static int hidpp_multiplatform_get_num_pdesc(struct hidpp_device > *hidpp, > + u8 feat_index, u8 > *num_desc) > +{ > + int ret; > + struct hidpp_report response; > + struct hid_device *hdev = hidpp->hid_dev; > + > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > + > HIDPP_MULTIPLATFORM_GET_FEATURE_INFO, > + NULL, 0, &response); > + if (ret) { > + hid_warn(hdev, "Multiplatform: GET_FEATURE_INFO > failed (err=%d)", ret); > + return ret; > + } > + > + *num_desc = response.fap.params[3]; > + hid_dbg(hdev, "Multiplatform: Device supports %d platform > descriptors", *num_desc); > + > + return 0; > +} > + > +/** > + * hidpp_multiplatform_get_platform_desc() - Retrieve a platform > descriptor entry > + * @hidpp: Pointer to the hidpp_device instance > + * @feat_index: Feature index of the Multi-Platform feature > + * @platform_idx: Index of the platform descriptor to retrieve > + * @pdesc: Pointer to store the retrieved platform descriptor > + * > + * Retrieves a single platform descriptor identified by > @platform_idx from the > + * device and stores the parsed descriptor fields in @pdesc. > + * > + * Return: 0 on success, or non-zero on failure. > + */ > +static int hidpp_multiplatform_get_platform_desc(struct hidpp_device > *hidpp, u8 feat_index, > + u8 platform_idx, > struct hidpp_platform_desc *pdesc) > +{ > + int ret; > + struct hidpp_report response; > + u8 params[1] = { platform_idx }; > + struct hid_device *hdev = hidpp->hid_dev; > + > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > + > HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR, > + params, sizeof(params), > &response); > + > + if (ret) { > + hid_warn(hdev, > + "Multiplatform: GET_PLATFORM_DESCRIPTOR > failed for index %d (err=%d)", > + platform_idx, ret); > + return ret; > + } > + > + pdesc->plat_idx = response.fap.params[0]; > + pdesc->desc_idx = response.fap.params[1]; > + pdesc->plat_mask = > get_unaligned_be16(&response.fap.params[2]); > + > + hid_dbg(hdev, > + "Multiplatform: descriptor %d: plat_idx=%d, > desc_idx=%d, plat_mask=0x%04x", > + platform_idx, pdesc->plat_idx, pdesc->desc_idx, > pdesc->plat_mask); > + > + return 0; > +} > + > +/** > + * hidpp_multiplatform_get_platform_index() - Find platform index > for a mask > + * @hidpp: Pointer to the hidpp_device instance > + * @feat_index: Feature index of the Multi-Platform feature > + * @plat_mask: Platform mask to search for > + * @plat_index: Pointer to store the matched platform index > + * > + * Iterates through all platform descriptors exposed by the device > via the > + * Multi-Platform feature, retrieving each descriptor and comparing > its > + * platform mask to @plat_mask. A descriptor matches if its mask > overlaps with > + * the requested @plat_mask (i.e. (pdesc.plat_mask & plat_mask) is > non-zero). > + * > + * When a matching descriptor is found, its platform index > (plat_idx) is > + * written to @plat_index and the function returns success. > + * > + * If no descriptor matches, -ENOENT is returned. > + * > + * Return: 0 on success; -ENOENT if no matching descriptor exists; > + * or non-zero on failure. > + */ > +static int hidpp_multiplatform_get_platform_index(struct > hidpp_device *hidpp, > + u8 feat_index, u16 > plat_mask, > + u8 *plat_index) > +{ > + int i; > + int ret; > + u8 num_desc; > + struct hidpp_platform_desc pdesc; > + struct hid_device *hdev = hidpp->hid_dev; > + > + ret = hidpp_multiplatform_get_num_pdesc(hidpp, feat_index, > &num_desc); > + if (ret) > + return ret; > + > + for (i = 0; i < num_desc; i++) { > + ret = hidpp_multiplatform_get_platform_desc(hidpp, > feat_index, i, &pdesc); > + if (ret) > + return ret; > + > + if (pdesc.plat_mask & plat_mask) { > + *plat_index = pdesc.plat_idx; > + hid_dbg(hdev, > + "Multiplatform: Selected platform > index %d for platform '%s'", > + *plat_index, hidpp_platform); > + return 0; > + } > + } > + > + hid_dbg(hdev, > + "Multiplatform: No matching platform descriptor > found for platform '%s'", > + hidpp_platform); > + return -ENOENT; > +} > + > +/** > + * hidpp_multiplatform_update_device_platform() - Update the device > platform > + * @hidpp: Pointer to the hidpp_device instance > + * @feat_index: Feature index of the Multi-Platform feature > + * @plat_index: Platform index to set on the device > + * > + * Sends the HID++ Multi-Platform 'SET_CURRENT_PLATFORM' command to > the device to > + * update its platform index to @plat_index. > + * > + * Return: 0 on success, or non-zero on failure. > + */ > +static int hidpp_multiplatform_update_device_platform(struct > hidpp_device *hidpp, > + u8 feat_index, > u8 plat_index) > +{ > + int ret; > + struct hidpp_report response; > + /* Byte 0 (hostIndex): 0xFF selects the current host. */ > + u8 params[2] = { 0xFF, plat_index }; > + > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > + > HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM, > + params, sizeof(params), > &response); > + > + if (ret) > + hid_warn(hidpp->hid_dev, > + "Multiplatform: SET_CURRENT_PLATFORM failed > for index %d (err=%d)", > + plat_index, ret); > + > + return ret; > +} > + > +/** > + * hidpp_multiplatform_init() - Apply the HID++ Multi-Platform > (0x4531) feature > + * @hidpp: Pointer to the hidpp_device instance > + * > + * Initializes the Multi-Platform feature by selecting the device > platform > + * corresponding to the module parameter @hidpp_platform, if > provided. > + * > + * The function performs the following steps: > + * 1. Convert the @hidpp_platform string into a platform mask. > + * 2. Check whether the device supports the Multi-Platform feature > (0x4531). > + * 3. Look up the device's platform index whose mask matches the > host > + * platform mask. > + * 4. Apply that platform index to the device via > 'SET_CURRENT_PLATFORM'. > + * > + * If the module parameter is unset or invalid, or the device does > not support > + * the feature, or no matching platform descriptor is found, the > function exits > + * silently without modifying the device state. > + * > + * On success, the device's platform configuration is updated. > + */ > +static void hidpp_multiplatform_init(struct hidpp_device *hidpp) > +{ > + int ret; > + u8 feat_index; > + u8 plat_index; > + u16 host_plat_mask; > + struct hid_device *hdev = hidpp->hid_dev; > + > + if (!hidpp_platform) > + return; > + > + host_plat_mask = > hidpp_multiplatform_mask_from_str(hidpp_platform); > + if (!host_plat_mask) { > + hid_warn(hdev, > + "Multiplatform: Invalid or unsupported > platform name '%s'", > + hidpp_platform); > + return; > + } > + > + ret = hidpp_root_get_feature(hidpp, > HIDPP_MULTIPLATFORM_FEAT_ID, &feat_index); > + if (ret) { > + hid_warn(hdev, > + "Multiplatform: Failed to get the HID++ > multiplatform feature 0x4531"); > + return; > + } > + > + ret = hidpp_multiplatform_get_platform_index(hidpp, > feat_index, host_plat_mask, > + &plat_index); > + if (ret) > + return; > + > + ret = hidpp_multiplatform_update_device_platform(hidpp, > feat_index, plat_index); > + if (ret) > + return; > + > + hid_info(hdev, > + "Multiplatform: Device platform successfully set to > '%s'", hidpp_platform); > +} > + > static int hidpp_probe(struct hid_device *hdev, const struct > hid_device_id *id) > { > struct hidpp_device *hidpp; > @@ -4467,6 +4741,8 @@ static int hidpp_probe(struct hid_device *hdev, > const struct hid_device_id *id) > if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) > connect_mask &= ~HID_CONNECT_HIDINPUT; > > + hidpp_multiplatform_init(hidpp); > + > /* Now export the actual inputs and hidraw nodes to the > world */ > hid_device_io_stop(hdev); > ret = hid_connect(hdev, connect_mask); > @@ -4664,6 +4940,10 @@ static const struct hid_device_id > hidpp_devices[] = { > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) }, > { /* MX Anywhere 3SB mouse over Bluetooth */ > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, > + { /* Casa Keys keyboard over Bluetooth */ > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > + { /* MX Keys S keyboard over Bluetooth */ > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > {} > }; > > diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c > index c89a015686c0..99ca04b61bda 100644 > --- a/drivers/hid/hid-quirks.c > +++ b/drivers/hid/hid-quirks.c > @@ -520,6 +520,8 @@ static const struct hid_device_id > hid_have_special_driver[] = { > #endif > #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP) > { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, > USB_DEVICE_ID_LOGITECH_G920_WHEEL) }, > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > #endif > #if IS_ENABLED(CONFIG_HID_MAGICMOUSE) > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, > USB_DEVICE_ID_APPLE_MAGICMOUSE) }, ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) 2026-03-09 9:53 ` Bastien Nocera @ 2026-03-19 10:05 ` dev exalt 2026-05-10 6:36 ` dev exalt 0 siblings, 1 reply; 7+ messages in thread From: dev exalt @ 2026-03-19 10:05 UTC (permalink / raw) To: Bastien Nocera Cc: jikos, bentiss, lains, linux-input, linux-kernel, sari.kreitem, hbarnor Hi Bastien, Thanks for the review. Please see our responses inline below. On Mon, Mar 9, 2026 at 11:53 AM Bastien Nocera <hadess@hadess.net> wrote: > > Hey, > > Sorry for not looking at this earlier, it slipped through the cracks as > it arrived on the mailing-list as I was away. > > On Mon, 2025-12-15 at 14:53 +0200, DevExalt wrote: > > From: "Baraa Atta (Dev Exalt)" <exalt.dev.team@gmail.com> > > > > Add support in the Logitech HID++ driver for the HID++ Multi-Platform > > feature (0x4531), which enables HID++ devices to adjust their > > behavior > > based on the host operating system (Linux, ChromeOS, Android). > > Can you please explain what the feature actually does ? (the Logitech > docs say "Set the right keyboard layout for your computer operating > system" and mention that some multimedia keys are inoperable unless a > compatible OS is set). The HID++ Multi-Platform feature (0x4531) allows a device to select a platform profile that determines how the device firmware behaves for a specific operating system. In practice, this affects how certain keys and functions are exposed to the host. Depending on the selected platform, the device may emit different HID usages or key combinations for the same physical key. For example, on the Logitech MX Keys S keyboard a specific key produces different events depending on the configured platform. When the platform is set to Linux the key generates the combination Shift + Ctrl + Alt + Meta + Space, while when the platform is set to Chrome the same key generates a dedicated Emoji key event (HID usage code 585). The exact behavioral differences are device-specific and defined by the device firmware. > > > > > This patch: > > * Adds device IDs for MX Keys S (046d:b378) and Casa Keys > > (046d:b371). > > * Introduces the module parameter "hidpp_platform" to allow > > selecting a > > target platform. > > * Detects whether a device implements feature 0x4531. > > * Validates that the requested platform is supported by the device. > > * Applies the platform index when valid, otherwise leaves the device > > unchanged. > > * Keeps default behavior when "hidpp_platform" is unset or invalid. > > Can you explain the benefits of setting this module parameter, compared > to using the keyboard shortcuts to switch to a specific OS > configuration? The distribution can configure the parameter and have the OS configure the device automatically without user interaction. Devices will just work as expected out of the box. Users can still override it using the keyboard shortcut. > > What happens when 2 Logitech devices with different supported OSes are > used? If a device does not support the platform specified through the module parameter, the driver does not modify that device and its default platform configuration remains unchanged. During initialization, the driver queries the device for the list of supported platform descriptors exposed by the HID++ Multi-Platform feature (0x4531). The requested platform is only applied if the device advertises support for a compatible descriptor. For example, if two devices are connected and the module parameter is set to linux, a device that supports the Linux platform descriptor will have its platform updated accordingly, causing its firmware behavior to switch to the Linux profile. A device that does not advertise support for the Linux platform will not be modified and will continue operating on its default configuration. > > > Supported values for hidpp_platform: > > Android, Linux, Chrome > > Any reason why there aren't more supported OSes? > > The Logitech docs[1] lists: > WebOS iOS MacOS Android Chrome Linux WinEmb Windows Tizen > as possible values. > > [1]: > https://drive.google.com/file/d/1KyiBA5m_5V1s6jQ9eQrgRJN0SbbbI9_I/view > > I recently got a K980 which has this functionality, it only documents > Windows, macOS and Chrome, but Solaar also lists Linux as an option. > > So my questions would be: > - why not support the whole range of possible OSes in this option? Our initial focus during development was primarily on Android, and we subsequently added Linux and Chrome. However, if it is preferred for completeness, we are happy to add the rest of supported OS platforms listed in the documentation. > - why is it a module option instead of, say, a sysfs attribute that > could be changed per device? > - why not implement this in user-space through a udev callout? The module parameter was initially chosen to provide a simple, system-wide default that distributions can configure at boot. This ensures the devices work out of the box without relying on user interaction. Following your question, we can also add a per-device sysfs attribute alongside the module parameter. This hybrid approach accommodates compatibility with all systems, since udev is not supported by all distributions. > > Cheers > > > > > TEST=Pair MX Keys S and Casa Keys over Bluetooth and verify: > > * Feature 0x4531 is detected. > > * Valid platform values are accepted and applied. > > * Invalid platform values result in no update. > > * Devices without 0x4531 retain default behavior. > > * Platform-specific key behavior is observed once applied. > > > > Signed-off-by: Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> > > --- > > drivers/hid/hid-ids.h | 2 + > > drivers/hid/hid-logitech-hidpp.c | 280 > > +++++++++++++++++++++++++++++++ > > drivers/hid/hid-quirks.c | 2 + > > 3 files changed, 284 insertions(+) > > > > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > > index d31711f1aaec..12de1194d7fa 100644 > > --- a/drivers/hid/hid-ids.h > > +++ b/drivers/hid/hid-ids.h > > @@ -866,6 +866,8 @@ > > #define USB_DEVICE_ID_LOGITECH_T651 0xb00c > > #define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 > > #define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00 > > +#define USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD 0xb371 > > +#define USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD 0xb378 > > #define USB_DEVICE_ID_LOGITECH_C007 0xc007 > > #define USB_DEVICE_ID_LOGITECH_C077 0xc077 > > #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 > > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid- > > logitech-hidpp.c > > index d5011a5d0890..e94daed31981 100644 > > --- a/drivers/hid/hid-logitech-hidpp.c > > +++ b/drivers/hid/hid-logitech-hidpp.c > > @@ -4373,6 +4373,280 @@ static bool hidpp_application_equals(struct > > hid_device *hdev, > > return report && report->application == application; > > } > > > > +/* ----------------------------------------------------------------- > > --------- */ > > +/* 0x4531: Multi-Platform > > Support */ > > +/* ----------------------------------------------------------------- > > --------- */ > > + > > +/* > > + * Some Logitech devices expose the HID++ feature 0x4531 (Multi- > > Platform) allowing > > + * the host to specify which operating system platform to use on the > > device. Changing device's > > + * platform may alter the behavior of the device to match the > > specified platform. > > + */ > > + > > +static char *hidpp_platform; > > +module_param(hidpp_platform, charp, 0644); > > +MODULE_PARM_DESC(hidpp_platform, "Select host platform type for > > Logitech HID++ Multi-Platform feature " > > + "0x4531, valid values: (linux|chrome|android). If > > unset, no " > > + "change is applied."); > > + > > +#define HIDPP_MULTIPLATFORM_FEAT_ID 0x4531 > > +#define HIDPP_MULTIPLATFORM_GET_FEATURE_INFO 0x0F > > +#define HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR 0x1F > > +#define HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM 0x3F > > + > > +#define > > HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX BIT(10) > > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME BIT(11) > > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID BIT(12) > > + > > +struct hidpp_platform_desc { > > + u8 plat_idx; > > + u8 desc_idx; > > + u16 plat_mask; > > +}; > > + > > +/** > > + * hidpp_multiplatform_mask_from_str() - Convert platform name to an > > HID++ platform mask > > + * @pname: Platform name string > > + * > > + * Converts a platform name string to its corresponding HID++ > > platform mask based on > > + * the Multi-Platform feature specification. > > + * > > + * Return: Platform mask corresponding to @pname on success, > > + * or 0 if @pname is NULL or unsupported. > > + */ > > +static u16 hidpp_multiplatform_mask_from_str(const char *pname) > > +{ > > + if (!pname) > > + return 0; > > + > > + if (!strcasecmp(pname, "linux")) > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX; > > + if (!strcasecmp(pname, "chrome")) > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME; > > + if (!strcasecmp(pname, "android")) > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID; > > + > > + return 0; > > +} > > + > > +/** > > + * hidpp_multiplatform_get_num_pdesc() - Retrieve number of platform > > descriptors > > + * @hidpp: Pointer to the hidpp_device instance > > + * @feat_index: Feature index of the Multi-Platform feature > > + * @num_desc: Pointer to store the number of platform descriptors > > + * > > + * Retrieves the number of platform descriptors supported by the > > device through > > + * the Multi-Platform feature and stores it in @num_desc. > > + * > > + * Return: 0 on success, or non-zero on failure. > > + */ > > +static int hidpp_multiplatform_get_num_pdesc(struct hidpp_device > > *hidpp, > > + u8 feat_index, u8 > > *num_desc) > > +{ > > + int ret; > > + struct hidpp_report response; > > + struct hid_device *hdev = hidpp->hid_dev; > > + > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > + > > HIDPP_MULTIPLATFORM_GET_FEATURE_INFO, > > + NULL, 0, &response); > > + if (ret) { > > + hid_warn(hdev, "Multiplatform: GET_FEATURE_INFO > > failed (err=%d)", ret); > > + return ret; > > + } > > + > > + *num_desc = response.fap.params[3]; > > + hid_dbg(hdev, "Multiplatform: Device supports %d platform > > descriptors", *num_desc); > > + > > + return 0; > > +} > > + > > +/** > > + * hidpp_multiplatform_get_platform_desc() - Retrieve a platform > > descriptor entry > > + * @hidpp: Pointer to the hidpp_device instance > > + * @feat_index: Feature index of the Multi-Platform feature > > + * @platform_idx: Index of the platform descriptor to retrieve > > + * @pdesc: Pointer to store the retrieved platform descriptor > > + * > > + * Retrieves a single platform descriptor identified by > > @platform_idx from the > > + * device and stores the parsed descriptor fields in @pdesc. > > + * > > + * Return: 0 on success, or non-zero on failure. > > + */ > > +static int hidpp_multiplatform_get_platform_desc(struct hidpp_device > > *hidpp, u8 feat_index, > > + u8 platform_idx, > > struct hidpp_platform_desc *pdesc) > > +{ > > + int ret; > > + struct hidpp_report response; > > + u8 params[1] = { platform_idx }; > > + struct hid_device *hdev = hidpp->hid_dev; > > + > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > + > > HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR, > > + params, sizeof(params), > > &response); > > + > > + if (ret) { > > + hid_warn(hdev, > > + "Multiplatform: GET_PLATFORM_DESCRIPTOR > > failed for index %d (err=%d)", > > + platform_idx, ret); > > + return ret; > > + } > > + > > + pdesc->plat_idx = response.fap.params[0]; > > + pdesc->desc_idx = response.fap.params[1]; > > + pdesc->plat_mask = > > get_unaligned_be16(&response.fap.params[2]); > > + > > + hid_dbg(hdev, > > + "Multiplatform: descriptor %d: plat_idx=%d, > > desc_idx=%d, plat_mask=0x%04x", > > + platform_idx, pdesc->plat_idx, pdesc->desc_idx, > > pdesc->plat_mask); > > + > > + return 0; > > +} > > + > > +/** > > + * hidpp_multiplatform_get_platform_index() - Find platform index > > for a mask > > + * @hidpp: Pointer to the hidpp_device instance > > + * @feat_index: Feature index of the Multi-Platform feature > > + * @plat_mask: Platform mask to search for > > + * @plat_index: Pointer to store the matched platform index > > + * > > + * Iterates through all platform descriptors exposed by the device > > via the > > + * Multi-Platform feature, retrieving each descriptor and comparing > > its > > + * platform mask to @plat_mask. A descriptor matches if its mask > > overlaps with > > + * the requested @plat_mask (i.e. (pdesc.plat_mask & plat_mask) is > > non-zero). > > + * > > + * When a matching descriptor is found, its platform index > > (plat_idx) is > > + * written to @plat_index and the function returns success. > > + * > > + * If no descriptor matches, -ENOENT is returned. > > + * > > + * Return: 0 on success; -ENOENT if no matching descriptor exists; > > + * or non-zero on failure. > > + */ > > +static int hidpp_multiplatform_get_platform_index(struct > > hidpp_device *hidpp, > > + u8 feat_index, u16 > > plat_mask, > > + u8 *plat_index) > > +{ > > + int i; > > + int ret; > > + u8 num_desc; > > + struct hidpp_platform_desc pdesc; > > + struct hid_device *hdev = hidpp->hid_dev; > > + > > + ret = hidpp_multiplatform_get_num_pdesc(hidpp, feat_index, > > &num_desc); > > + if (ret) > > + return ret; > > + > > + for (i = 0; i < num_desc; i++) { > > + ret = hidpp_multiplatform_get_platform_desc(hidpp, > > feat_index, i, &pdesc); > > + if (ret) > > + return ret; > > + > > + if (pdesc.plat_mask & plat_mask) { > > + *plat_index = pdesc.plat_idx; > > + hid_dbg(hdev, > > + "Multiplatform: Selected platform > > index %d for platform '%s'", > > + *plat_index, hidpp_platform); > > + return 0; > > + } > > + } > > + > > + hid_dbg(hdev, > > + "Multiplatform: No matching platform descriptor > > found for platform '%s'", > > + hidpp_platform); > > + return -ENOENT; > > +} > > + > > +/** > > + * hidpp_multiplatform_update_device_platform() - Update the device > > platform > > + * @hidpp: Pointer to the hidpp_device instance > > + * @feat_index: Feature index of the Multi-Platform feature > > + * @plat_index: Platform index to set on the device > > + * > > + * Sends the HID++ Multi-Platform 'SET_CURRENT_PLATFORM' command to > > the device to > > + * update its platform index to @plat_index. > > + * > > + * Return: 0 on success, or non-zero on failure. > > + */ > > +static int hidpp_multiplatform_update_device_platform(struct > > hidpp_device *hidpp, > > + u8 feat_index, > > u8 plat_index) > > +{ > > + int ret; > > + struct hidpp_report response; > > + /* Byte 0 (hostIndex): 0xFF selects the current host. */ > > + u8 params[2] = { 0xFF, plat_index }; > > + > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > + > > HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM, > > + params, sizeof(params), > > &response); > > + > > + if (ret) > > + hid_warn(hidpp->hid_dev, > > + "Multiplatform: SET_CURRENT_PLATFORM failed > > for index %d (err=%d)", > > + plat_index, ret); > > + > > + return ret; > > +} > > + > > +/** > > + * hidpp_multiplatform_init() - Apply the HID++ Multi-Platform > > (0x4531) feature > > + * @hidpp: Pointer to the hidpp_device instance > > + * > > + * Initializes the Multi-Platform feature by selecting the device > > platform > > + * corresponding to the module parameter @hidpp_platform, if > > provided. > > + * > > + * The function performs the following steps: > > + * 1. Convert the @hidpp_platform string into a platform mask. > > + * 2. Check whether the device supports the Multi-Platform feature > > (0x4531). > > + * 3. Look up the device's platform index whose mask matches the > > host > > + * platform mask. > > + * 4. Apply that platform index to the device via > > 'SET_CURRENT_PLATFORM'. > > + * > > + * If the module parameter is unset or invalid, or the device does > > not support > > + * the feature, or no matching platform descriptor is found, the > > function exits > > + * silently without modifying the device state. > > + * > > + * On success, the device's platform configuration is updated. > > + */ > > +static void hidpp_multiplatform_init(struct hidpp_device *hidpp) > > +{ > > + int ret; > > + u8 feat_index; > > + u8 plat_index; > > + u16 host_plat_mask; > > + struct hid_device *hdev = hidpp->hid_dev; > > + > > + if (!hidpp_platform) > > + return; > > + > > + host_plat_mask = > > hidpp_multiplatform_mask_from_str(hidpp_platform); > > + if (!host_plat_mask) { > > + hid_warn(hdev, > > + "Multiplatform: Invalid or unsupported > > platform name '%s'", > > + hidpp_platform); > > + return; > > + } > > + > > + ret = hidpp_root_get_feature(hidpp, > > HIDPP_MULTIPLATFORM_FEAT_ID, &feat_index); > > + if (ret) { > > + hid_warn(hdev, > > + "Multiplatform: Failed to get the HID++ > > multiplatform feature 0x4531"); > > + return; > > + } > > + > > + ret = hidpp_multiplatform_get_platform_index(hidpp, > > feat_index, host_plat_mask, > > + &plat_index); > > + if (ret) > > + return; > > + > > + ret = hidpp_multiplatform_update_device_platform(hidpp, > > feat_index, plat_index); > > + if (ret) > > + return; > > + > > + hid_info(hdev, > > + "Multiplatform: Device platform successfully set to > > '%s'", hidpp_platform); > > +} > > + > > static int hidpp_probe(struct hid_device *hdev, const struct > > hid_device_id *id) > > { > > struct hidpp_device *hidpp; > > @@ -4467,6 +4741,8 @@ static int hidpp_probe(struct hid_device *hdev, > > const struct hid_device_id *id) > > if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) > > connect_mask &= ~HID_CONNECT_HIDINPUT; > > > > + hidpp_multiplatform_init(hidpp); > > + > > /* Now export the actual inputs and hidraw nodes to the > > world */ > > hid_device_io_stop(hdev); > > ret = hid_connect(hdev, connect_mask); > > @@ -4664,6 +4940,10 @@ static const struct hid_device_id > > hidpp_devices[] = { > > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) }, > > { /* MX Anywhere 3SB mouse over Bluetooth */ > > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, > > + { /* Casa Keys keyboard over Bluetooth */ > > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > > + { /* MX Keys S keyboard over Bluetooth */ > > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > > {} > > }; > > > > diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c > > index c89a015686c0..99ca04b61bda 100644 > > --- a/drivers/hid/hid-quirks.c > > +++ b/drivers/hid/hid-quirks.c > > @@ -520,6 +520,8 @@ static const struct hid_device_id > > hid_have_special_driver[] = { > > #endif > > #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP) > > { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, > > USB_DEVICE_ID_LOGITECH_G920_WHEEL) }, > > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > > #endif > > #if IS_ENABLED(CONFIG_HID_MAGICMOUSE) > > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, > > USB_DEVICE_ID_APPLE_MAGICMOUSE) }, Thanks, Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) 2026-03-19 10:05 ` dev exalt @ 2026-05-10 6:36 ` dev exalt 2026-05-21 9:27 ` dev exalt 0 siblings, 1 reply; 7+ messages in thread From: dev exalt @ 2026-05-10 6:36 UTC (permalink / raw) To: Bastien Nocera Cc: jikos, bentiss, lains, linux-input, linux-kernel, sari.kreitem, hbarnor Hi Bastien, Just following up on this thread in case you had a chance to review our latest response. Would you be OK with us proceeding with the implementation and preparing a v2 patch based on it? Thanks, Baraa On Thu, Mar 19, 2026 at 12:05 PM dev exalt <exalt.dev.team@gmail.com> wrote: > > Hi Bastien, > > Thanks for the review. Please see our responses inline below. > > On Mon, Mar 9, 2026 at 11:53 AM Bastien Nocera <hadess@hadess.net> wrote: > > > > Hey, > > > > Sorry for not looking at this earlier, it slipped through the cracks as > > it arrived on the mailing-list as I was away. > > > > On Mon, 2025-12-15 at 14:53 +0200, DevExalt wrote: > > > From: "Baraa Atta (Dev Exalt)" <exalt.dev.team@gmail.com> > > > > > > Add support in the Logitech HID++ driver for the HID++ Multi-Platform > > > feature (0x4531), which enables HID++ devices to adjust their > > > behavior > > > based on the host operating system (Linux, ChromeOS, Android). > > > > Can you please explain what the feature actually does ? (the Logitech > > docs say "Set the right keyboard layout for your computer operating > > system" and mention that some multimedia keys are inoperable unless a > > compatible OS is set). > > The HID++ Multi-Platform feature (0x4531) allows a device to select a > platform profile that determines how the device firmware behaves for a > specific operating system. > > In practice, this affects how certain keys and functions are exposed > to the host. Depending on the selected platform, the device may emit > different HID usages or key combinations for the same physical key. > > For example, on the Logitech MX Keys S keyboard a specific key > produces different events depending on the configured platform. When > the platform is set to Linux the key generates the combination Shift + > Ctrl + Alt + Meta + Space, while when the platform is set to Chrome > the same key generates a dedicated Emoji key event (HID usage code > 585). > > The exact behavioral differences are device-specific and defined by > the device firmware. > > > > > > > > > This patch: > > > * Adds device IDs for MX Keys S (046d:b378) and Casa Keys > > > (046d:b371). > > > * Introduces the module parameter "hidpp_platform" to allow > > > selecting a > > > target platform. > > > * Detects whether a device implements feature 0x4531. > > > * Validates that the requested platform is supported by the device. > > > * Applies the platform index when valid, otherwise leaves the device > > > unchanged. > > > * Keeps default behavior when "hidpp_platform" is unset or invalid. > > > > Can you explain the benefits of setting this module parameter, compared > > to using the keyboard shortcuts to switch to a specific OS > > configuration? > > The distribution can configure the parameter and have the OS configure > the device automatically without user interaction. Devices will just > work as expected out of the box. Users can still override it using the > keyboard shortcut. > > > > > What happens when 2 Logitech devices with different supported OSes are > > used? > > If a device does not support the platform specified through the module > parameter, the driver does not modify that device and its default > platform configuration remains unchanged. > > During initialization, the driver queries the device for the list of > supported platform descriptors exposed by the HID++ Multi-Platform > feature (0x4531). The requested platform is only applied if the device > advertises support for a compatible descriptor. > > For example, if two devices are connected and the module parameter is > set to linux, a device that supports the Linux platform descriptor > will have its platform updated accordingly, causing its firmware > behavior to switch to the Linux profile. A device that does not > advertise support for the Linux platform will not be modified and will > continue operating on its default configuration. > > > > > > Supported values for hidpp_platform: > > > Android, Linux, Chrome > > > > Any reason why there aren't more supported OSes? > > > > The Logitech docs[1] lists: > > WebOS iOS MacOS Android Chrome Linux WinEmb Windows Tizen > > as possible values. > > > > [1]: > > https://drive.google.com/file/d/1KyiBA5m_5V1s6jQ9eQrgRJN0SbbbI9_I/view > > > > I recently got a K980 which has this functionality, it only documents > > Windows, macOS and Chrome, but Solaar also lists Linux as an option. > > > > So my questions would be: > > - why not support the whole range of possible OSes in this option? > > Our initial focus during development was primarily on Android, and we > subsequently added Linux and Chrome. However, if it is preferred for > completeness, we are happy to add the rest of supported OS platforms > listed in the documentation. > > > - why is it a module option instead of, say, a sysfs attribute that > > could be changed per device? > > - why not implement this in user-space through a udev callout? > > The module parameter was initially chosen to provide a simple, > system-wide default that distributions can configure at boot. This > ensures the devices work out of the box without relying on user > interaction. > > Following your question, we can also add a per-device sysfs attribute > alongside the module parameter. This hybrid approach accommodates > compatibility with all systems, since udev is not supported by all > distributions. > > > > > Cheers > > > > > > > > TEST=Pair MX Keys S and Casa Keys over Bluetooth and verify: > > > * Feature 0x4531 is detected. > > > * Valid platform values are accepted and applied. > > > * Invalid platform values result in no update. > > > * Devices without 0x4531 retain default behavior. > > > * Platform-specific key behavior is observed once applied. > > > > > > Signed-off-by: Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> > > > --- > > > drivers/hid/hid-ids.h | 2 + > > > drivers/hid/hid-logitech-hidpp.c | 280 > > > +++++++++++++++++++++++++++++++ > > > drivers/hid/hid-quirks.c | 2 + > > > 3 files changed, 284 insertions(+) > > > > > > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > > > index d31711f1aaec..12de1194d7fa 100644 > > > --- a/drivers/hid/hid-ids.h > > > +++ b/drivers/hid/hid-ids.h > > > @@ -866,6 +866,8 @@ > > > #define USB_DEVICE_ID_LOGITECH_T651 0xb00c > > > #define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 > > > #define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00 > > > +#define USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD 0xb371 > > > +#define USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD 0xb378 > > > #define USB_DEVICE_ID_LOGITECH_C007 0xc007 > > > #define USB_DEVICE_ID_LOGITECH_C077 0xc077 > > > #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 > > > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid- > > > logitech-hidpp.c > > > index d5011a5d0890..e94daed31981 100644 > > > --- a/drivers/hid/hid-logitech-hidpp.c > > > +++ b/drivers/hid/hid-logitech-hidpp.c > > > @@ -4373,6 +4373,280 @@ static bool hidpp_application_equals(struct > > > hid_device *hdev, > > > return report && report->application == application; > > > } > > > > > > +/* ----------------------------------------------------------------- > > > --------- */ > > > +/* 0x4531: Multi-Platform > > > Support */ > > > +/* ----------------------------------------------------------------- > > > --------- */ > > > + > > > +/* > > > + * Some Logitech devices expose the HID++ feature 0x4531 (Multi- > > > Platform) allowing > > > + * the host to specify which operating system platform to use on the > > > device. Changing device's > > > + * platform may alter the behavior of the device to match the > > > specified platform. > > > + */ > > > + > > > +static char *hidpp_platform; > > > +module_param(hidpp_platform, charp, 0644); > > > +MODULE_PARM_DESC(hidpp_platform, "Select host platform type for > > > Logitech HID++ Multi-Platform feature " > > > + "0x4531, valid values: (linux|chrome|android). If > > > unset, no " > > > + "change is applied."); > > > + > > > +#define HIDPP_MULTIPLATFORM_FEAT_ID 0x4531 > > > +#define HIDPP_MULTIPLATFORM_GET_FEATURE_INFO 0x0F > > > +#define HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR 0x1F > > > +#define HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM 0x3F > > > + > > > +#define > > > HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX BIT(10) > > > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME BIT(11) > > > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID BIT(12) > > > + > > > +struct hidpp_platform_desc { > > > + u8 plat_idx; > > > + u8 desc_idx; > > > + u16 plat_mask; > > > +}; > > > + > > > +/** > > > + * hidpp_multiplatform_mask_from_str() - Convert platform name to an > > > HID++ platform mask > > > + * @pname: Platform name string > > > + * > > > + * Converts a platform name string to its corresponding HID++ > > > platform mask based on > > > + * the Multi-Platform feature specification. > > > + * > > > + * Return: Platform mask corresponding to @pname on success, > > > + * or 0 if @pname is NULL or unsupported. > > > + */ > > > +static u16 hidpp_multiplatform_mask_from_str(const char *pname) > > > +{ > > > + if (!pname) > > > + return 0; > > > + > > > + if (!strcasecmp(pname, "linux")) > > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX; > > > + if (!strcasecmp(pname, "chrome")) > > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME; > > > + if (!strcasecmp(pname, "android")) > > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID; > > > + > > > + return 0; > > > +} > > > + > > > +/** > > > + * hidpp_multiplatform_get_num_pdesc() - Retrieve number of platform > > > descriptors > > > + * @hidpp: Pointer to the hidpp_device instance > > > + * @feat_index: Feature index of the Multi-Platform feature > > > + * @num_desc: Pointer to store the number of platform descriptors > > > + * > > > + * Retrieves the number of platform descriptors supported by the > > > device through > > > + * the Multi-Platform feature and stores it in @num_desc. > > > + * > > > + * Return: 0 on success, or non-zero on failure. > > > + */ > > > +static int hidpp_multiplatform_get_num_pdesc(struct hidpp_device > > > *hidpp, > > > + u8 feat_index, u8 > > > *num_desc) > > > +{ > > > + int ret; > > > + struct hidpp_report response; > > > + struct hid_device *hdev = hidpp->hid_dev; > > > + > > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > > + > > > HIDPP_MULTIPLATFORM_GET_FEATURE_INFO, > > > + NULL, 0, &response); > > > + if (ret) { > > > + hid_warn(hdev, "Multiplatform: GET_FEATURE_INFO > > > failed (err=%d)", ret); > > > + return ret; > > > + } > > > + > > > + *num_desc = response.fap.params[3]; > > > + hid_dbg(hdev, "Multiplatform: Device supports %d platform > > > descriptors", *num_desc); > > > + > > > + return 0; > > > +} > > > + > > > +/** > > > + * hidpp_multiplatform_get_platform_desc() - Retrieve a platform > > > descriptor entry > > > + * @hidpp: Pointer to the hidpp_device instance > > > + * @feat_index: Feature index of the Multi-Platform feature > > > + * @platform_idx: Index of the platform descriptor to retrieve > > > + * @pdesc: Pointer to store the retrieved platform descriptor > > > + * > > > + * Retrieves a single platform descriptor identified by > > > @platform_idx from the > > > + * device and stores the parsed descriptor fields in @pdesc. > > > + * > > > + * Return: 0 on success, or non-zero on failure. > > > + */ > > > +static int hidpp_multiplatform_get_platform_desc(struct hidpp_device > > > *hidpp, u8 feat_index, > > > + u8 platform_idx, > > > struct hidpp_platform_desc *pdesc) > > > +{ > > > + int ret; > > > + struct hidpp_report response; > > > + u8 params[1] = { platform_idx }; > > > + struct hid_device *hdev = hidpp->hid_dev; > > > + > > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > > + > > > HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR, > > > + params, sizeof(params), > > > &response); > > > + > > > + if (ret) { > > > + hid_warn(hdev, > > > + "Multiplatform: GET_PLATFORM_DESCRIPTOR > > > failed for index %d (err=%d)", > > > + platform_idx, ret); > > > + return ret; > > > + } > > > + > > > + pdesc->plat_idx = response.fap.params[0]; > > > + pdesc->desc_idx = response.fap.params[1]; > > > + pdesc->plat_mask = > > > get_unaligned_be16(&response.fap.params[2]); > > > + > > > + hid_dbg(hdev, > > > + "Multiplatform: descriptor %d: plat_idx=%d, > > > desc_idx=%d, plat_mask=0x%04x", > > > + platform_idx, pdesc->plat_idx, pdesc->desc_idx, > > > pdesc->plat_mask); > > > + > > > + return 0; > > > +} > > > + > > > +/** > > > + * hidpp_multiplatform_get_platform_index() - Find platform index > > > for a mask > > > + * @hidpp: Pointer to the hidpp_device instance > > > + * @feat_index: Feature index of the Multi-Platform feature > > > + * @plat_mask: Platform mask to search for > > > + * @plat_index: Pointer to store the matched platform index > > > + * > > > + * Iterates through all platform descriptors exposed by the device > > > via the > > > + * Multi-Platform feature, retrieving each descriptor and comparing > > > its > > > + * platform mask to @plat_mask. A descriptor matches if its mask > > > overlaps with > > > + * the requested @plat_mask (i.e. (pdesc.plat_mask & plat_mask) is > > > non-zero). > > > + * > > > + * When a matching descriptor is found, its platform index > > > (plat_idx) is > > > + * written to @plat_index and the function returns success. > > > + * > > > + * If no descriptor matches, -ENOENT is returned. > > > + * > > > + * Return: 0 on success; -ENOENT if no matching descriptor exists; > > > + * or non-zero on failure. > > > + */ > > > +static int hidpp_multiplatform_get_platform_index(struct > > > hidpp_device *hidpp, > > > + u8 feat_index, u16 > > > plat_mask, > > > + u8 *plat_index) > > > +{ > > > + int i; > > > + int ret; > > > + u8 num_desc; > > > + struct hidpp_platform_desc pdesc; > > > + struct hid_device *hdev = hidpp->hid_dev; > > > + > > > + ret = hidpp_multiplatform_get_num_pdesc(hidpp, feat_index, > > > &num_desc); > > > + if (ret) > > > + return ret; > > > + > > > + for (i = 0; i < num_desc; i++) { > > > + ret = hidpp_multiplatform_get_platform_desc(hidpp, > > > feat_index, i, &pdesc); > > > + if (ret) > > > + return ret; > > > + > > > + if (pdesc.plat_mask & plat_mask) { > > > + *plat_index = pdesc.plat_idx; > > > + hid_dbg(hdev, > > > + "Multiplatform: Selected platform > > > index %d for platform '%s'", > > > + *plat_index, hidpp_platform); > > > + return 0; > > > + } > > > + } > > > + > > > + hid_dbg(hdev, > > > + "Multiplatform: No matching platform descriptor > > > found for platform '%s'", > > > + hidpp_platform); > > > + return -ENOENT; > > > +} > > > + > > > +/** > > > + * hidpp_multiplatform_update_device_platform() - Update the device > > > platform > > > + * @hidpp: Pointer to the hidpp_device instance > > > + * @feat_index: Feature index of the Multi-Platform feature > > > + * @plat_index: Platform index to set on the device > > > + * > > > + * Sends the HID++ Multi-Platform 'SET_CURRENT_PLATFORM' command to > > > the device to > > > + * update its platform index to @plat_index. > > > + * > > > + * Return: 0 on success, or non-zero on failure. > > > + */ > > > +static int hidpp_multiplatform_update_device_platform(struct > > > hidpp_device *hidpp, > > > + u8 feat_index, > > > u8 plat_index) > > > +{ > > > + int ret; > > > + struct hidpp_report response; > > > + /* Byte 0 (hostIndex): 0xFF selects the current host. */ > > > + u8 params[2] = { 0xFF, plat_index }; > > > + > > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > > + > > > HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM, > > > + params, sizeof(params), > > > &response); > > > + > > > + if (ret) > > > + hid_warn(hidpp->hid_dev, > > > + "Multiplatform: SET_CURRENT_PLATFORM failed > > > for index %d (err=%d)", > > > + plat_index, ret); > > > + > > > + return ret; > > > +} > > > + > > > +/** > > > + * hidpp_multiplatform_init() - Apply the HID++ Multi-Platform > > > (0x4531) feature > > > + * @hidpp: Pointer to the hidpp_device instance > > > + * > > > + * Initializes the Multi-Platform feature by selecting the device > > > platform > > > + * corresponding to the module parameter @hidpp_platform, if > > > provided. > > > + * > > > + * The function performs the following steps: > > > + * 1. Convert the @hidpp_platform string into a platform mask. > > > + * 2. Check whether the device supports the Multi-Platform feature > > > (0x4531). > > > + * 3. Look up the device's platform index whose mask matches the > > > host > > > + * platform mask. > > > + * 4. Apply that platform index to the device via > > > 'SET_CURRENT_PLATFORM'. > > > + * > > > + * If the module parameter is unset or invalid, or the device does > > > not support > > > + * the feature, or no matching platform descriptor is found, the > > > function exits > > > + * silently without modifying the device state. > > > + * > > > + * On success, the device's platform configuration is updated. > > > + */ > > > +static void hidpp_multiplatform_init(struct hidpp_device *hidpp) > > > +{ > > > + int ret; > > > + u8 feat_index; > > > + u8 plat_index; > > > + u16 host_plat_mask; > > > + struct hid_device *hdev = hidpp->hid_dev; > > > + > > > + if (!hidpp_platform) > > > + return; > > > + > > > + host_plat_mask = > > > hidpp_multiplatform_mask_from_str(hidpp_platform); > > > + if (!host_plat_mask) { > > > + hid_warn(hdev, > > > + "Multiplatform: Invalid or unsupported > > > platform name '%s'", > > > + hidpp_platform); > > > + return; > > > + } > > > + > > > + ret = hidpp_root_get_feature(hidpp, > > > HIDPP_MULTIPLATFORM_FEAT_ID, &feat_index); > > > + if (ret) { > > > + hid_warn(hdev, > > > + "Multiplatform: Failed to get the HID++ > > > multiplatform feature 0x4531"); > > > + return; > > > + } > > > + > > > + ret = hidpp_multiplatform_get_platform_index(hidpp, > > > feat_index, host_plat_mask, > > > + &plat_index); > > > + if (ret) > > > + return; > > > + > > > + ret = hidpp_multiplatform_update_device_platform(hidpp, > > > feat_index, plat_index); > > > + if (ret) > > > + return; > > > + > > > + hid_info(hdev, > > > + "Multiplatform: Device platform successfully set to > > > '%s'", hidpp_platform); > > > +} > > > + > > > static int hidpp_probe(struct hid_device *hdev, const struct > > > hid_device_id *id) > > > { > > > struct hidpp_device *hidpp; > > > @@ -4467,6 +4741,8 @@ static int hidpp_probe(struct hid_device *hdev, > > > const struct hid_device_id *id) > > > if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) > > > connect_mask &= ~HID_CONNECT_HIDINPUT; > > > > > > + hidpp_multiplatform_init(hidpp); > > > + > > > /* Now export the actual inputs and hidraw nodes to the > > > world */ > > > hid_device_io_stop(hdev); > > > ret = hid_connect(hdev, connect_mask); > > > @@ -4664,6 +4940,10 @@ static const struct hid_device_id > > > hidpp_devices[] = { > > > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) }, > > > { /* MX Anywhere 3SB mouse over Bluetooth */ > > > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, > > > + { /* Casa Keys keyboard over Bluetooth */ > > > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > > > + { /* MX Keys S keyboard over Bluetooth */ > > > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > > > {} > > > }; > > > > > > diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c > > > index c89a015686c0..99ca04b61bda 100644 > > > --- a/drivers/hid/hid-quirks.c > > > +++ b/drivers/hid/hid-quirks.c > > > @@ -520,6 +520,8 @@ static const struct hid_device_id > > > hid_have_special_driver[] = { > > > #endif > > > #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP) > > > { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, > > > USB_DEVICE_ID_LOGITECH_G920_WHEEL) }, > > > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > > > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > > > #endif > > > #if IS_ENABLED(CONFIG_HID_MAGICMOUSE) > > > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, > > > USB_DEVICE_ID_APPLE_MAGICMOUSE) }, > > Thanks, > > Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) 2026-05-10 6:36 ` dev exalt @ 2026-05-21 9:27 ` dev exalt 2026-05-23 4:12 ` Greg KH 0 siblings, 1 reply; 7+ messages in thread From: dev exalt @ 2026-05-21 9:27 UTC (permalink / raw) To: Bastien Nocera Cc: jikos, bentiss, lains, linux-input, linux-kernel, sari.kreitem, hbarnor Hi, Following up on this thread regarding HID++ Multi-Platform feature (0x4531) support. Please let us know if you’d like us to proceed with a V2 patch based on the discussed approach. Thanks, Baraa On Sun, May 10, 2026 at 9:36 AM dev exalt <exalt.dev.team@gmail.com> wrote: > > Hi Bastien, > > Just following up on this thread in case you had a chance to review > our latest response. > > Would you be OK with us proceeding with the implementation and > preparing a v2 patch based on it? > > Thanks, > Baraa > > On Thu, Mar 19, 2026 at 12:05 PM dev exalt <exalt.dev.team@gmail.com> wrote: > > > > Hi Bastien, > > > > Thanks for the review. Please see our responses inline below. > > > > On Mon, Mar 9, 2026 at 11:53 AM Bastien Nocera <hadess@hadess.net> wrote: > > > > > > Hey, > > > > > > Sorry for not looking at this earlier, it slipped through the cracks as > > > it arrived on the mailing-list as I was away. > > > > > > On Mon, 2025-12-15 at 14:53 +0200, DevExalt wrote: > > > > From: "Baraa Atta (Dev Exalt)" <exalt.dev.team@gmail.com> > > > > > > > > Add support in the Logitech HID++ driver for the HID++ Multi-Platform > > > > feature (0x4531), which enables HID++ devices to adjust their > > > > behavior > > > > based on the host operating system (Linux, ChromeOS, Android). > > > > > > Can you please explain what the feature actually does ? (the Logitech > > > docs say "Set the right keyboard layout for your computer operating > > > system" and mention that some multimedia keys are inoperable unless a > > > compatible OS is set). > > > > The HID++ Multi-Platform feature (0x4531) allows a device to select a > > platform profile that determines how the device firmware behaves for a > > specific operating system. > > > > In practice, this affects how certain keys and functions are exposed > > to the host. Depending on the selected platform, the device may emit > > different HID usages or key combinations for the same physical key. > > > > For example, on the Logitech MX Keys S keyboard a specific key > > produces different events depending on the configured platform. When > > the platform is set to Linux the key generates the combination Shift + > > Ctrl + Alt + Meta + Space, while when the platform is set to Chrome > > the same key generates a dedicated Emoji key event (HID usage code > > 585). > > > > The exact behavioral differences are device-specific and defined by > > the device firmware. > > > > > > > > > > > > > This patch: > > > > * Adds device IDs for MX Keys S (046d:b378) and Casa Keys > > > > (046d:b371). > > > > * Introduces the module parameter "hidpp_platform" to allow > > > > selecting a > > > > target platform. > > > > * Detects whether a device implements feature 0x4531. > > > > * Validates that the requested platform is supported by the device. > > > > * Applies the platform index when valid, otherwise leaves the device > > > > unchanged. > > > > * Keeps default behavior when "hidpp_platform" is unset or invalid. > > > > > > Can you explain the benefits of setting this module parameter, compared > > > to using the keyboard shortcuts to switch to a specific OS > > > configuration? > > > > The distribution can configure the parameter and have the OS configure > > the device automatically without user interaction. Devices will just > > work as expected out of the box. Users can still override it using the > > keyboard shortcut. > > > > > > > > What happens when 2 Logitech devices with different supported OSes are > > > used? > > > > If a device does not support the platform specified through the module > > parameter, the driver does not modify that device and its default > > platform configuration remains unchanged. > > > > During initialization, the driver queries the device for the list of > > supported platform descriptors exposed by the HID++ Multi-Platform > > feature (0x4531). The requested platform is only applied if the device > > advertises support for a compatible descriptor. > > > > For example, if two devices are connected and the module parameter is > > set to linux, a device that supports the Linux platform descriptor > > will have its platform updated accordingly, causing its firmware > > behavior to switch to the Linux profile. A device that does not > > advertise support for the Linux platform will not be modified and will > > continue operating on its default configuration. > > > > > > > > > Supported values for hidpp_platform: > > > > Android, Linux, Chrome > > > > > > Any reason why there aren't more supported OSes? > > > > > > The Logitech docs[1] lists: > > > WebOS iOS MacOS Android Chrome Linux WinEmb Windows Tizen > > > as possible values. > > > > > > [1]: > > > https://drive.google.com/file/d/1KyiBA5m_5V1s6jQ9eQrgRJN0SbbbI9_I/view > > > > > > I recently got a K980 which has this functionality, it only documents > > > Windows, macOS and Chrome, but Solaar also lists Linux as an option. > > > > > > So my questions would be: > > > - why not support the whole range of possible OSes in this option? > > > > Our initial focus during development was primarily on Android, and we > > subsequently added Linux and Chrome. However, if it is preferred for > > completeness, we are happy to add the rest of supported OS platforms > > listed in the documentation. > > > > > - why is it a module option instead of, say, a sysfs attribute that > > > could be changed per device? > > > - why not implement this in user-space through a udev callout? > > > > The module parameter was initially chosen to provide a simple, > > system-wide default that distributions can configure at boot. This > > ensures the devices work out of the box without relying on user > > interaction. > > > > Following your question, we can also add a per-device sysfs attribute > > alongside the module parameter. This hybrid approach accommodates > > compatibility with all systems, since udev is not supported by all > > distributions. > > > > > > > > Cheers > > > > > > > > > > > TEST=Pair MX Keys S and Casa Keys over Bluetooth and verify: > > > > * Feature 0x4531 is detected. > > > > * Valid platform values are accepted and applied. > > > > * Invalid platform values result in no update. > > > > * Devices without 0x4531 retain default behavior. > > > > * Platform-specific key behavior is observed once applied. > > > > > > > > Signed-off-by: Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> > > > > --- > > > > drivers/hid/hid-ids.h | 2 + > > > > drivers/hid/hid-logitech-hidpp.c | 280 > > > > +++++++++++++++++++++++++++++++ > > > > drivers/hid/hid-quirks.c | 2 + > > > > 3 files changed, 284 insertions(+) > > > > > > > > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > > > > index d31711f1aaec..12de1194d7fa 100644 > > > > --- a/drivers/hid/hid-ids.h > > > > +++ b/drivers/hid/hid-ids.h > > > > @@ -866,6 +866,8 @@ > > > > #define USB_DEVICE_ID_LOGITECH_T651 0xb00c > > > > #define USB_DEVICE_ID_LOGITECH_DINOVO_EDGE_KBD 0xb309 > > > > #define USB_DEVICE_ID_LOGITECH_CASA_TOUCHPAD 0xbb00 > > > > +#define USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD 0xb371 > > > > +#define USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD 0xb378 > > > > #define USB_DEVICE_ID_LOGITECH_C007 0xc007 > > > > #define USB_DEVICE_ID_LOGITECH_C077 0xc077 > > > > #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 > > > > diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid- > > > > logitech-hidpp.c > > > > index d5011a5d0890..e94daed31981 100644 > > > > --- a/drivers/hid/hid-logitech-hidpp.c > > > > +++ b/drivers/hid/hid-logitech-hidpp.c > > > > @@ -4373,6 +4373,280 @@ static bool hidpp_application_equals(struct > > > > hid_device *hdev, > > > > return report && report->application == application; > > > > } > > > > > > > > +/* ----------------------------------------------------------------- > > > > --------- */ > > > > +/* 0x4531: Multi-Platform > > > > Support */ > > > > +/* ----------------------------------------------------------------- > > > > --------- */ > > > > + > > > > +/* > > > > + * Some Logitech devices expose the HID++ feature 0x4531 (Multi- > > > > Platform) allowing > > > > + * the host to specify which operating system platform to use on the > > > > device. Changing device's > > > > + * platform may alter the behavior of the device to match the > > > > specified platform. > > > > + */ > > > > + > > > > +static char *hidpp_platform; > > > > +module_param(hidpp_platform, charp, 0644); > > > > +MODULE_PARM_DESC(hidpp_platform, "Select host platform type for > > > > Logitech HID++ Multi-Platform feature " > > > > + "0x4531, valid values: (linux|chrome|android). If > > > > unset, no " > > > > + "change is applied."); > > > > + > > > > +#define HIDPP_MULTIPLATFORM_FEAT_ID 0x4531 > > > > +#define HIDPP_MULTIPLATFORM_GET_FEATURE_INFO 0x0F > > > > +#define HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR 0x1F > > > > +#define HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM 0x3F > > > > + > > > > +#define > > > > HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX BIT(10) > > > > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME BIT(11) > > > > +#define HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID BIT(12) > > > > + > > > > +struct hidpp_platform_desc { > > > > + u8 plat_idx; > > > > + u8 desc_idx; > > > > + u16 plat_mask; > > > > +}; > > > > + > > > > +/** > > > > + * hidpp_multiplatform_mask_from_str() - Convert platform name to an > > > > HID++ platform mask > > > > + * @pname: Platform name string > > > > + * > > > > + * Converts a platform name string to its corresponding HID++ > > > > platform mask based on > > > > + * the Multi-Platform feature specification. > > > > + * > > > > + * Return: Platform mask corresponding to @pname on success, > > > > + * or 0 if @pname is NULL or unsupported. > > > > + */ > > > > +static u16 hidpp_multiplatform_mask_from_str(const char *pname) > > > > +{ > > > > + if (!pname) > > > > + return 0; > > > > + > > > > + if (!strcasecmp(pname, "linux")) > > > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_LINUX; > > > > + if (!strcasecmp(pname, "chrome")) > > > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_CHROME; > > > > + if (!strcasecmp(pname, "android")) > > > > + return HIDPP_MULTIPLATFORM_PLATFORM_MASK_ANDROID; > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +/** > > > > + * hidpp_multiplatform_get_num_pdesc() - Retrieve number of platform > > > > descriptors > > > > + * @hidpp: Pointer to the hidpp_device instance > > > > + * @feat_index: Feature index of the Multi-Platform feature > > > > + * @num_desc: Pointer to store the number of platform descriptors > > > > + * > > > > + * Retrieves the number of platform descriptors supported by the > > > > device through > > > > + * the Multi-Platform feature and stores it in @num_desc. > > > > + * > > > > + * Return: 0 on success, or non-zero on failure. > > > > + */ > > > > +static int hidpp_multiplatform_get_num_pdesc(struct hidpp_device > > > > *hidpp, > > > > + u8 feat_index, u8 > > > > *num_desc) > > > > +{ > > > > + int ret; > > > > + struct hidpp_report response; > > > > + struct hid_device *hdev = hidpp->hid_dev; > > > > + > > > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > > > + > > > > HIDPP_MULTIPLATFORM_GET_FEATURE_INFO, > > > > + NULL, 0, &response); > > > > + if (ret) { > > > > + hid_warn(hdev, "Multiplatform: GET_FEATURE_INFO > > > > failed (err=%d)", ret); > > > > + return ret; > > > > + } > > > > + > > > > + *num_desc = response.fap.params[3]; > > > > + hid_dbg(hdev, "Multiplatform: Device supports %d platform > > > > descriptors", *num_desc); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +/** > > > > + * hidpp_multiplatform_get_platform_desc() - Retrieve a platform > > > > descriptor entry > > > > + * @hidpp: Pointer to the hidpp_device instance > > > > + * @feat_index: Feature index of the Multi-Platform feature > > > > + * @platform_idx: Index of the platform descriptor to retrieve > > > > + * @pdesc: Pointer to store the retrieved platform descriptor > > > > + * > > > > + * Retrieves a single platform descriptor identified by > > > > @platform_idx from the > > > > + * device and stores the parsed descriptor fields in @pdesc. > > > > + * > > > > + * Return: 0 on success, or non-zero on failure. > > > > + */ > > > > +static int hidpp_multiplatform_get_platform_desc(struct hidpp_device > > > > *hidpp, u8 feat_index, > > > > + u8 platform_idx, > > > > struct hidpp_platform_desc *pdesc) > > > > +{ > > > > + int ret; > > > > + struct hidpp_report response; > > > > + u8 params[1] = { platform_idx }; > > > > + struct hid_device *hdev = hidpp->hid_dev; > > > > + > > > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > > > + > > > > HIDPP_MULTIPLATFORM_GET_PLATFORM_DESCRIPTOR, > > > > + params, sizeof(params), > > > > &response); > > > > + > > > > + if (ret) { > > > > + hid_warn(hdev, > > > > + "Multiplatform: GET_PLATFORM_DESCRIPTOR > > > > failed for index %d (err=%d)", > > > > + platform_idx, ret); > > > > + return ret; > > > > + } > > > > + > > > > + pdesc->plat_idx = response.fap.params[0]; > > > > + pdesc->desc_idx = response.fap.params[1]; > > > > + pdesc->plat_mask = > > > > get_unaligned_be16(&response.fap.params[2]); > > > > + > > > > + hid_dbg(hdev, > > > > + "Multiplatform: descriptor %d: plat_idx=%d, > > > > desc_idx=%d, plat_mask=0x%04x", > > > > + platform_idx, pdesc->plat_idx, pdesc->desc_idx, > > > > pdesc->plat_mask); > > > > + > > > > + return 0; > > > > +} > > > > + > > > > +/** > > > > + * hidpp_multiplatform_get_platform_index() - Find platform index > > > > for a mask > > > > + * @hidpp: Pointer to the hidpp_device instance > > > > + * @feat_index: Feature index of the Multi-Platform feature > > > > + * @plat_mask: Platform mask to search for > > > > + * @plat_index: Pointer to store the matched platform index > > > > + * > > > > + * Iterates through all platform descriptors exposed by the device > > > > via the > > > > + * Multi-Platform feature, retrieving each descriptor and comparing > > > > its > > > > + * platform mask to @plat_mask. A descriptor matches if its mask > > > > overlaps with > > > > + * the requested @plat_mask (i.e. (pdesc.plat_mask & plat_mask) is > > > > non-zero). > > > > + * > > > > + * When a matching descriptor is found, its platform index > > > > (plat_idx) is > > > > + * written to @plat_index and the function returns success. > > > > + * > > > > + * If no descriptor matches, -ENOENT is returned. > > > > + * > > > > + * Return: 0 on success; -ENOENT if no matching descriptor exists; > > > > + * or non-zero on failure. > > > > + */ > > > > +static int hidpp_multiplatform_get_platform_index(struct > > > > hidpp_device *hidpp, > > > > + u8 feat_index, u16 > > > > plat_mask, > > > > + u8 *plat_index) > > > > +{ > > > > + int i; > > > > + int ret; > > > > + u8 num_desc; > > > > + struct hidpp_platform_desc pdesc; > > > > + struct hid_device *hdev = hidpp->hid_dev; > > > > + > > > > + ret = hidpp_multiplatform_get_num_pdesc(hidpp, feat_index, > > > > &num_desc); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + for (i = 0; i < num_desc; i++) { > > > > + ret = hidpp_multiplatform_get_platform_desc(hidpp, > > > > feat_index, i, &pdesc); > > > > + if (ret) > > > > + return ret; > > > > + > > > > + if (pdesc.plat_mask & plat_mask) { > > > > + *plat_index = pdesc.plat_idx; > > > > + hid_dbg(hdev, > > > > + "Multiplatform: Selected platform > > > > index %d for platform '%s'", > > > > + *plat_index, hidpp_platform); > > > > + return 0; > > > > + } > > > > + } > > > > + > > > > + hid_dbg(hdev, > > > > + "Multiplatform: No matching platform descriptor > > > > found for platform '%s'", > > > > + hidpp_platform); > > > > + return -ENOENT; > > > > +} > > > > + > > > > +/** > > > > + * hidpp_multiplatform_update_device_platform() - Update the device > > > > platform > > > > + * @hidpp: Pointer to the hidpp_device instance > > > > + * @feat_index: Feature index of the Multi-Platform feature > > > > + * @plat_index: Platform index to set on the device > > > > + * > > > > + * Sends the HID++ Multi-Platform 'SET_CURRENT_PLATFORM' command to > > > > the device to > > > > + * update its platform index to @plat_index. > > > > + * > > > > + * Return: 0 on success, or non-zero on failure. > > > > + */ > > > > +static int hidpp_multiplatform_update_device_platform(struct > > > > hidpp_device *hidpp, > > > > + u8 feat_index, > > > > u8 plat_index) > > > > +{ > > > > + int ret; > > > > + struct hidpp_report response; > > > > + /* Byte 0 (hostIndex): 0xFF selects the current host. */ > > > > + u8 params[2] = { 0xFF, plat_index }; > > > > + > > > > + ret = hidpp_send_fap_command_sync(hidpp, feat_index, > > > > + > > > > HIDPP_MULTIPLATFORM_SET_CURRENT_PLATFORM, > > > > + params, sizeof(params), > > > > &response); > > > > + > > > > + if (ret) > > > > + hid_warn(hidpp->hid_dev, > > > > + "Multiplatform: SET_CURRENT_PLATFORM failed > > > > for index %d (err=%d)", > > > > + plat_index, ret); > > > > + > > > > + return ret; > > > > +} > > > > + > > > > +/** > > > > + * hidpp_multiplatform_init() - Apply the HID++ Multi-Platform > > > > (0x4531) feature > > > > + * @hidpp: Pointer to the hidpp_device instance > > > > + * > > > > + * Initializes the Multi-Platform feature by selecting the device > > > > platform > > > > + * corresponding to the module parameter @hidpp_platform, if > > > > provided. > > > > + * > > > > + * The function performs the following steps: > > > > + * 1. Convert the @hidpp_platform string into a platform mask. > > > > + * 2. Check whether the device supports the Multi-Platform feature > > > > (0x4531). > > > > + * 3. Look up the device's platform index whose mask matches the > > > > host > > > > + * platform mask. > > > > + * 4. Apply that platform index to the device via > > > > 'SET_CURRENT_PLATFORM'. > > > > + * > > > > + * If the module parameter is unset or invalid, or the device does > > > > not support > > > > + * the feature, or no matching platform descriptor is found, the > > > > function exits > > > > + * silently without modifying the device state. > > > > + * > > > > + * On success, the device's platform configuration is updated. > > > > + */ > > > > +static void hidpp_multiplatform_init(struct hidpp_device *hidpp) > > > > +{ > > > > + int ret; > > > > + u8 feat_index; > > > > + u8 plat_index; > > > > + u16 host_plat_mask; > > > > + struct hid_device *hdev = hidpp->hid_dev; > > > > + > > > > + if (!hidpp_platform) > > > > + return; > > > > + > > > > + host_plat_mask = > > > > hidpp_multiplatform_mask_from_str(hidpp_platform); > > > > + if (!host_plat_mask) { > > > > + hid_warn(hdev, > > > > + "Multiplatform: Invalid or unsupported > > > > platform name '%s'", > > > > + hidpp_platform); > > > > + return; > > > > + } > > > > + > > > > + ret = hidpp_root_get_feature(hidpp, > > > > HIDPP_MULTIPLATFORM_FEAT_ID, &feat_index); > > > > + if (ret) { > > > > + hid_warn(hdev, > > > > + "Multiplatform: Failed to get the HID++ > > > > multiplatform feature 0x4531"); > > > > + return; > > > > + } > > > > + > > > > + ret = hidpp_multiplatform_get_platform_index(hidpp, > > > > feat_index, host_plat_mask, > > > > + &plat_index); > > > > + if (ret) > > > > + return; > > > > + > > > > + ret = hidpp_multiplatform_update_device_platform(hidpp, > > > > feat_index, plat_index); > > > > + if (ret) > > > > + return; > > > > + > > > > + hid_info(hdev, > > > > + "Multiplatform: Device platform successfully set to > > > > '%s'", hidpp_platform); > > > > +} > > > > + > > > > static int hidpp_probe(struct hid_device *hdev, const struct > > > > hid_device_id *id) > > > > { > > > > struct hidpp_device *hidpp; > > > > @@ -4467,6 +4741,8 @@ static int hidpp_probe(struct hid_device *hdev, > > > > const struct hid_device_id *id) > > > > if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) > > > > connect_mask &= ~HID_CONNECT_HIDINPUT; > > > > > > > > + hidpp_multiplatform_init(hidpp); > > > > + > > > > /* Now export the actual inputs and hidraw nodes to the > > > > world */ > > > > hid_device_io_stop(hdev); > > > > ret = hid_connect(hdev, connect_mask); > > > > @@ -4664,6 +4940,10 @@ static const struct hid_device_id > > > > hidpp_devices[] = { > > > > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb034) }, > > > > { /* MX Anywhere 3SB mouse over Bluetooth */ > > > > HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb038) }, > > > > + { /* Casa Keys keyboard over Bluetooth */ > > > > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > > > > + { /* MX Keys S keyboard over Bluetooth */ > > > > + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > > > > {} > > > > }; > > > > > > > > diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c > > > > index c89a015686c0..99ca04b61bda 100644 > > > > --- a/drivers/hid/hid-quirks.c > > > > +++ b/drivers/hid/hid-quirks.c > > > > @@ -520,6 +520,8 @@ static const struct hid_device_id > > > > hid_have_special_driver[] = { > > > > #endif > > > > #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP) > > > > { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, > > > > USB_DEVICE_ID_LOGITECH_G920_WHEEL) }, > > > > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > > USB_DEVICE_ID_LOGITECH_CASA_KEYS_KEYBOARD) }, > > > > + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, > > > > USB_DEVICE_ID_LOGITECH_MX_KEYS_S_KEYBOARD) }, > > > > #endif > > > > #if IS_ENABLED(CONFIG_HID_MAGICMOUSE) > > > > { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, > > > > USB_DEVICE_ID_APPLE_MAGICMOUSE) }, > > > > Thanks, > > > > Baraa Atta (Dev Exalt) <exalt.dev.team@gmail.com> ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) 2026-05-21 9:27 ` dev exalt @ 2026-05-23 4:12 ` Greg KH 0 siblings, 0 replies; 7+ messages in thread From: Greg KH @ 2026-05-23 4:12 UTC (permalink / raw) To: dev exalt Cc: Bastien Nocera, jikos, bentiss, lains, linux-input, linux-kernel, sari.kreitem, hbarnor On Thu, May 21, 2026 at 12:27:05PM +0300, dev exalt wrote: > Hi, > > Following up on this thread regarding HID++ Multi-Platform feature > (0x4531) support. > Please let us know if you’d like us to proceed with a V2 patch based > on the discussed approach. As-is, a module parameter will not work. All systems have configfs, and sysfs, so use that for device configurations that need it. thanks, greg k-h ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-05-23 4:12 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-15 12:53 [PATCH] HID: logitech-hidpp: Add support for HID++ Multi-Platform feature (0x4531) DevExalt
[not found] ` <CAJaUH_8A70=_Cb8yCWqJxbjpW-BnK958fExnC1kSgyhVaydbUw@mail.gmail.com>
2026-03-08 8:08 ` dev exalt
2026-03-09 9:53 ` Bastien Nocera
2026-03-19 10:05 ` dev exalt
2026-05-10 6:36 ` dev exalt
2026-05-21 9:27 ` dev exalt
2026-05-23 4:12 ` Greg KH
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox