return changed;
 }
 
+/* get the current value from a mixer element */
+static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct usb_mixer_elem_info *cval = kcontrol->private_data;
+       int val, err;
+
+       err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
+       if (err < 0)
+               return filter_error(cval, err);
+       val = (val != 0);
+       ucontrol->value.integer.value[0] = val;
+       return 0;
+}
+
 static struct snd_kcontrol_new usb_feature_unit_ctl = {
        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
        .name = "", /* will be filled later manually */
        .put = NULL,
 };
 
+/* A UAC connector mixer control */
+static struct snd_kcontrol_new usb_connector_ctl_ro = {
+       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+       .name = "", /* will be filled later manually */
+       .access = SNDRV_CTL_ELEM_ACCESS_READ,
+       .info = snd_ctl_boolean_mono_info,
+       .get = mixer_ctl_connector_get,
+       .put = NULL,
+};
+
 /*
  * This symbol is exported in order to allow the mixer quirks to
  * hook up to the standard feature unit control mechanism
        snd_usb_mixer_add_control(&cval->head, kctl);
 }
 
+static void get_connector_control_name(struct mixer_build *state,
+                                      struct usb_audio_term *term,
+                                      bool is_input, char *name, int name_size)
+{
+       int name_len = get_term_name(state, term, name, name_size, 0);
+
+       if (name_len == 0)
+               strlcpy(name, "Unknown", name_size);
+
+       /*
+        *  sound/core/ctljack.c has a convention of naming jack controls
+        * by ending in " Jack".  Make it slightly more useful by
+        * indicating Input or Output after the terminal name.
+        */
+       if (is_input)
+               strlcat(name, " - Input Jack", name_size);
+       else
+               strlcat(name, " - Output Jack", name_size);
+}
+
+/* Build a mixer control for a UAC connector control (jack-detect) */
+static void build_connector_control(struct mixer_build *state,
+                                   struct usb_audio_term *term, bool is_input)
+{
+       struct snd_kcontrol *kctl;
+       struct usb_mixer_elem_info *cval;
+
+       cval = kzalloc(sizeof(*cval), GFP_KERNEL);
+       if (!cval)
+               return;
+       snd_usb_mixer_elem_init_std(&cval->head, state->mixer, term->id);
+       cval->control = UAC2_TE_CONNECTOR;
+       cval->val_type = USB_MIXER_BOOLEAN;
+       cval->channels = 1; /* report true if any channel is connected */
+       cval->min = 0;
+       cval->max = 1;
+       kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval);
+       if (!kctl) {
+               usb_audio_err(state->chip, "cannot malloc kcontrol\n");
+               kfree(cval);
+               return;
+       }
+       get_connector_control_name(state, term, is_input, kctl->id.name,
+                                  sizeof(kctl->id.name));
+       kctl->private_free = snd_usb_mixer_elem_free;
+       snd_usb_mixer_add_control(&cval->head, kctl);
+}
+
 static int parse_clock_source_unit(struct mixer_build *state, int unitid,
                                   void *_ftr)
 {
        snd_usb_mixer_add_control(&cval->head, kctl);
 }
 
+static int parse_audio_input_terminal(struct mixer_build *state, int unitid,
+                                     void *raw_desc)
+{
+       struct usb_audio_term iterm;
+       struct uac2_input_terminal_descriptor *d = raw_desc;
+
+       check_input_term(state, d->bTerminalID, &iterm);
+       if (state->mixer->protocol == UAC_VERSION_2) {
+               /* Check for jack detection. */
+               if (uac_v2v3_control_is_readable(d->bmControls,
+                                                UAC2_TE_CONNECTOR)) {
+                       build_connector_control(state, &iterm, true);
+               }
+       }
+       return 0;
+}
+
 /*
  * parse a mixer unit
  */
        if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
                switch (p1[2]) {
                case UAC_INPUT_TERMINAL:
-                       return 0; /* NOP */
+                       return parse_audio_input_terminal(state, unitid, p1);
                case UAC_MIXER_UNIT:
                        return parse_audio_mixer_unit(state, unitid, p1);
                case UAC2_CLOCK_SOURCE:
                        err = parse_audio_unit(&state, desc->bCSourceID);
                        if (err < 0 && err != -EINVAL)
                                return err;
+
+                       if (uac_v2v3_control_is_readable(desc->bmControls,
+                                                        UAC2_TE_CONNECTOR)) {
+                               build_connector_control(&state, &state.oterm,
+                                                       false);
+                       }
                } else {  /* UAC_VERSION_3 */
                        struct uac3_output_terminal_descriptor *desc = p;