summaryrefslogtreecommitdiffstats
path: root/src/modules/module-udev-detect.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/module-udev-detect.c')
-rw-r--r--src/modules/module-udev-detect.c158
1 files changed, 106 insertions, 52 deletions
diff --git a/src/modules/module-udev-detect.c b/src/modules/module-udev-detect.c
index 0b30fd54..1d67c0cc 100644
--- a/src/modules/module-udev-detect.c
+++ b/src/modules/module-udev-detect.c
@@ -45,8 +45,10 @@ PA_MODULE_USAGE(
struct device {
char *path;
- pa_bool_t accessible;
+ pa_bool_t accessible:1;
+ pa_bool_t need_verify:1;
char *card_name;
+ char *args;
uint32_t module;
};
@@ -78,6 +80,7 @@ static void device_free(struct device *d) {
pa_xfree(d->path);
pa_xfree(d->card_name);
+ pa_xfree(d->args);
pa_xfree(d);
}
@@ -103,23 +106,43 @@ static void verify_access(struct userdata *u, struct device *d) {
pa_assert(u);
pa_assert(d);
- if (!(card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD)))
- return;
-
cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path));
- d->accessible = access(cd, W_OK) >= 0;
+ d->accessible = access(cd, R_OK|W_OK) >= 0;
+
pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible));
pa_xfree(cd);
- pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION);
+ if (d->module == PA_INVALID_INDEX) {
+
+ /* If we not loaded, try to load */
+
+ if (d->accessible) {
+ pa_module *m;
+
+ pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args);
+ m = pa_module_load(u->core, "module-alsa-card", d->args);
+
+ if (m) {
+ d->module = m->index;
+ pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name);
+ } else
+ pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name);
+ }
+
+ } else {
+
+ /* If we are already loaded update suspend status with
+ * accessible boolean */
+
+ if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD)))
+ pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION);
+ }
}
static void card_changed(struct userdata *u, struct udev_device *dev) {
struct device *d;
const char *path;
const char *t;
- char *card_name, *args;
- pa_module *m;
char *n;
pa_assert(u);
@@ -135,44 +158,34 @@ static void card_changed(struct userdata *u, struct udev_device *dev) {
return;
}
+ d = pa_xnew0(struct device, 1);
+ d->path = pa_xstrdup(path);
+ d->accessible = TRUE;
+ d->module = PA_INVALID_INDEX;
+
if (!(t = udev_device_get_property_value(dev, "PULSE_NAME")))
if (!(t = udev_device_get_property_value(dev, "ID_ID")))
if (!(t = udev_device_get_property_value(dev, "ID_PATH")))
t = path_get_card_id(path);
n = pa_namereg_make_valid_name(t);
+ d->card_name = pa_sprintf_malloc("alsa_card.%s", n);
+ d->args = pa_sprintf_malloc("device_id=\"%s\" "
+ "name=\"%s\" "
+ "card_name=\"%s\" "
+ "tsched=%s "
+ "ignore_dB=%s "
+ "card_properties=\"module-udev-detect.discovered=1\"",
+ path_get_card_id(path),
+ n,
+ d->card_name,
+ pa_yes_no(u->use_tsched),
+ pa_yes_no(u->ignore_dB));
+ pa_xfree(n);
- card_name = pa_sprintf_malloc("alsa_card.%s", n);
- args = pa_sprintf_malloc("device_id=\"%s\" "
- "name=\"%s\" "
- "card_name=\"%s\" "
- "tsched=%s "
- "ignore_dB=%s "
- "card_properties=\"module-udev-detect.discovered=1\"",
- path_get_card_id(path),
- n,
- card_name,
- pa_yes_no(u->use_tsched),
- pa_yes_no(u->ignore_dB));
-
- pa_log_debug("Loading module-alsa-card with arguments '%s'", args);
- m = pa_module_load(u->core, "module-alsa-card", args);
- pa_xfree(args);
-
- if (m) {
- pa_log_info("Card %s (%s) added.", path, n);
-
- d = pa_xnew(struct device, 1);
- d->path = pa_xstrdup(path);
- d->card_name = card_name;
- d->module = m->index;
- d->accessible = TRUE;
-
- pa_hashmap_put(u->devices, d->path, d);
- } else
- pa_xfree(card_name);
+ pa_hashmap_put(u->devices, d->path, d);
- pa_xfree(n);
+ verify_access(u, d);
}
static void remove_card(struct userdata *u, struct udev_device *dev) {
@@ -185,7 +198,10 @@ static void remove_card(struct userdata *u, struct udev_device *dev) {
return;
pa_log_info("Card %s removed.", d->path);
- pa_module_unload_request_by_index(u->core, d->module, TRUE);
+
+ if (d->module != PA_INVALID_INDEX)
+ pa_module_unload_request_by_index(u->core, d->module, TRUE);
+
device_free(d);
}
@@ -262,6 +278,34 @@ fail:
u->udev_io = NULL;
}
+static pa_bool_t pcm_node_belongs_to_device(
+ struct device *d,
+ const char *node) {
+
+ char *cd;
+ pa_bool_t b;
+
+ cd = pa_sprintf_malloc("pcmC%sD", path_get_card_id(d->path));
+ b = pa_startswith(node, cd);
+ pa_xfree(cd);
+
+ return b;
+}
+
+static pa_bool_t control_node_belongs_to_device(
+ struct device *d,
+ const char *node) {
+
+ char *cd;
+ pa_bool_t b;
+
+ cd = pa_sprintf_malloc("controlC%s", path_get_card_id(d->path));
+ b = pa_streq(node, cd);
+ pa_xfree(cd);
+
+ return b;
+}
+
static void inotify_cb(
pa_mainloop_api*a,
pa_io_event* e,
@@ -275,7 +319,9 @@ static void inotify_cb(
} buf;
struct userdata *u = userdata;
static int type = 0;
- pa_bool_t verify = FALSE, deleted = FALSE;
+ pa_bool_t deleted = FALSE;
+ struct device *d;
+ void *state;
for (;;) {
ssize_t r;
@@ -290,22 +336,30 @@ static void inotify_cb(
goto fail;
}
- if ((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC"))
- verify = TRUE;
+ /* From udev we get the guarantee that the control
+ * device's ACL is changes last. To avoid races when ACLs
+ * are changed we hence watch only the control device */
+ if (((buf.e.mask & IN_ATTRIB) && pa_startswith(buf.e.name, "controlC")))
+ PA_HASHMAP_FOREACH(d, u->devices, state)
+ if (control_node_belongs_to_device(d, buf.e.name))
+ d->need_verify = TRUE;
+
+ /* ALSA doesn't really give us any guarantee on the closing
+ * order, so let's simply hope */
+ if (((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC")))
+ PA_HASHMAP_FOREACH(d, u->devices, state)
+ if (pcm_node_belongs_to_device(d, buf.e.name))
+ d->need_verify = TRUE;
if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF)))
deleted = TRUE;
}
- if (verify) {
- struct device *d;
- void *state;
-
- pa_log_debug("Verifying access.");
-
- PA_HASHMAP_FOREACH(d, u->devices, state)
+ PA_HASHMAP_FOREACH(d, u->devices, state)
+ if (d->need_verify) {
+ d->need_verify = FALSE;
verify_access(u, d);
- }
+ }
if (!deleted)
return;
@@ -335,7 +389,7 @@ static int setup_inotify(struct userdata *u) {
}
dev_snd = pa_sprintf_malloc("%s/snd", udev_get_dev_path(u->udev));
- r = inotify_add_watch(u->inotify_fd, dev_snd, IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF);
+ r = inotify_add_watch(u->inotify_fd, dev_snd, IN_ATTRIB|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF);
pa_xfree(dev_snd);
if (r < 0) {
@@ -449,7 +503,7 @@ int pa__init(pa_module *m) {
udev_enumerate_unref(enumerate);
- pa_log_info("Loaded %u modules.", pa_hashmap_size(u->devices));
+ pa_log_info("Found %u cards.", pa_hashmap_size(u->devices));
pa_modargs_free(ma);