udev: when a device appears that we cannot access right-away try again later on inotify
[pulseaudio-mirror.git] / src / modules / module-udev-detect.c
blob22ce8c3ce9895d3d161e91685d5eef72ab866899
1 /***
2 This file is part of PulseAudio.
4 Copyright 2009 Lennart Poettering
6 PulseAudio is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as
8 published by the Free Software Foundation; either version 2.1 of the
9 License, or (at your option) any later version.
11 PulseAudio is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with PulseAudio; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19 USA.
20 ***/
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
26 #include <errno.h>
27 #include <limits.h>
28 #include <sys/inotify.h>
29 #include <libudev.h>
31 #include <pulsecore/modargs.h>
32 #include <pulsecore/core-error.h>
33 #include <pulsecore/core-util.h>
34 #include <pulsecore/namereg.h>
36 #include "module-udev-detect-symdef.h"
38 PA_MODULE_AUTHOR("Lennart Poettering");
39 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
40 PA_MODULE_VERSION(PACKAGE_VERSION);
41 PA_MODULE_LOAD_ONCE(TRUE);
42 PA_MODULE_USAGE(
43 "tsched=<enable system timer based scheduling mode?> "
44 "ignore_dB=<ignore dB information from the device?>");
46 struct device {
47 char *path;
48 pa_bool_t accessible;
49 char *card_name;
50 char *args;
51 uint32_t module;
54 struct userdata {
55 pa_core *core;
56 pa_hashmap *devices;
58 pa_bool_t use_tsched:1;
59 pa_bool_t ignore_dB:1;
61 struct udev* udev;
62 struct udev_monitor *monitor;
63 pa_io_event *udev_io;
65 int inotify_fd;
66 pa_io_event *inotify_io;
69 static const char* const valid_modargs[] = {
70 "tsched",
71 "ignore_dB",
72 NULL
75 static int setup_inotify(struct userdata *u);
77 static void device_free(struct device *d) {
78 pa_assert(d);
80 pa_xfree(d->path);
81 pa_xfree(d->card_name);
82 pa_xfree(d->args);
83 pa_xfree(d);
86 static const char *path_get_card_id(const char *path) {
87 const char *e;
89 if (!path)
90 return NULL;
92 if (!(e = strrchr(path, '/')))
93 return NULL;
95 if (!pa_startswith(e, "/card"))
96 return NULL;
98 return e + 5;
101 static void verify_access(struct userdata *u, struct device *d) {
102 char *cd;
103 pa_card *card;
105 pa_assert(u);
106 pa_assert(d);
108 cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path));
109 d->accessible = access(cd, R_OK|W_OK) >= 0;
110 pa_xfree(cd);
112 pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible));
114 if (d->module == PA_INVALID_INDEX) {
116 /* If we not loaded, try to load */
118 if (d->accessible) {
119 pa_module *m;
121 pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args);
122 m = pa_module_load(u->core, "module-alsa-card", d->args);
124 if (m) {
125 d->module = m->index;
126 pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name);
127 } else
128 pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name);
131 } else {
133 /* If we are already loaded update suspend status with
134 * accessible boolean */
136 if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD)))
137 pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION);
141 static void card_changed(struct userdata *u, struct udev_device *dev) {
142 struct device *d;
143 const char *path;
144 const char *t;
145 pa_module *m;
146 char *n;
148 pa_assert(u);
149 pa_assert(dev);
151 /* Maybe /dev/snd is now available? */
152 setup_inotify(u);
154 path = udev_device_get_devpath(dev);
156 if ((d = pa_hashmap_get(u->devices, path))) {
157 verify_access(u, d);
158 return;
161 d = pa_xnew0(struct device, 1);
162 d->path = pa_xstrdup(path);
163 d->accessible = TRUE;
164 d->module = PA_INVALID_INDEX;
166 if (!(t = udev_device_get_property_value(dev, "PULSE_NAME")))
167 if (!(t = udev_device_get_property_value(dev, "ID_ID")))
168 if (!(t = udev_device_get_property_value(dev, "ID_PATH")))
169 t = path_get_card_id(path);
171 n = pa_namereg_make_valid_name(t);
172 d->card_name = pa_sprintf_malloc("alsa_card.%s", n);
173 d->args = pa_sprintf_malloc("device_id=\"%s\" "
174 "name=\"%s\" "
175 "card_name=\"%s\" "
176 "tsched=%s "
177 "ignore_dB=%s "
178 "card_properties=\"module-udev-detect.discovered=1\"",
179 path_get_card_id(path),
181 d->card_name,
182 pa_yes_no(u->use_tsched),
183 pa_yes_no(u->ignore_dB));
184 pa_xfree(n);
186 pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args);
187 m = pa_module_load(u->core, "module-alsa-card", d->args);
189 if (m) {
190 d->module = m->index;
191 pa_log_info("Card %s (%s) added and module loaded.", path, d->card_name);
192 } else
193 pa_log_info("Card %s (%s) added but failed to load module.", path, d->card_name);
195 pa_hashmap_put(u->devices, d->path, d);
198 static void remove_card(struct userdata *u, struct udev_device *dev) {
199 struct device *d;
201 pa_assert(u);
202 pa_assert(dev);
204 if (!(d = pa_hashmap_remove(u->devices, udev_device_get_devpath(dev))))
205 return;
207 pa_log_info("Card %s removed.", d->path);
209 if (d->module != PA_INVALID_INDEX)
210 pa_module_unload_request_by_index(u->core, d->module, TRUE);
212 device_free(d);
215 static void process_device(struct userdata *u, struct udev_device *dev) {
216 const char *action, *ff;
218 pa_assert(u);
219 pa_assert(dev);
221 if (udev_device_get_property_value(dev, "PULSE_IGNORE")) {
222 pa_log_debug("Ignoring %s, because marked so.", udev_device_get_devpath(dev));
223 return;
226 if ((ff = udev_device_get_property_value(dev, "SOUND_FORM_FACTOR")) &&
227 pa_streq(ff, "modem")) {
228 pa_log_debug("Ignoring %s, because it is a modem.", udev_device_get_devpath(dev));
229 return;
232 action = udev_device_get_action(dev);
234 if (action && pa_streq(action, "remove"))
235 remove_card(u, dev);
236 else if ((!action || pa_streq(action, "change")) &&
237 udev_device_get_property_value(dev, "SOUND_INITIALIZED"))
238 card_changed(u, dev);
240 /* For an explanation why we don't look for 'add' events here
241 * have a look into /lib/udev/rules.d/78-sound-card.rules! */
244 static void process_path(struct userdata *u, const char *path) {
245 struct udev_device *dev;
247 if (!path_get_card_id(path))
248 return;
250 if (!(dev = udev_device_new_from_syspath(u->udev, path))) {
251 pa_log("Failed to get udev device object from udev.");
252 return;
255 process_device(u, dev);
256 udev_device_unref(dev);
259 static void monitor_cb(
260 pa_mainloop_api*a,
261 pa_io_event* e,
262 int fd,
263 pa_io_event_flags_t events,
264 void *userdata) {
266 struct userdata *u = userdata;
267 struct udev_device *dev;
269 pa_assert(a);
271 if (!(dev = udev_monitor_receive_device(u->monitor))) {
272 pa_log("Failed to get udev device object from monitor.");
273 goto fail;
276 if (!path_get_card_id(udev_device_get_devpath(dev)))
277 return;
279 process_device(u, dev);
280 udev_device_unref(dev);
281 return;
283 fail:
284 a->io_free(u->udev_io);
285 u->udev_io = NULL;
288 static void inotify_cb(
289 pa_mainloop_api*a,
290 pa_io_event* e,
291 int fd,
292 pa_io_event_flags_t events,
293 void *userdata) {
295 struct {
296 struct inotify_event e;
297 char name[NAME_MAX];
298 } buf;
299 struct userdata *u = userdata;
300 static int type = 0;
301 pa_bool_t verify = FALSE, deleted = FALSE;
303 for (;;) {
304 ssize_t r;
306 pa_zero(buf);
307 if ((r = pa_read(fd, &buf, sizeof(buf), &type)) <= 0) {
309 if (r < 0 && errno == EAGAIN)
310 break;
312 pa_log("read() from inotify failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
313 goto fail;
316 if ((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC"))
317 verify = TRUE;
319 if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF)))
320 deleted = TRUE;
323 if (verify) {
324 struct device *d;
325 void *state;
327 pa_log_debug("Verifying access.");
329 PA_HASHMAP_FOREACH(d, u->devices, state)
330 verify_access(u, d);
333 if (!deleted)
334 return;
336 fail:
337 if (u->inotify_io) {
338 a->io_free(u->inotify_io);
339 u->inotify_io = NULL;
342 if (u->inotify_fd >= 0) {
343 pa_close(u->inotify_fd);
344 u->inotify_fd = -1;
348 static int setup_inotify(struct userdata *u) {
349 char *dev_snd;
350 int r;
352 if (u->inotify_fd >= 0)
353 return 0;
355 if ((u->inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
356 pa_log("inotify_init1() failed: %s", pa_cstrerror(errno));
357 return -1;
360 dev_snd = pa_sprintf_malloc("%s/snd", udev_get_dev_path(u->udev));
361 r = inotify_add_watch(u->inotify_fd, dev_snd, IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF);
362 pa_xfree(dev_snd);
364 if (r < 0) {
365 int saved_errno = errno;
367 pa_close(u->inotify_fd);
368 u->inotify_fd = -1;
370 if (saved_errno == ENOENT) {
371 pa_log_debug("/dev/snd/ is apparently not existing yet, retrying to create inotify watch later.");
372 return 0;
375 if (saved_errno == ENOSPC) {
376 pa_log("You apparently ran out of inotify watches, probably because Tracker/Beagle took them all away. "
377 "I wished people would do their homework first and fix inotify before using it for watching whole "
378 "directory trees which is something the current inotify is certainly not useful for. "
379 "Please make sure to drop the Tracker/Beagle guys a line complaining about their broken use of inotify.");
380 return 0;
383 pa_log("inotify_add_watch() failed: %s", pa_cstrerror(saved_errno));
384 return -1;
387 pa_assert_se(u->inotify_io = u->core->mainloop->io_new(u->core->mainloop, u->inotify_fd, PA_IO_EVENT_INPUT, inotify_cb, u));
389 return 0;
392 int pa__init(pa_module *m) {
393 struct userdata *u = NULL;
394 pa_modargs *ma;
395 struct udev_enumerate *enumerate = NULL;
396 struct udev_list_entry *item = NULL, *first = NULL;
397 int fd;
398 pa_bool_t use_tsched = TRUE, ignore_dB = FALSE;
400 pa_assert(m);
402 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
403 pa_log("Failed to parse module arguments");
404 goto fail;
407 m->userdata = u = pa_xnew0(struct userdata, 1);
408 u->core = m->core;
409 u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
410 u->inotify_fd = -1;
412 if (pa_modargs_get_value_boolean(ma, "tsched", &use_tsched) < 0) {
413 pa_log("Failed to parse tsched= argument.");
414 goto fail;
416 u->use_tsched = use_tsched;
418 if (pa_modargs_get_value_boolean(ma, "ignore_dB", &ignore_dB) < 0) {
419 pa_log("Failed to parse ignore_dB= argument.");
420 goto fail;
422 u->ignore_dB = ignore_dB;
424 if (!(u->udev = udev_new())) {
425 pa_log("Failed to initialize udev library.");
426 goto fail;
429 if (setup_inotify(u) < 0)
430 goto fail;
432 if (!(u->monitor = udev_monitor_new_from_netlink(u->udev, "udev"))) {
433 pa_log("Failed to initialize monitor.");
434 goto fail;
437 errno = 0;
438 if (udev_monitor_enable_receiving(u->monitor) < 0) {
439 pa_log("Failed to enable monitor: %s", pa_cstrerror(errno));
440 if (errno == EPERM)
441 pa_log_info("Most likely your kernel is simply too old and "
442 "allows only priviliged processes to listen to device events. "
443 "Please upgrade your kernel to at least 2.6.30.");
444 goto fail;
447 if ((fd = udev_monitor_get_fd(u->monitor)) < 0) {
448 pa_log("Failed to get udev monitor fd.");
449 goto fail;
452 pa_assert_se(u->udev_io = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, monitor_cb, u));
454 if (!(enumerate = udev_enumerate_new(u->udev))) {
455 pa_log("Failed to initialize udev enumerator.");
456 goto fail;
459 if (udev_enumerate_add_match_subsystem(enumerate, "sound") < 0) {
460 pa_log("Failed to match to subsystem.");
461 goto fail;
464 if (udev_enumerate_scan_devices(enumerate) < 0) {
465 pa_log("Failed to scan for devices.");
466 goto fail;
469 first = udev_enumerate_get_list_entry(enumerate);
470 udev_list_entry_foreach(item, first)
471 process_path(u, udev_list_entry_get_name(item));
473 udev_enumerate_unref(enumerate);
475 pa_log_info("Loaded %u modules.", pa_hashmap_size(u->devices));
477 pa_modargs_free(ma);
479 return 0;
481 fail:
483 if (enumerate)
484 udev_enumerate_unref(enumerate);
486 if (ma)
487 pa_modargs_free(ma);
489 pa__done(m);
491 return -1;
494 void pa__done(pa_module *m) {
495 struct userdata *u;
497 pa_assert(m);
499 if (!(u = m->userdata))
500 return;
502 if (u->udev_io)
503 m->core->mainloop->io_free(u->udev_io);
505 if (u->monitor)
506 udev_monitor_unref(u->monitor);
508 if (u->udev)
509 udev_unref(u->udev);
511 if (u->inotify_io)
512 m->core->mainloop->io_free(u->inotify_io);
514 if (u->inotify_fd >= 0)
515 pa_close(u->inotify_fd);
517 if (u->devices) {
518 struct device *d;
520 while ((d = pa_hashmap_steal_first(u->devices)))
521 device_free(d);
523 pa_hashmap_free(u->devices, NULL, NULL);
526 pa_xfree(u);