From 52067e9be53eea55613b6446ede54eb4c77ce37a Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Tue, 1 Apr 2025 10:08:46 +0100 Subject: [PATCH] 5.4-stable patches added patches: alsa-usb-audio-add-quirk-for-plantronics-headsets-to-fix-control-names.patch hid-hid-plantronics-add-mic-mute-mapping-and-generalize-quirks.patch --- ...ronics-headsets-to-fix-control-names.patch | 100 +++++++ ...c-mute-mapping-and-generalize-quirks.patch | 281 ++++++++++++++++++ queue-5.4/series | 2 + 3 files changed, 383 insertions(+) create mode 100644 queue-5.4/alsa-usb-audio-add-quirk-for-plantronics-headsets-to-fix-control-names.patch create mode 100644 queue-5.4/hid-hid-plantronics-add-mic-mute-mapping-and-generalize-quirks.patch diff --git a/queue-5.4/alsa-usb-audio-add-quirk-for-plantronics-headsets-to-fix-control-names.patch b/queue-5.4/alsa-usb-audio-add-quirk-for-plantronics-headsets-to-fix-control-names.patch new file mode 100644 index 0000000000..c96592ed95 --- /dev/null +++ b/queue-5.4/alsa-usb-audio-add-quirk-for-plantronics-headsets-to-fix-control-names.patch @@ -0,0 +1,100 @@ +From 486f6205c233da1baa309bde5f634eb1f8319a33 Mon Sep 17 00:00:00 2001 +From: Terry Junge +Date: Fri, 17 Jan 2025 16:58:39 -0800 +Subject: ALSA: usb-audio: Add quirk for Plantronics headsets to fix control names + +From: Terry Junge + +commit 486f6205c233da1baa309bde5f634eb1f8319a33 upstream. + +Many Poly/Plantronics headset families name the feature, input, +and/or output units in a such a way to produce control names +that are not recognized by user space. As such, the volume and +mute events do not get routed to the headset's audio controls. + +As an example from a product family: + +The microphone mute control is named +Headset Microphone Capture Switch +and the headset volume control is named +Headset Earphone Playback Volume + +The quirk fixes these to become +Headset Capture Switch +Headset Playback Volume + +Signed-off-by: Terry Junge +Reviewed-by: Takashi Iwai +Cc: stable@vger.kernel.org +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + sound/usb/mixer_quirks.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 51 insertions(+) + +--- a/sound/usb/mixer_quirks.c ++++ b/sound/usb/mixer_quirks.c +@@ -2531,6 +2531,52 @@ static void snd_dragonfly_quirk_db_scale + } + } + ++/* ++ * Some Plantronics headsets have control names that don't meet ALSA naming ++ * standards. This function fixes nonstandard source names. By the time ++ * this function is called the control name should look like one of these: ++ * "source names Playback Volume" ++ * "source names Playback Switch" ++ * "source names Capture Volume" ++ * "source names Capture Switch" ++ * If any of the trigger words are found in the name then the name will ++ * be changed to: ++ * "Headset Playback Volume" ++ * "Headset Playback Switch" ++ * "Headset Capture Volume" ++ * "Headset Capture Switch" ++ * depending on the current suffix. ++ */ ++static void snd_fix_plt_name(struct snd_usb_audio *chip, ++ struct snd_ctl_elem_id *id) ++{ ++ /* no variant of "Sidetone" should be added to this list */ ++ static const char * const trigger[] = { ++ "Earphone", "Microphone", "Receive", "Transmit" ++ }; ++ static const char * const suffix[] = { ++ " Playback Volume", " Playback Switch", ++ " Capture Volume", " Capture Switch" ++ }; ++ int i; ++ ++ for (i = 0; i < ARRAY_SIZE(trigger); i++) ++ if (strstr(id->name, trigger[i])) ++ goto triggered; ++ usb_audio_dbg(chip, "no change in %s\n", id->name); ++ return; ++ ++triggered: ++ for (i = 0; i < ARRAY_SIZE(suffix); i++) ++ if (strstr(id->name, suffix[i])) { ++ usb_audio_dbg(chip, "fixing kctl name %s\n", id->name); ++ snprintf(id->name, sizeof(id->name), "Headset%s", ++ suffix[i]); ++ return; ++ } ++ usb_audio_dbg(chip, "something wrong in kctl name %s\n", id->name); ++} ++ + void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, + struct usb_mixer_elem_info *cval, int unitid, + struct snd_kcontrol *kctl) +@@ -2548,5 +2594,10 @@ void snd_usb_mixer_fu_apply_quirk(struct + cval->min_mute = 1; + break; + } ++ ++ /* ALSA-ify some Plantronics headset control names */ ++ if (USB_ID_VENDOR(mixer->chip->usb_id) == 0x047f && ++ (cval->control == UAC_FU_MUTE || cval->control == UAC_FU_VOLUME)) ++ snd_fix_plt_name(mixer->chip, &kctl->id); + } + diff --git a/queue-5.4/hid-hid-plantronics-add-mic-mute-mapping-and-generalize-quirks.patch b/queue-5.4/hid-hid-plantronics-add-mic-mute-mapping-and-generalize-quirks.patch new file mode 100644 index 0000000000..d577af5c2e --- /dev/null +++ b/queue-5.4/hid-hid-plantronics-add-mic-mute-mapping-and-generalize-quirks.patch @@ -0,0 +1,281 @@ +From 9821709af892be9fbf4ee9a50b2f3e0604295ce0 Mon Sep 17 00:00:00 2001 +From: Terry Junge +Date: Fri, 17 Jan 2025 16:58:38 -0800 +Subject: HID: hid-plantronics: Add mic mute mapping and generalize quirks + +From: Terry Junge + +commit 9821709af892be9fbf4ee9a50b2f3e0604295ce0 upstream. + +Add mapping for headset mute key events. + +Remove PLT_QUIRK_DOUBLE_VOLUME_KEYS quirk and made it generic. +The quirk logic did not keep track of the actual previous key +so any key event occurring in less than or equal to 5ms was ignored. + +Remove PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS quirk. +It had the same logic issue as the double key quirk and was actually +masking the as designed behavior of most of the headsets. +It's occurrence should be minimized with the ALSA control naming +quirk that is part of the patch set. + +Signed-off-by: Terry Junge +Cc: stable@vger.kernel.org +Signed-off-by: Jiri Kosina +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hid/hid-plantronics.c | 148 +++++++++++++++++++----------------------- + 1 file changed, 69 insertions(+), 79 deletions(-) + +--- a/drivers/hid/hid-plantronics.c ++++ b/drivers/hid/hid-plantronics.c +@@ -6,9 +6,6 @@ + * Copyright (c) 2015-2018 Terry Junge + */ + +-/* +- */ +- + #include "hid-ids.h" + + #include +@@ -23,30 +20,28 @@ + + #define PLT_VOL_UP 0x00b1 + #define PLT_VOL_DOWN 0x00b2 ++#define PLT_MIC_MUTE 0x00b5 + + #define PLT1_VOL_UP (PLT_HID_1_0_PAGE | PLT_VOL_UP) + #define PLT1_VOL_DOWN (PLT_HID_1_0_PAGE | PLT_VOL_DOWN) ++#define PLT1_MIC_MUTE (PLT_HID_1_0_PAGE | PLT_MIC_MUTE) + #define PLT2_VOL_UP (PLT_HID_2_0_PAGE | PLT_VOL_UP) + #define PLT2_VOL_DOWN (PLT_HID_2_0_PAGE | PLT_VOL_DOWN) ++#define PLT2_MIC_MUTE (PLT_HID_2_0_PAGE | PLT_MIC_MUTE) ++#define HID_TELEPHONY_MUTE (HID_UP_TELEPHONY | 0x2f) ++#define HID_CONSUMER_MUTE (HID_UP_CONSUMER | 0xe2) + + #define PLT_DA60 0xda60 + #define PLT_BT300_MIN 0x0413 + #define PLT_BT300_MAX 0x0418 + +- +-#define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \ +- (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) +- +-#define PLT_QUIRK_DOUBLE_VOLUME_KEYS BIT(0) +-#define PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS BIT(1) +- + #define PLT_DOUBLE_KEY_TIMEOUT 5 /* ms */ +-#define PLT_FOLLOWED_OPPOSITE_KEY_TIMEOUT 220 /* ms */ + + struct plt_drv_data { + unsigned long device_type; +- unsigned long last_volume_key_ts; +- u32 quirks; ++ unsigned long last_key_ts; ++ unsigned long double_key_to; ++ __u16 last_key; + }; + + static int plantronics_input_mapping(struct hid_device *hdev, +@@ -58,34 +53,43 @@ static int plantronics_input_mapping(str + unsigned short mapped_key; + struct plt_drv_data *drv_data = hid_get_drvdata(hdev); + unsigned long plt_type = drv_data->device_type; ++ int allow_mute = usage->hid == HID_TELEPHONY_MUTE; ++ int allow_consumer = field->application == HID_CP_CONSUMERCONTROL && ++ (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER && ++ usage->hid != HID_CONSUMER_MUTE; + + /* special case for PTT products */ + if (field->application == HID_GD_JOYSTICK) + goto defaulted; + +- /* handle volume up/down mapping */ + /* non-standard types or multi-HID interfaces - plt_type is PID */ + if (!(plt_type & HID_USAGE_PAGE)) { + switch (plt_type) { + case PLT_DA60: +- if (PLT_ALLOW_CONSUMER) ++ if (allow_consumer) + goto defaulted; +- goto ignored; ++ if (usage->hid == HID_CONSUMER_MUTE) { ++ mapped_key = KEY_MICMUTE; ++ goto mapped; ++ } ++ break; + default: +- if (PLT_ALLOW_CONSUMER) ++ if (allow_consumer || allow_mute) + goto defaulted; + } ++ goto ignored; + } +- /* handle standard types - plt_type is 0xffa0uuuu or 0xffa2uuuu */ +- /* 'basic telephony compliant' - allow default consumer page map */ +- else if ((plt_type & HID_USAGE) >= PLT_BASIC_TELEPHONY && +- (plt_type & HID_USAGE) != PLT_BASIC_EXCEPTION) { +- if (PLT_ALLOW_CONSUMER) +- goto defaulted; +- } +- /* not 'basic telephony' - apply legacy mapping */ +- /* only map if the field is in the device's primary vendor page */ +- else if (!((field->application ^ plt_type) & HID_USAGE_PAGE)) { ++ ++ /* handle standard consumer control mapping */ ++ /* and standard telephony mic mute mapping */ ++ if (allow_consumer || allow_mute) ++ goto defaulted; ++ ++ /* handle vendor unique types - plt_type is 0xffa0uuuu or 0xffa2uuuu */ ++ /* if not 'basic telephony compliant' - map vendor unique controls */ ++ if (!((plt_type & HID_USAGE) >= PLT_BASIC_TELEPHONY && ++ (plt_type & HID_USAGE) != PLT_BASIC_EXCEPTION) && ++ !((field->application ^ plt_type) & HID_USAGE_PAGE)) + switch (usage->hid) { + case PLT1_VOL_UP: + case PLT2_VOL_UP: +@@ -95,8 +99,11 @@ static int plantronics_input_mapping(str + case PLT2_VOL_DOWN: + mapped_key = KEY_VOLUMEDOWN; + goto mapped; ++ case PLT1_MIC_MUTE: ++ case PLT2_MIC_MUTE: ++ mapped_key = KEY_MICMUTE; ++ goto mapped; + } +- } + + /* + * Future mapping of call control or other usages, +@@ -105,6 +112,8 @@ static int plantronics_input_mapping(str + */ + + ignored: ++ hid_dbg(hdev, "usage: %08x (appl: %08x) - ignored\n", ++ usage->hid, field->application); + return -1; + + defaulted: +@@ -123,38 +132,26 @@ static int plantronics_event(struct hid_ + struct hid_usage *usage, __s32 value) + { + struct plt_drv_data *drv_data = hid_get_drvdata(hdev); ++ unsigned long prev_tsto, cur_ts; ++ __u16 prev_key, cur_key; + +- if (drv_data->quirks & PLT_QUIRK_DOUBLE_VOLUME_KEYS) { +- unsigned long prev_ts, cur_ts; +- +- /* Usages are filtered in plantronics_usages. */ +- +- if (!value) /* Handle key presses only. */ +- return 0; +- +- prev_ts = drv_data->last_volume_key_ts; +- cur_ts = jiffies; +- if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_DOUBLE_KEY_TIMEOUT) +- return 1; /* Ignore the repeated key. */ +- +- drv_data->last_volume_key_ts = cur_ts; +- } +- if (drv_data->quirks & PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS) { +- unsigned long prev_ts, cur_ts; +- +- /* Usages are filtered in plantronics_usages. */ +- +- if (!value) /* Handle key presses only. */ +- return 0; ++ /* Usages are filtered in plantronics_usages. */ + +- prev_ts = drv_data->last_volume_key_ts; +- cur_ts = jiffies; +- if (jiffies_to_msecs(cur_ts - prev_ts) <= PLT_FOLLOWED_OPPOSITE_KEY_TIMEOUT) +- return 1; /* Ignore the followed opposite volume key. */ +- +- drv_data->last_volume_key_ts = cur_ts; ++ /* HZ too low for ms resolution - double key detection disabled */ ++ /* or it is a key release - handle key presses only. */ ++ if (!drv_data->double_key_to || !value) ++ return 0; ++ ++ prev_tsto = drv_data->last_key_ts + drv_data->double_key_to; ++ cur_ts = drv_data->last_key_ts = jiffies; ++ prev_key = drv_data->last_key; ++ cur_key = drv_data->last_key = usage->code; ++ ++ /* If the same key occurs in <= double_key_to -- ignore it */ ++ if (prev_key == cur_key && time_before_eq(cur_ts, prev_tsto)) { ++ hid_dbg(hdev, "double key %d ignored\n", cur_key); ++ return 1; /* Ignore the repeated key. */ + } +- + return 0; + } + +@@ -196,12 +193,16 @@ static int plantronics_probe(struct hid_ + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); +- goto err; ++ return ret; + } + + drv_data->device_type = plantronics_device_type(hdev); +- drv_data->quirks = id->driver_data; +- drv_data->last_volume_key_ts = jiffies - msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT); ++ drv_data->double_key_to = msecs_to_jiffies(PLT_DOUBLE_KEY_TIMEOUT); ++ drv_data->last_key_ts = jiffies - drv_data->double_key_to; ++ ++ /* if HZ does not allow ms resolution - disable double key detection */ ++ if (drv_data->double_key_to < PLT_DOUBLE_KEY_TIMEOUT) ++ drv_data->double_key_to = 0; + + hid_set_drvdata(hdev, drv_data); + +@@ -210,29 +211,10 @@ static int plantronics_probe(struct hid_ + if (ret) + hid_err(hdev, "hw start failed\n"); + +-err: + return ret; + } + + static const struct hid_device_id plantronics_devices[] = { +- { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, +- USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3210_SERIES), +- .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, +- { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, +- USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3220_SERIES), +- .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, +- { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, +- USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3215_SERIES), +- .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, +- { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, +- USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3225_SERIES), +- .driver_data = PLT_QUIRK_DOUBLE_VOLUME_KEYS }, +- { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, +- USB_DEVICE_ID_PLANTRONICS_BLACKWIRE_3325_SERIES), +- .driver_data = PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS }, +- { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, +- USB_DEVICE_ID_PLANTRONICS_ENCOREPRO_500_SERIES), +- .driver_data = PLT_QUIRK_FOLLOWED_OPPOSITE_VOLUME_KEYS }, + { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) }, + { } + }; +@@ -241,6 +223,14 @@ MODULE_DEVICE_TABLE(hid, plantronics_dev + static const struct hid_usage_id plantronics_usages[] = { + { HID_CP_VOLUMEUP, EV_KEY, HID_ANY_ID }, + { HID_CP_VOLUMEDOWN, EV_KEY, HID_ANY_ID }, ++ { HID_TELEPHONY_MUTE, EV_KEY, HID_ANY_ID }, ++ { HID_CONSUMER_MUTE, EV_KEY, HID_ANY_ID }, ++ { PLT2_VOL_UP, EV_KEY, HID_ANY_ID }, ++ { PLT2_VOL_DOWN, EV_KEY, HID_ANY_ID }, ++ { PLT2_MIC_MUTE, EV_KEY, HID_ANY_ID }, ++ { PLT1_VOL_UP, EV_KEY, HID_ANY_ID }, ++ { PLT1_VOL_DOWN, EV_KEY, HID_ANY_ID }, ++ { PLT1_MIC_MUTE, EV_KEY, HID_ANY_ID }, + { HID_TERMINATOR, HID_TERMINATOR, HID_TERMINATOR } + }; + diff --git a/queue-5.4/series b/queue-5.4/series index d5e345ee13..d85ed0f5f5 100644 --- a/queue-5.4/series +++ b/queue-5.4/series @@ -63,3 +63,5 @@ mmc-atmel-mci-add-missing-clk_disable_unprepare.patch arm-shmobile-smp-enforce-shmobile_smp_-alignment.patch batman-adv-ignore-own-maximum-aggregation-size-during-rx.patch drm-radeon-fix-uninitialized-size-issue-in-radeon_vce_cs_parse.patch +alsa-usb-audio-add-quirk-for-plantronics-headsets-to-fix-control-names.patch +hid-hid-plantronics-add-mic-mute-mapping-and-generalize-quirks.patch -- 2.47.3