@@ -4216,6 +4216,67 @@ static void snd_dragonfly_quirk_db_scale(struct usb_mixer_interface *mixer,
}
}
+/*
+ * Some Plantronics headsets have control names that don't meet ALSA naming
+ * standards. This function removes nonstandard source names. By the time
+ * this function is called the control name will look like one of these:
+ * "source names Playback Volume"
+ * "source names Playback Switch"
+ * "source names Capture Volume"
+ * "source names Capture Switch"
+ * First it scans through the list and removes any found name(s) by moving the
+ * remaining string and its null terminator over the found name and its leading
+ * space, if it has one.
+ * Second, if all source names were removed, it puts back "Headset"
+ * otherwise removes a leading space, if there is one.
+ */
+static void snd_fix_plt_control_name(struct usb_mixer_interface *mixer,
+ struct snd_kcontrol *kctl)
+{
+ /* no variant of "Sidetone" should be added to this list */
+ static const char * const names_to_remove[] = {
+ "Earphone",
+ "Microphone",
+ "Receive",
+ "Transmit",
+ NULL
+ };
+ const char * const *n2r;
+ char *dst, *src, *last = NULL;
+ size_t len = 0;
+
+ for (n2r = names_to_remove; *n2r; ++n2r) {
+ dst = strstr(kctl->id.name, *n2r);
+ if (dst) {
+ usb_audio_dbg(mixer->chip, "found %s in %s\n",
+ *n2r, kctl->id.name);
+ src = dst + strlen(*n2r);
+ len = strlen(src) + 1;
+ if ((char *)kctl->id.name != dst && *(dst - 1) == ' ')
+ --dst;
+ last = memmove(dst, src, len);
+ usb_audio_dbg(mixer->chip, "now %s\n", kctl->id.name);
+ }
+ }
+ if (!len) {
+ usb_audio_dbg(mixer->chip, "no change in %s\n", kctl->id.name);
+ return;
+ }
+ if (len <= sizeof " Playback Volume" && (char *)kctl->id.name == last) {
+ char rcat[sizeof(kctl->id.name)] = { "Headset" };
+
+ strlcat(rcat, kctl->id.name, sizeof(rcat));
+ strscpy(kctl->id.name, rcat, sizeof(kctl->id.name));
+ usb_audio_dbg(mixer->chip, "now %s\n", kctl->id.name);
+ } else if (kctl->id.name[0] == ' ') {
+ dst = kctl->id.name;
+ src = dst + 1;
+ len = strlen(src) + 1;
+ memmove(dst, src, len);
+ usb_audio_dbg(mixer->chip, "now %s\n", kctl->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)
@@ -4233,5 +4294,10 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer,
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_control_name(mixer, kctl);
}