]> code.delx.au - pulseaudio/blob - src/modules/module-udev-detect.c
Merge commit 'origin/master-tx'
[pulseaudio] / src / modules / module-udev-detect.c
1 /***
2 This file is part of PulseAudio.
3
4 Copyright 2009 Lennart Poettering
5
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.
10
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.
15
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 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <errno.h>
27 #include <limits.h>
28 #include <dirent.h>
29 #include <sys/inotify.h>
30 #include <libudev.h>
31
32 #include <pulsecore/modargs.h>
33 #include <pulsecore/core-error.h>
34 #include <pulsecore/core-util.h>
35 #include <pulsecore/namereg.h>
36
37 #include "module-udev-detect-symdef.h"
38
39 PA_MODULE_AUTHOR("Lennart Poettering");
40 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
41 PA_MODULE_VERSION(PACKAGE_VERSION);
42 PA_MODULE_LOAD_ONCE(TRUE);
43 PA_MODULE_USAGE(
44 "tsched=<enable system timer based scheduling mode?> "
45 "ignore_dB=<ignore dB information from the device?>");
46
47 struct device {
48 char *path;
49 pa_bool_t need_verify;
50 char *card_name;
51 char *args;
52 uint32_t module;
53 };
54
55 struct userdata {
56 pa_core *core;
57 pa_hashmap *devices;
58
59 pa_bool_t use_tsched:1;
60 pa_bool_t ignore_dB:1;
61
62 struct udev* udev;
63 struct udev_monitor *monitor;
64 pa_io_event *udev_io;
65
66 int inotify_fd;
67 pa_io_event *inotify_io;
68 };
69
70 static const char* const valid_modargs[] = {
71 "tsched",
72 "ignore_dB",
73 NULL
74 };
75
76 static int setup_inotify(struct userdata *u);
77
78 static void device_free(struct device *d) {
79 pa_assert(d);
80
81 pa_xfree(d->path);
82 pa_xfree(d->card_name);
83 pa_xfree(d->args);
84 pa_xfree(d);
85 }
86
87 static const char *path_get_card_id(const char *path) {
88 const char *e;
89
90 if (!path)
91 return NULL;
92
93 if (!(e = strrchr(path, '/')))
94 return NULL;
95
96 if (!pa_startswith(e, "/card"))
97 return NULL;
98
99 return e + 5;
100 }
101
102 static pa_bool_t is_card_busy(const char *id) {
103 char *card_path = NULL, *pcm_path = NULL, *sub_status = NULL;
104 DIR *card_dir = NULL, *pcm_dir = NULL;
105 FILE *status_file = NULL;
106 size_t len;
107 struct dirent *space = NULL, *de;
108 pa_bool_t busy = FALSE;
109 int r;
110
111 pa_assert(id);
112
113 card_path = pa_sprintf_malloc("/proc/asound/card%s", id);
114
115 if (!(card_dir = opendir(card_path))) {
116 pa_log_warn("Failed to open %s: %s", card_path, pa_cstrerror(errno));
117 goto fail;
118 }
119
120 len = offsetof(struct dirent, d_name) + fpathconf(dirfd(card_dir), _PC_NAME_MAX) + 1;
121 space = pa_xmalloc(len);
122
123 for (;;) {
124 de = NULL;
125
126 if ((r = readdir_r(card_dir, space, &de)) != 0) {
127 pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r));
128 goto fail;
129 }
130
131 if (!de)
132 break;
133
134 if (!pa_startswith(de->d_name, "pcm"))
135 continue;
136
137 pa_xfree(pcm_path);
138 pcm_path = pa_sprintf_malloc("%s/%s", card_path, de->d_name);
139
140 if (pcm_dir)
141 closedir(pcm_dir);
142
143 if (!(pcm_dir = opendir(pcm_path))) {
144 pa_log_warn("Failed to open %s: %s", pcm_path, pa_cstrerror(errno));
145 continue;
146 }
147
148 for (;;) {
149 char line[32];
150
151 if ((r = readdir_r(pcm_dir, space, &de)) != 0) {
152 pa_log_warn("readdir_r() failed: %s", pa_cstrerror(r));
153 goto fail;
154 }
155
156 if (!de)
157 break;
158
159 if (!pa_startswith(de->d_name, "sub"))
160 continue;
161
162 pa_xfree(sub_status);
163 sub_status = pa_sprintf_malloc("%s/%s/status", pcm_path, de->d_name);
164
165 if (status_file)
166 fclose(status_file);
167
168 if (!(status_file = fopen(sub_status, "r"))) {
169 pa_log_warn("Failed to open %s: %s", sub_status, pa_cstrerror(errno));
170 continue;
171 }
172
173 if (!(fgets(line, sizeof(line)-1, status_file))) {
174 pa_log_warn("Failed to read from %s: %s", sub_status, pa_cstrerror(errno));
175 continue;
176 }
177
178 if (!pa_streq(line, "closed\n")) {
179 busy = TRUE;
180 break;
181 }
182 }
183 }
184
185 fail:
186
187 pa_xfree(card_path);
188 pa_xfree(pcm_path);
189 pa_xfree(sub_status);
190 pa_xfree(space);
191
192 if (card_dir)
193 closedir(card_dir);
194
195 if (pcm_dir)
196 closedir(pcm_dir);
197
198 if (status_file)
199 fclose(status_file);
200
201 return busy;
202 }
203
204 static void verify_access(struct userdata *u, struct device *d) {
205 char *cd;
206 pa_card *card;
207 pa_bool_t accessible;
208
209 pa_assert(u);
210 pa_assert(d);
211
212 cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path));
213 accessible = access(cd, R_OK|W_OK) >= 0;
214 pa_log_debug("%s is accessible: %s", cd, pa_yes_no(accessible));
215
216 pa_xfree(cd);
217
218 if (d->module == PA_INVALID_INDEX) {
219
220 /* If we are not loaded, try to load */
221
222 if (accessible) {
223 pa_module *m;
224 pa_bool_t busy;
225
226 /* Check if any of the PCM devices that belong to this
227 * card are currently busy. If they are, don't try to load
228 * right now, to make sure the probing phase can
229 * successfully complete. When the current user of the
230 * device closes it we will get another notification via
231 * inotify and can then recheck. */
232
233 busy = is_card_busy(path_get_card_id(d->path));
234 pa_log_debug("%s is busy: %s", d->path, pa_yes_no(busy));
235
236 if (!busy) {
237 pa_log_debug("Loading module-alsa-card with arguments '%s'", d->args);
238 m = pa_module_load(u->core, "module-alsa-card", d->args);
239
240 if (m) {
241 d->module = m->index;
242 pa_log_info("Card %s (%s) module loaded.", d->path, d->card_name);
243 } else
244 pa_log_info("Card %s (%s) failed to load module.", d->path, d->card_name);
245 }
246 }
247
248 } else {
249
250 /* If we are already loaded update suspend status with
251 * accessible boolean */
252
253 if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD)))
254 pa_card_suspend(card, !accessible, PA_SUSPEND_SESSION);
255 }
256 }
257
258 static void card_changed(struct userdata *u, struct udev_device *dev) {
259 struct device *d;
260 const char *path;
261 const char *t;
262 char *n;
263
264 pa_assert(u);
265 pa_assert(dev);
266
267 /* Maybe /dev/snd is now available? */
268 setup_inotify(u);
269
270 path = udev_device_get_devpath(dev);
271
272 if ((d = pa_hashmap_get(u->devices, path))) {
273 verify_access(u, d);
274 return;
275 }
276
277 d = pa_xnew0(struct device, 1);
278 d->path = pa_xstrdup(path);
279 d->module = PA_INVALID_INDEX;
280
281 if (!(t = udev_device_get_property_value(dev, "PULSE_NAME")))
282 if (!(t = udev_device_get_property_value(dev, "ID_ID")))
283 if (!(t = udev_device_get_property_value(dev, "ID_PATH")))
284 t = path_get_card_id(path);
285
286 n = pa_namereg_make_valid_name(t);
287 d->card_name = pa_sprintf_malloc("alsa_card.%s", n);
288 d->args = pa_sprintf_malloc("device_id=\"%s\" "
289 "name=\"%s\" "
290 "card_name=\"%s\" "
291 "tsched=%s "
292 "ignore_dB=%s "
293 "card_properties=\"module-udev-detect.discovered=1\"",
294 path_get_card_id(path),
295 n,
296 d->card_name,
297 pa_yes_no(u->use_tsched),
298 pa_yes_no(u->ignore_dB));
299 pa_xfree(n);
300
301 pa_hashmap_put(u->devices, d->path, d);
302
303 verify_access(u, d);
304 }
305
306 static void remove_card(struct userdata *u, struct udev_device *dev) {
307 struct device *d;
308
309 pa_assert(u);
310 pa_assert(dev);
311
312 if (!(d = pa_hashmap_remove(u->devices, udev_device_get_devpath(dev))))
313 return;
314
315 pa_log_info("Card %s removed.", d->path);
316
317 if (d->module != PA_INVALID_INDEX)
318 pa_module_unload_request_by_index(u->core, d->module, TRUE);
319
320 device_free(d);
321 }
322
323 static void process_device(struct userdata *u, struct udev_device *dev) {
324 const char *action, *ff;
325
326 pa_assert(u);
327 pa_assert(dev);
328
329 if (udev_device_get_property_value(dev, "PULSE_IGNORE")) {
330 pa_log_debug("Ignoring %s, because marked so.", udev_device_get_devpath(dev));
331 return;
332 }
333
334 if ((ff = udev_device_get_property_value(dev, "SOUND_FORM_FACTOR")) &&
335 pa_streq(ff, "modem")) {
336 pa_log_debug("Ignoring %s, because it is a modem.", udev_device_get_devpath(dev));
337 return;
338 }
339
340 action = udev_device_get_action(dev);
341
342 if (action && pa_streq(action, "remove"))
343 remove_card(u, dev);
344 else if ((!action || pa_streq(action, "change")) &&
345 udev_device_get_property_value(dev, "SOUND_INITIALIZED"))
346 card_changed(u, dev);
347
348 /* For an explanation why we don't look for 'add' events here
349 * have a look into /lib/udev/rules.d/78-sound-card.rules! */
350 }
351
352 static void process_path(struct userdata *u, const char *path) {
353 struct udev_device *dev;
354
355 if (!path_get_card_id(path))
356 return;
357
358 if (!(dev = udev_device_new_from_syspath(u->udev, path))) {
359 pa_log("Failed to get udev device object from udev.");
360 return;
361 }
362
363 process_device(u, dev);
364 udev_device_unref(dev);
365 }
366
367 static void monitor_cb(
368 pa_mainloop_api*a,
369 pa_io_event* e,
370 int fd,
371 pa_io_event_flags_t events,
372 void *userdata) {
373
374 struct userdata *u = userdata;
375 struct udev_device *dev;
376
377 pa_assert(a);
378
379 if (!(dev = udev_monitor_receive_device(u->monitor))) {
380 pa_log("Failed to get udev device object from monitor.");
381 goto fail;
382 }
383
384 if (!path_get_card_id(udev_device_get_devpath(dev)))
385 return;
386
387 process_device(u, dev);
388 udev_device_unref(dev);
389 return;
390
391 fail:
392 a->io_free(u->udev_io);
393 u->udev_io = NULL;
394 }
395
396 static pa_bool_t pcm_node_belongs_to_device(
397 struct device *d,
398 const char *node) {
399
400 char *cd;
401 pa_bool_t b;
402
403 cd = pa_sprintf_malloc("pcmC%sD", path_get_card_id(d->path));
404 b = pa_startswith(node, cd);
405 pa_xfree(cd);
406
407 return b;
408 }
409
410 static pa_bool_t control_node_belongs_to_device(
411 struct device *d,
412 const char *node) {
413
414 char *cd;
415 pa_bool_t b;
416
417 cd = pa_sprintf_malloc("controlC%s", path_get_card_id(d->path));
418 b = pa_streq(node, cd);
419 pa_xfree(cd);
420
421 return b;
422 }
423
424 static void inotify_cb(
425 pa_mainloop_api*a,
426 pa_io_event* e,
427 int fd,
428 pa_io_event_flags_t events,
429 void *userdata) {
430
431 struct {
432 struct inotify_event e;
433 char name[NAME_MAX];
434 } buf;
435 struct userdata *u = userdata;
436 static int type = 0;
437 pa_bool_t deleted = FALSE;
438 struct device *d;
439 void *state;
440
441 for (;;) {
442 ssize_t r;
443 struct inotify_event *event;
444
445 pa_zero(buf);
446 if ((r = pa_read(fd, &buf, sizeof(buf), &type)) <= 0) {
447
448 if (r < 0 && errno == EAGAIN)
449 break;
450
451 pa_log("read() from inotify failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
452 goto fail;
453 }
454
455 event = &buf.e;
456 while (r > 0) {
457 size_t len;
458
459 if ((size_t) r < sizeof(struct inotify_event)) {
460 pa_log("read() too short.");
461 goto fail;
462 }
463
464 len = sizeof(struct inotify_event) + event->len;
465
466 if ((size_t) r < len) {
467 pa_log("Payload missing.");
468 goto fail;
469 }
470
471 /* From udev we get the guarantee that the control
472 * device's ACL is changed last. To avoid races when ACLs
473 * are changed we hence watch only the control device */
474 if (((event->mask & IN_ATTRIB) && pa_startswith(event->name, "controlC")))
475 PA_HASHMAP_FOREACH(d, u->devices, state)
476 if (control_node_belongs_to_device(d, event->name))
477 d->need_verify = TRUE;
478
479 /* ALSA doesn't really give us any guarantee on the closing
480 * order, so let's simply hope */
481 if (((event->mask & IN_CLOSE_WRITE) && pa_startswith(event->name, "pcmC")))
482 PA_HASHMAP_FOREACH(d, u->devices, state)
483 if (pcm_node_belongs_to_device(d, event->name))
484 d->need_verify = TRUE;
485
486 /* /dev/snd/ might have been removed */
487 if ((event->mask & (IN_DELETE_SELF|IN_MOVE_SELF)))
488 deleted = TRUE;
489
490 event = (struct inotify_event*) ((uint8_t*) event + len);
491 r -= len;
492 }
493 }
494
495 PA_HASHMAP_FOREACH(d, u->devices, state)
496 if (d->need_verify) {
497 d->need_verify = FALSE;
498 verify_access(u, d);
499 }
500
501 if (!deleted)
502 return;
503
504 fail:
505 if (u->inotify_io) {
506 a->io_free(u->inotify_io);
507 u->inotify_io = NULL;
508 }
509
510 if (u->inotify_fd >= 0) {
511 pa_close(u->inotify_fd);
512 u->inotify_fd = -1;
513 }
514 }
515
516 static int setup_inotify(struct userdata *u) {
517 char *dev_snd;
518 int r;
519
520 if (u->inotify_fd >= 0)
521 return 0;
522
523 if ((u->inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
524 pa_log("inotify_init1() failed: %s", pa_cstrerror(errno));
525 return -1;
526 }
527
528 dev_snd = pa_sprintf_malloc("%s/snd", udev_get_dev_path(u->udev));
529 r = inotify_add_watch(u->inotify_fd, dev_snd, IN_ATTRIB|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF);
530 pa_xfree(dev_snd);
531
532 if (r < 0) {
533 int saved_errno = errno;
534
535 pa_close(u->inotify_fd);
536 u->inotify_fd = -1;
537
538 if (saved_errno == ENOENT) {
539 pa_log_debug("/dev/snd/ is apparently not existing yet, retrying to create inotify watch later.");
540 return 0;
541 }
542
543 if (saved_errno == ENOSPC) {
544 pa_log("You apparently ran out of inotify watches, probably because Tracker/Beagle took them all away. "
545 "I wished people would do their homework first and fix inotify before using it for watching whole "
546 "directory trees which is something the current inotify is certainly not useful for. "
547 "Please make sure to drop the Tracker/Beagle guys a line complaining about their broken use of inotify.");
548 return 0;
549 }
550
551 pa_log("inotify_add_watch() failed: %s", pa_cstrerror(saved_errno));
552 return -1;
553 }
554
555 pa_assert_se(u->inotify_io = u->core->mainloop->io_new(u->core->mainloop, u->inotify_fd, PA_IO_EVENT_INPUT, inotify_cb, u));
556
557 return 0;
558 }
559
560 int pa__init(pa_module *m) {
561 struct userdata *u = NULL;
562 pa_modargs *ma;
563 struct udev_enumerate *enumerate = NULL;
564 struct udev_list_entry *item = NULL, *first = NULL;
565 int fd;
566 pa_bool_t use_tsched = TRUE, ignore_dB = FALSE;
567
568 pa_assert(m);
569
570 if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
571 pa_log("Failed to parse module arguments");
572 goto fail;
573 }
574
575 m->userdata = u = pa_xnew0(struct userdata, 1);
576 u->core = m->core;
577 u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
578 u->inotify_fd = -1;
579
580 if (pa_modargs_get_value_boolean(ma, "tsched", &use_tsched) < 0) {
581 pa_log("Failed to parse tsched= argument.");
582 goto fail;
583 }
584 u->use_tsched = use_tsched;
585
586 if (pa_modargs_get_value_boolean(ma, "ignore_dB", &ignore_dB) < 0) {
587 pa_log("Failed to parse ignore_dB= argument.");
588 goto fail;
589 }
590 u->ignore_dB = ignore_dB;
591
592 if (!(u->udev = udev_new())) {
593 pa_log("Failed to initialize udev library.");
594 goto fail;
595 }
596
597 if (setup_inotify(u) < 0)
598 goto fail;
599
600 if (!(u->monitor = udev_monitor_new_from_netlink(u->udev, "udev"))) {
601 pa_log("Failed to initialize monitor.");
602 goto fail;
603 }
604
605 errno = 0;
606 if (udev_monitor_enable_receiving(u->monitor) < 0) {
607 pa_log("Failed to enable monitor: %s", pa_cstrerror(errno));
608 if (errno == EPERM)
609 pa_log_info("Most likely your kernel is simply too old and "
610 "allows only priviliged processes to listen to device events. "
611 "Please upgrade your kernel to at least 2.6.30.");
612 goto fail;
613 }
614
615 if ((fd = udev_monitor_get_fd(u->monitor)) < 0) {
616 pa_log("Failed to get udev monitor fd.");
617 goto fail;
618 }
619
620 pa_assert_se(u->udev_io = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, monitor_cb, u));
621
622 if (!(enumerate = udev_enumerate_new(u->udev))) {
623 pa_log("Failed to initialize udev enumerator.");
624 goto fail;
625 }
626
627 if (udev_enumerate_add_match_subsystem(enumerate, "sound") < 0) {
628 pa_log("Failed to match to subsystem.");
629 goto fail;
630 }
631
632 if (udev_enumerate_scan_devices(enumerate) < 0) {
633 pa_log("Failed to scan for devices.");
634 goto fail;
635 }
636
637 first = udev_enumerate_get_list_entry(enumerate);
638 udev_list_entry_foreach(item, first)
639 process_path(u, udev_list_entry_get_name(item));
640
641 udev_enumerate_unref(enumerate);
642
643 pa_log_info("Found %u cards.", pa_hashmap_size(u->devices));
644
645 pa_modargs_free(ma);
646
647 return 0;
648
649 fail:
650
651 if (enumerate)
652 udev_enumerate_unref(enumerate);
653
654 if (ma)
655 pa_modargs_free(ma);
656
657 pa__done(m);
658
659 return -1;
660 }
661
662 void pa__done(pa_module *m) {
663 struct userdata *u;
664
665 pa_assert(m);
666
667 if (!(u = m->userdata))
668 return;
669
670 if (u->udev_io)
671 m->core->mainloop->io_free(u->udev_io);
672
673 if (u->monitor)
674 udev_monitor_unref(u->monitor);
675
676 if (u->udev)
677 udev_unref(u->udev);
678
679 if (u->inotify_io)
680 m->core->mainloop->io_free(u->inotify_io);
681
682 if (u->inotify_fd >= 0)
683 pa_close(u->inotify_fd);
684
685 if (u->devices) {
686 struct device *d;
687
688 while ((d = pa_hashmap_steal_first(u->devices)))
689 device_free(d);
690
691 pa_hashmap_free(u->devices, NULL, NULL);
692 }
693
694 pa_xfree(u);
695 }