diff --git a/src/modules/alsa/alsa-mixer.c b/src/modules/alsa/alsa-mixer.c
index 317fe12..39a4633 100644
--- a/src/modules/alsa/alsa-mixer.c
+++ b/src/modules/alsa/alsa-mixer.c
@@ -3294,7 +3294,7 @@ static void mapping_free(pa_alsa_mapping *m) {
     pa_assert(!m->input_pcm);
     pa_assert(!m->output_pcm);
 
-    pa_xfree(m->ucm_context.ucm_devices);
+    ucm_mapping_context_free(&m->ucm_context);
 
     pa_xfree(m);
 }
@@ -4449,17 +4449,7 @@ void pa_alsa_profile_set_probe(
     /* Clean up */
     profile_finalize_probing(last, NULL);
 
-    PA_HASHMAP_FOREACH(p, ps->profiles, state)
-        if (!p->supported) {
-            pa_hashmap_remove(ps->profiles, p->name);
-            profile_free(p);
-        }
-
-    PA_HASHMAP_FOREACH(m, ps->mappings, state)
-        if (m->supported <= 0) {
-            pa_hashmap_remove(ps->mappings, m->name);
-            mapping_free(m);
-        }
+    pa_alsa_profile_set_drop_unsupported(ps);
 
     paths_drop_unsupported(ps->input_paths);
     paths_drop_unsupported(ps->output_paths);
@@ -4494,6 +4484,24 @@ void pa_alsa_profile_set_dump(pa_alsa_profile_set *ps) {
         pa_alsa_decibel_fix_dump(db_fix);
 }
 
+void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *ps) {
+    pa_alsa_profile *p;
+    pa_alsa_mapping *m;
+    void *state;
+
+    PA_HASHMAP_FOREACH(p, ps->profiles, state)
+        if (!p->supported) {
+            pa_hashmap_remove(ps->profiles, p->name);
+            profile_free(p);
+        }
+
+    PA_HASHMAP_FOREACH(m, ps->mappings, state)
+        if (m->supported <= 0) {
+            pa_hashmap_remove(ps->mappings, m->name);
+            mapping_free(m);
+        }
+}
+
 static pa_device_port* device_port_alsa_init(pa_hashmap *ports,
     const char* name,
     const char* description,
diff --git a/src/modules/alsa/alsa-mixer.h b/src/modules/alsa/alsa-mixer.h
index 4234a2b..c640915 100644
--- a/src/modules/alsa/alsa-mixer.h
+++ b/src/modules/alsa/alsa-mixer.h
@@ -323,6 +323,7 @@ pa_alsa_profile_set* pa_alsa_profile_set_new(const char *fname, const pa_channel
 void pa_alsa_profile_set_probe(pa_alsa_profile_set *ps, const char *dev_id, const pa_sample_spec *ss, unsigned default_n_fragments, unsigned default_fragment_size_msec);
 void pa_alsa_profile_set_free(pa_alsa_profile_set *s);
 void pa_alsa_profile_set_dump(pa_alsa_profile_set *s);
+void pa_alsa_profile_set_drop_unsupported(pa_alsa_profile_set *s);
 
 snd_mixer_t *pa_alsa_open_mixer_for_pcm(snd_pcm_t *pcm, char **ctl_device, snd_hctl_t **hctl);
 
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
index 2d299e3..705518b 100644
--- a/src/modules/alsa/alsa-ucm.c
+++ b/src/modules/alsa/alsa-ucm.c
@@ -590,6 +590,7 @@ static void ucm_add_port_combination(pa_hashmap *hash, pa_alsa_ucm_mapping_conte
         pa_log_debug("Add port %s: %s", port->name, port->description);
         port->profiles = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     }
+
     port->priority = priority;
     if (is_sink)
         port->is_output = TRUE;
@@ -926,8 +927,8 @@ static int ucm_create_mapping_direction(struct pa_alsa_ucm_config *ucm,
     channels = is_sink ? device->playback_channels : device->capture_channels;
     if (m->ucm_context.ucm_devices_num == 0)
     {   /* new mapping */
-        m->supported = TRUE;
         m->ucm_context.ucm = ucm;
+        m->ucm_context.direction = is_sink ? PA_ALSA_UCM_DIRECT_SINK : PA_ALSA_UCM_DIRECT_SOURCE;
 
         m->device_strings = pa_xnew0(char*, 2);
         m->device_strings[0] = pa_xstrdup(device_str);
@@ -970,6 +971,24 @@ static int ucm_create_mapping(struct pa_alsa_ucm_config *ucm,
     return ret;
 }
 
+static pa_alsa_jack* ucm_get_jack(struct pa_alsa_ucm_config *ucm, const char *dev_name) {
+    pa_alsa_jack *j;
+
+    PA_LLIST_FOREACH(j, ucm->jacks)
+        if (pa_streq(j->name, dev_name))
+            return j;
+
+    j = pa_xnew0(pa_alsa_jack, 1);
+    j->state_unplugged = PA_PORT_AVAILABLE_NO;
+    j->state_plugged = PA_PORT_AVAILABLE_YES;
+    j->name = pa_xstrdup(dev_name);
+    j->alsa_name = pa_sprintf_malloc("%s Jack", dev_name);
+
+    PA_LLIST_PREPEND(pa_alsa_jack, ucm->jacks, j);
+
+    return j;
+}
+
 static int ucm_create_profile(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps,
         struct pa_alsa_ucm_verb *verb, const char *verb_name, const char *verb_desc) {
     struct pa_alsa_profile *p;
@@ -991,7 +1010,7 @@ static int ucm_create_profile(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_se
     p->output_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
     p->input_mappings = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
-    p->supported = 1;
+    p->supported = TRUE;
     pa_hashmap_put(ps->profiles, p->name, p);
 
     /* TODO: get profile priority from ucm info or policy management */
@@ -1026,12 +1045,146 @@ static int ucm_create_profile(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_se
         source = pa_proplist_gets(dev->proplist, PA_PROP_UCM_SOURCE);
 
         ucm_create_mapping(ucm, ps, p, dev, verb_name, dev_name, sink, source);
+        dev->jack = ucm_get_jack(ucm, dev_name);
     }
     pa_alsa_profile_dump(p);
 
     return 0;
 }
 
+static snd_pcm_t* mapping_open_pcm(struct pa_alsa_ucm_config *ucm,
+        pa_alsa_mapping *m, int mode) {
+    pa_sample_spec try_ss = ucm->core->default_sample_spec;
+    pa_channel_map try_map = m->channel_map;
+    snd_pcm_uframes_t try_period_size, try_buffer_size;
+
+    try_ss.channels = try_map.channels;
+
+    try_period_size =
+        pa_usec_to_bytes(ucm->core->default_fragment_size_msec * PA_USEC_PER_MSEC, &try_ss) /
+        pa_frame_size(&try_ss);
+    try_buffer_size = ucm->core->default_n_fragments * try_period_size;
+
+    return pa_alsa_open_by_device_string(m->device_strings[0], NULL, &try_ss,
+                              &try_map, mode, &try_period_size,
+                              &try_buffer_size, 0, NULL, NULL, TRUE);
+}
+
+static void profile_finalize_probing(pa_alsa_profile *p) {
+    pa_alsa_mapping *m;
+    uint32_t idx;
+
+    PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
+        if (!m->output_pcm)
+            continue;
+
+        if (p->supported)
+            m->supported++;
+
+        snd_pcm_close(m->output_pcm);
+        m->output_pcm = NULL;
+    }
+
+    PA_IDXSET_FOREACH(m, p->input_mappings, idx) {
+        if (!m->input_pcm)
+            continue;
+
+        if (p->supported)
+            m->supported++;
+
+        snd_pcm_close(m->input_pcm);
+        m->input_pcm = NULL;
+    }
+}
+
+static struct pa_alsa_ucm_device *find_ucm_dev(
+        struct pa_alsa_ucm_verb *verb, const char *dev_name) {
+    struct pa_alsa_ucm_device *dev;
+
+    PA_LLIST_FOREACH(dev, verb->devices) {
+        const char *name = pa_proplist_gets(dev->proplist, PA_PROP_UCM_NAME);
+        if (pa_streq(name, dev_name))
+            return dev;
+    }
+
+    return NULL;
+}
+
+static void ucm_mapping_jack_probe(pa_alsa_mapping *m) {
+    snd_pcm_t *pcm_handle;
+    snd_mixer_t *mixer_handle;
+    snd_hctl_t *hctl_handle;
+    pa_alsa_ucm_mapping_context *context = &m->ucm_context;
+    struct pa_alsa_ucm_device *dev;
+    int i;
+
+    pcm_handle = m->direction == PA_ALSA_DIRECTION_OUTPUT ? m->output_pcm : m->input_pcm;
+    mixer_handle = pa_alsa_open_mixer_for_pcm(pcm_handle, NULL, &hctl_handle);
+    if (!mixer_handle || !hctl_handle)
+        return;
+
+    for (i=0; i<context->ucm_devices_num; i++) {
+        dev = context->ucm_devices[i];
+        pa_assert (dev->jack);
+        dev->jack->has_control = pa_alsa_find_jack(hctl_handle, dev->jack->alsa_name) != NULL;
+        pa_log_info("ucm_mapping_jack_probe: %s has_control=%d", dev->jack->name, dev->jack->has_control);
+    }
+
+    snd_mixer_close(mixer_handle);
+}
+
+static void ucm_probe_jacks(struct pa_alsa_ucm_config *ucm, pa_alsa_profile_set *ps) {
+    void *state;
+    pa_alsa_profile *p;
+    pa_alsa_mapping *m;
+    uint32_t idx;
+
+    PA_HASHMAP_FOREACH(p, ps->profiles, state) {
+        /* change verb */
+        pa_log_info("ucm_probe_jacks: set ucm verb to %s", p->name);
+        if ((snd_use_case_set(ucm->ucm_mgr, "_verb", p->name)) < 0) {
+            pa_log("ucm_probe_jacks: failed to set verb %s", p->name);
+            p->supported = FALSE;
+            continue;
+        }
+        PA_IDXSET_FOREACH(m, p->output_mappings, idx) {
+            m->output_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_PLAYBACK);
+            if (!m->output_pcm) {
+                p->supported = FALSE;
+                break;
+            }
+        }
+        if (p->supported) {
+            PA_IDXSET_FOREACH(m, p->input_mappings, idx) {
+                m->input_pcm = mapping_open_pcm(ucm, m, SND_PCM_STREAM_CAPTURE);
+                if (!m->input_pcm) {
+                    p->supported = FALSE;
+                    break;
+                }
+            }
+        }
+        if (!p->supported) {
+            profile_finalize_probing(p);
+            continue;
+        }
+
+        pa_log_debug("Profile %s supported.", p->name);
+
+        PA_IDXSET_FOREACH(m, p->output_mappings, idx)
+            ucm_mapping_jack_probe(m);
+
+        PA_IDXSET_FOREACH(m, p->input_mappings, idx)
+            ucm_mapping_jack_probe(m);
+
+        profile_finalize_probing(p);
+    }
+
+    /* restore ucm state */
+    snd_use_case_set(ucm->ucm_mgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
+
+    pa_alsa_profile_set_drop_unsupported(ps);
+}
+
 pa_alsa_profile_set* ucm_add_profile_set(struct pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map) {
     struct pa_alsa_ucm_verb *verb;
     pa_alsa_profile_set *ps;
@@ -1055,6 +1208,8 @@ pa_alsa_profile_set* ucm_add_profile_set(struct pa_alsa_ucm_config *ucm, pa_chan
 
 	    ucm_create_profile(ucm, ps, verb, verb_name, verb_desc);
     }
+
+    ucm_probe_jacks(ucm, ps);
     ps->probed = TRUE;
 
     return ps;
@@ -1090,11 +1245,18 @@ static void free_verb(struct pa_alsa_ucm_verb *verb) {
 
 void ucm_free(struct pa_alsa_ucm_config *ucm) {
     struct pa_alsa_ucm_verb *vi, *vn;
+    pa_alsa_jack *ji, *jn;
 
     PA_LLIST_FOREACH_SAFE(vi, vn, ucm->verbs) {
         PA_LLIST_REMOVE(pa_alsa_ucm_verb, ucm->verbs, vi);
         free_verb(vi);
     }
+    PA_LLIST_FOREACH_SAFE(ji, jn, ucm->jacks) {
+        PA_LLIST_REMOVE(pa_alsa_jack, ucm->jacks, ji);
+        pa_xfree(ji->alsa_name);
+        pa_xfree(ji->name);
+        pa_xfree(ji);
+    }
     if (ucm->ucm_mgr)
     {
         snd_use_case_mgr_close(ucm->ucm_mgr);
@@ -1102,6 +1264,22 @@ void ucm_free(struct pa_alsa_ucm_config *ucm) {
     }
 }
 
+void ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context) {
+    struct pa_alsa_ucm_device *dev;
+    int i;
+
+    /* clear ucm device pointer to mapping */
+    for (i=0; i<context->ucm_devices_num; i++) {
+        dev = context->ucm_devices[i];
+        if (context->direction == PA_ALSA_UCM_DIRECT_SINK)
+            dev->playback_mapping = NULL;
+        else
+            dev->capture_mapping = NULL;
+    }
+
+    pa_xfree(context->ucm_devices);
+}
+
 static pa_bool_t stream_routed_to_mod_intent (struct pa_alsa_ucm_verb *verb,
         struct pa_alsa_ucm_modifier *mod, const char *mapping_name) {
     int i;
@@ -1113,15 +1291,12 @@ static pa_bool_t stream_routed_to_mod_intent (struct pa_alsa_ucm_verb *verb,
     for (i=0; i<mod->n_suppdev; i++) {
         dev_name = mod->supported_devices[i];
         /* first find the supported device */
-        PA_LLIST_FOREACH(dev, verb->devices) {
-            const char *name = pa_proplist_gets(dev->proplist, PA_PROP_UCM_NAME);
-            if (pa_streq(name, dev_name)) {
-                /* then match the mapping name */
-                mapping = mod->action_direct == PA_ALSA_UCM_DIRECT_SINK ? dev->playback_mapping : dev->capture_mapping;
-                if (mapping && pa_streq(mapping->name, mapping_name))
-                    return TRUE;
-                break;
-            }
+        dev = find_ucm_dev(verb, dev_name);
+        if (dev) {
+            /* then match the mapping name */
+            mapping = mod->action_direct == PA_ALSA_UCM_DIRECT_SINK ? dev->playback_mapping : dev->capture_mapping;
+            if (mapping && pa_streq(mapping->name, mapping_name))
+                return TRUE;
         }
     }
 
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
index 680be5a..625de18 100644
--- a/src/modules/alsa/alsa-ucm.h
+++ b/src/modules/alsa/alsa-ucm.h
@@ -27,6 +27,8 @@
 #include <asoundlib.h>
 #include <use-case.h>
 
+typedef struct pa_core pa_core;
+typedef struct pa_device_port pa_device_port;
 typedef struct pa_alsa_mapping pa_alsa_mapping;
 
 typedef struct pa_alsa_ucm_verb pa_alsa_ucm_verb;
@@ -35,9 +37,11 @@ typedef struct pa_alsa_ucm_device pa_alsa_ucm_device;
 typedef struct pa_alsa_ucm_config pa_alsa_ucm_config;
 typedef struct pa_alsa_ucm_mapping_context pa_alsa_ucm_mapping_context;
 typedef struct pa_alsa_port_data_ucm pa_alsa_port_data_ucm;
+typedef struct pa_alsa_jack pa_alsa_jack;
 
 int  ucm_set_profile(struct pa_alsa_ucm_config *ucm, const char *new_profile, const char *old_profile);
 void ucm_free(struct pa_alsa_ucm_config *ucm);
+void ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context);
 pa_alsa_profile_set* ucm_add_profile_set(struct pa_alsa_ucm_config *ucm, pa_channel_map *default_channel_map);
 int  ucm_get_verb(snd_use_case_mgr_t *uc_mgr, const char *verb_name, const char *verb_desc, struct pa_alsa_ucm_verb ** p_verb);
 void ucm_add_ports(pa_hashmap **p, pa_proplist *proplist, pa_alsa_ucm_mapping_context *context, int is_sink, pa_card *card);
@@ -70,6 +74,7 @@ struct pa_alsa_ucm_device {
     int n_suppdev;
     char **conflicting_devices;
     char **supported_devices;
+    pa_alsa_jack *jack;
 };
 
 struct pa_alsa_ucm_modifier {
@@ -94,14 +99,17 @@ struct pa_alsa_ucm_verb {
 };
 
 struct pa_alsa_ucm_config {
+    pa_core *core;
     snd_use_case_mgr_t *ucm_mgr;
     pa_alsa_ucm_verb *active_verb;
 
     PA_LLIST_HEAD(pa_alsa_ucm_verb, verbs);
+    PA_LLIST_HEAD(pa_alsa_jack, jacks);
 };
 
 struct pa_alsa_ucm_mapping_context {
     pa_alsa_ucm_config *ucm;
+    int direction;
     int ucm_devices_num;
     pa_alsa_ucm_device **ucm_devices;
 };
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
index d7f1043..659bddb 100644
--- a/src/modules/alsa/module-alsa-card.c
+++ b/src/modules/alsa/module-alsa-card.c
@@ -326,14 +326,22 @@ static void report_port_state(pa_device_port *p, struct userdata *u)
     void *state;
     pa_alsa_jack *jack;
     pa_port_available_t pa = PA_PORT_AVAILABLE_UNKNOWN;
+    pa_device_port *port;
 
     PA_HASHMAP_FOREACH(jack, u->jacks, state) {
         pa_port_available_t cpa;
 
-        if (!jack->path)
-            continue;
+        if (u->use_ucm) {
+            port = pa_hashmap_get(u->card->ports, jack->name);
+        }
+        else {
+            if (jack->path)
+                port = jack->path->port;
+            else
+                continue;
+        }
 
-        if (p != jack->path->port)
+        if (p != port)
             continue;
 
         cpa = jack->plugged_in ? jack->state_plugged : jack->state_unplugged;
@@ -359,6 +367,7 @@ static int report_jack_state(snd_hctl_elem_t *elem, unsigned int mask)
     pa_bool_t plugged_in;
     void *state;
     pa_alsa_jack *jack;
+    pa_device_port *port;
 
     pa_assert(u);
 
@@ -378,8 +387,16 @@ static int report_jack_state(snd_hctl_elem_t *elem, unsigned int mask)
     PA_HASHMAP_FOREACH(jack, u->jacks, state)
         if (jack->hctl_elem == elem) {
             jack->plugged_in = plugged_in;
-            pa_assert(jack->path && jack->path->port);
-            report_port_state(jack->path->port, u);
+            if (u->use_ucm) {
+                pa_assert(u->card->ports);
+                port = pa_hashmap_get(u->card->ports, jack->name);
+                pa_assert(port);
+            }
+            else {
+                pa_assert(jack->path && jack->path->port);
+                port = jack->path->port;
+            }
+            report_port_state(port, u);
         }
     return 0;
 }
@@ -391,18 +408,25 @@ static void init_jacks(struct userdata *u) {
 
     u->jacks = pa_hashmap_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
 
-    /* See if we have any jacks */
-    if (u->profile_set->output_paths)
-        PA_HASHMAP_FOREACH(path, u->profile_set->output_paths, state)
-            PA_LLIST_FOREACH(jack, path->jacks)
+    if (u->use_ucm) {
+        PA_LLIST_FOREACH(jack, u->ucm.jacks)
+            if (jack->has_control)
+                pa_hashmap_put(u->jacks, jack, jack);
+    }
+    else {
+        /* See if we have any jacks */
+        if (u->profile_set->output_paths)
+            PA_HASHMAP_FOREACH(path, u->profile_set->output_paths, state)
+                PA_LLIST_FOREACH(jack, path->jacks)
                 if (jack->has_control)
                     pa_hashmap_put(u->jacks, jack, jack);
 
-    if (u->profile_set->input_paths)
-        PA_HASHMAP_FOREACH(path, u->profile_set->input_paths, state)
-            PA_LLIST_FOREACH(jack, path->jacks)
+        if (u->profile_set->input_paths)
+            PA_HASHMAP_FOREACH(path, u->profile_set->input_paths, state)
+                PA_LLIST_FOREACH(jack, path->jacks)
                 if (jack->has_control)
                     pa_hashmap_put(u->jacks, jack, jack);
+    }
 
     pa_log_debug("Found %d jacks.", pa_hashmap_size(u->jacks));
 
@@ -652,6 +676,8 @@ int pa__init(pa_module *m) {
     u->device_id = pa_xstrdup(pa_modargs_get_value(ma, "device_id", DEFAULT_DEVICE_ID));
     u->modargs = ma;
 
+    u->ucm.core = m->core;
+
     if ((u->alsa_card_index = snd_card_get_index(u->device_id)) < 0) {
         pa_log("Card '%s' doesn't exist: %s", u->device_id, pa_alsa_strerror(u->alsa_card_index));
         goto fail;
@@ -881,8 +907,6 @@ void pa__done(pa_module*m) {
             pa_alsa_source_free(s);
     }
 
-    ucm_free(&u->ucm);
-
     if (u->card)
         pa_card_free(u->card);
 
@@ -892,6 +916,8 @@ void pa__done(pa_module*m) {
     if (u->profile_set)
         pa_alsa_profile_set_free(u->profile_set);
 
+    ucm_free(&u->ucm);
+
     pa_xfree(u->device_id);
     pa_xfree(u);
 
