diff options
Diffstat (limited to 'src/modules/module-udev-detect.c')
-rw-r--r-- | src/modules/module-udev-detect.c | 158 |
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); |