Merge branch 'master' of ssh://rootserver/home/lennart/git/public/pulseaudio
[profile/ivi/pulseaudio.git] / 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 <sys/inotify.h>
29 #include <libudev.h>
30
31 #include <pulsecore/modargs.h>
32 #include <pulsecore/core-error.h>
33 #include <pulsecore/core-util.h>
34 #include <pulsecore/namereg.h>
35
36 #include "module-udev-detect-symdef.h"
37
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
43 struct device {
44     char *path;
45     pa_bool_t accessible;
46     char *card_name;
47     uint32_t module;
48 };
49
50 struct userdata {
51     pa_core *core;
52     pa_hashmap *devices;
53     pa_bool_t use_tsched;
54
55     struct udev* udev;
56     struct udev_monitor *monitor;
57     pa_io_event *udev_io;
58
59     int inotify_fd;
60     pa_io_event *inotify_io;
61 };
62
63 static const char* const valid_modargs[] = {
64     "tsched",
65     NULL
66 };
67
68 static int setup_inotify(struct userdata *u);
69
70 static void device_free(struct device *d) {
71     pa_assert(d);
72
73     pa_xfree(d->path);
74     pa_xfree(d->card_name);
75     pa_xfree(d);
76 }
77
78 static const char *path_get_card_id(const char *path) {
79     const char *e;
80
81     if (!path)
82         return NULL;
83
84     if (!(e = strrchr(path, '/')))
85         return NULL;
86
87     if (!pa_startswith(e, "/card"))
88         return NULL;
89
90     return e + 5;
91 }
92
93 static void verify_access(struct userdata *u, struct device *d) {
94     char *cd;
95     pa_card *card;
96
97     pa_assert(u);
98     pa_assert(d);
99
100     if (!(card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD)))
101         return;
102
103     cd = pa_sprintf_malloc("%s/snd/controlC%s", udev_get_dev_path(u->udev), path_get_card_id(d->path));
104     d->accessible = access(cd, W_OK) >= 0;
105     pa_log_info("%s is accessible: %s", cd, pa_yes_no(d->accessible));
106     pa_xfree(cd);
107
108     pa_card_suspend(card, !d->accessible, PA_SUSPEND_SESSION);
109 }
110
111 static void card_changed(struct userdata *u, struct udev_device *dev) {
112     struct device *d;
113     const char *path;
114     const char *t;
115     char *card_name, *args;
116     pa_module *m;
117     char *n;
118
119     pa_assert(u);
120     pa_assert(dev);
121
122     /* Maybe /dev/snd is now available? */
123     setup_inotify(u);
124
125     path = udev_device_get_devpath(dev);
126
127     if ((d = pa_hashmap_get(u->devices, path))) {
128         verify_access(u, d);
129         return;
130     }
131
132     if (!(t = udev_device_get_property_value(dev, "PULSE_NAME")))
133         if (!(t = udev_device_get_property_value(dev, "ID_ID")))
134             if (!(t = udev_device_get_property_value(dev, "ID_PATH")))
135                 t = path_get_card_id(path);
136
137     n = pa_namereg_make_valid_name(t);
138
139     card_name = pa_sprintf_malloc("alsa_card.%s", n);
140     args = pa_sprintf_malloc("device_id=\"%s\" "
141                              "name=\"%s\" "
142                              "card_name=\"%s\" "
143                              "tsched=%i "
144                              "card_properties=\"module-udev-detect.discovered=1\"",
145                              path_get_card_id(path),
146                              n,
147                              card_name,
148                              (int) u->use_tsched);
149
150     pa_log_debug("Loading module-alsa-card with arguments '%s'", args);
151     m = pa_module_load(u->core, "module-alsa-card", args);
152     pa_xfree(args);
153
154     if (m) {
155         pa_log_info("Card %s (%s) added.", path, n);
156
157         d = pa_xnew(struct device, 1);
158         d->path = pa_xstrdup(path);
159         d->card_name = card_name;
160         d->module = m->index;
161         d->accessible = TRUE;
162
163         pa_hashmap_put(u->devices, d->path, d);
164     } else
165         pa_xfree(card_name);
166
167     pa_xfree(n);
168 }
169
170 static void remove_card(struct userdata *u, struct udev_device *dev) {
171     struct device *d;
172
173     pa_assert(u);
174     pa_assert(dev);
175
176     if (!(d = pa_hashmap_remove(u->devices, udev_device_get_devpath(dev))))
177         return;
178
179     pa_log_info("Card %s removed.", d->path);
180     pa_module_unload_request_by_index(u->core, d->module, TRUE);
181     device_free(d);
182 }
183
184 static void process_device(struct userdata *u, struct udev_device *dev) {
185     const char *action, *ff;
186
187     pa_assert(u);
188     pa_assert(dev);
189
190     if (udev_device_get_property_value(dev, "PULSE_IGNORE")) {
191         pa_log_debug("Ignoring %s, because marked so.", udev_device_get_devpath(dev));
192         return;
193     }
194
195     if ((ff = udev_device_get_property_value(dev, "SOUND_FORM_FACTOR")) &&
196         pa_streq(ff, "modem")) {
197         pa_log_debug("Ignoring %s, because it is a modem.", udev_device_get_devpath(dev));
198         return;
199     }
200
201     action = udev_device_get_action(dev);
202
203     if (action && pa_streq(action, "remove"))
204         remove_card(u, dev);
205     else if ((!action || pa_streq(action, "change")) &&
206              udev_device_get_property_value(dev, "SOUND_INITIALIZED"))
207         card_changed(u, dev);
208
209     /* For an explanation why we don't look for 'add' events here
210      * have a look into /lib/udev/rules.d/78-sound-card.rules! */
211 }
212
213 static void process_path(struct userdata *u, const char *path) {
214     struct udev_device *dev;
215
216     if (!path_get_card_id(path))
217         return;
218
219     if (!(dev = udev_device_new_from_syspath(u->udev, path))) {
220         pa_log("Failed to get udev device object from udev.");
221         return;
222     }
223
224     process_device(u, dev);
225     udev_device_unref(dev);
226 }
227
228 static void monitor_cb(
229         pa_mainloop_api*a,
230         pa_io_event* e,
231         int fd,
232         pa_io_event_flags_t events,
233         void *userdata) {
234
235     struct userdata *u = userdata;
236     struct udev_device *dev;
237
238     pa_assert(a);
239
240     if (!(dev = udev_monitor_receive_device(u->monitor))) {
241         pa_log("Failed to get udev device object from monitor.");
242         goto fail;
243     }
244
245     if (!path_get_card_id(udev_device_get_devpath(dev)))
246         return;
247
248     process_device(u, dev);
249     udev_device_unref(dev);
250     return;
251
252 fail:
253     a->io_free(u->udev_io);
254     u->udev_io = NULL;
255 }
256
257 static void inotify_cb(
258         pa_mainloop_api*a,
259         pa_io_event* e,
260         int fd,
261         pa_io_event_flags_t events,
262         void *userdata) {
263
264     struct {
265         struct inotify_event e;
266         char name[NAME_MAX];
267     } buf;
268     struct userdata *u = userdata;
269     static int type = 0;
270     pa_bool_t verify = FALSE, deleted = FALSE;
271
272     for (;;) {
273         ssize_t r;
274
275         pa_zero(buf);
276         if ((r = pa_read(fd, &buf, sizeof(buf), &type)) <= 0) {
277
278             if (r < 0 && errno == EAGAIN)
279                 break;
280
281             pa_log("read() from inotify failed: %s", r < 0 ? pa_cstrerror(errno) : "EOF");
282             goto fail;
283         }
284
285         if ((buf.e.mask & IN_CLOSE_WRITE) && pa_startswith(buf.e.name, "pcmC"))
286             verify = TRUE;
287
288         if ((buf.e.mask & (IN_DELETE_SELF|IN_MOVE_SELF)))
289             deleted = TRUE;
290     }
291
292     if (verify) {
293         struct device *d;
294         void *state;
295
296         pa_log_debug("Verifying access.");
297
298         PA_HASHMAP_FOREACH(d, u->devices, state)
299             verify_access(u, d);
300     }
301
302     if (!deleted)
303         return;
304
305 fail:
306     if (u->inotify_io) {
307         a->io_free(u->inotify_io);
308         u->inotify_io = NULL;
309     }
310
311     if (u->inotify_fd >= 0) {
312         pa_close(u->inotify_fd);
313         u->inotify_fd = -1;
314     }
315 }
316
317 static int setup_inotify(struct userdata *u) {
318     char *dev_snd;
319     int r;
320
321     if (u->inotify_fd >= 0)
322         return 0;
323
324     if ((u->inotify_fd = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
325         pa_log("inotify_init1() failed: %s", pa_cstrerror(errno));
326         return -1;
327     }
328
329     dev_snd = pa_sprintf_malloc("%s/snd", udev_get_dev_path(u->udev));
330     r = inotify_add_watch(u->inotify_fd, dev_snd, IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF);
331     pa_xfree(dev_snd);
332
333     if (r < 0) {
334         int saved_errno = errno;
335
336         pa_close(u->inotify_fd);
337         u->inotify_fd = -1;
338
339         if (saved_errno == ENOENT)
340             return 0;
341
342         pa_log("inotify_add_watch() failed: %s", pa_cstrerror(saved_errno));
343         return -1;
344     }
345
346     pa_assert_se(u->inotify_io = u->core->mainloop->io_new(u->core->mainloop, u->inotify_fd, PA_IO_EVENT_INPUT, inotify_cb, u));
347
348     return 0;
349 }
350
351 int pa__init(pa_module *m) {
352     struct userdata *u = NULL;
353     pa_modargs *ma;
354     struct udev_enumerate *enumerate = NULL;
355     struct udev_list_entry *item = NULL, *first = NULL;
356     int fd;
357
358     pa_assert(m);
359
360     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
361         pa_log("Failed to parse module arguments");
362         goto fail;
363     }
364
365     m->userdata = u = pa_xnew0(struct userdata, 1);
366     u->core = m->core;
367     u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
368     u->use_tsched = TRUE;
369     u->inotify_fd = -1;
370
371     if (pa_modargs_get_value_boolean(ma, "tsched", &u->use_tsched) < 0) {
372         pa_log("Failed to parse tsched argument.");
373         goto fail;
374     }
375
376     if (!(u->udev = udev_new())) {
377         pa_log("Failed to initialize udev library.");
378         goto fail;
379     }
380
381     if (setup_inotify(u) < 0)
382         goto fail;
383
384     if (!(u->monitor = udev_monitor_new_from_netlink(u->udev, "udev"))) {
385         pa_log("Failed to initialize monitor.");
386         goto fail;
387     }
388
389     errno = 0;
390     if (udev_monitor_enable_receiving(u->monitor) < 0) {
391         pa_log("Failed to enable monitor: %s", pa_cstrerror(errno));
392         if (errno == EPERM)
393             pa_log_info("Most likely your kernel is simply too old and "
394                         "allows only priviliged processes to listen to device events. "
395                         "Please upgrade your kernel to at least 2.6.30.");
396         goto fail;
397     }
398
399     if ((fd = udev_monitor_get_fd(u->monitor)) < 0) {
400         pa_log("Failed to get udev monitor fd.");
401         goto fail;
402     }
403
404     pa_assert_se(u->udev_io = u->core->mainloop->io_new(u->core->mainloop, fd, PA_IO_EVENT_INPUT, monitor_cb, u));
405
406     if (!(enumerate = udev_enumerate_new(u->udev))) {
407         pa_log("Failed to initialize udev enumerator.");
408         goto fail;
409     }
410
411     if (udev_enumerate_add_match_subsystem(enumerate, "sound") < 0) {
412         pa_log("Failed to match to subsystem.");
413         goto fail;
414     }
415
416     if (udev_enumerate_scan_devices(enumerate) < 0) {
417         pa_log("Failed to scan for devices.");
418         goto fail;
419     }
420
421     first = udev_enumerate_get_list_entry(enumerate);
422     udev_list_entry_foreach(item, first)
423         process_path(u, udev_list_entry_get_name(item));
424
425     udev_enumerate_unref(enumerate);
426
427     pa_log_info("Loaded %u modules.", pa_hashmap_size(u->devices));
428
429     pa_modargs_free(ma);
430
431     return 0;
432
433 fail:
434
435     if (enumerate)
436         udev_enumerate_unref(enumerate);
437
438     if (ma)
439         pa_modargs_free(ma);
440
441     pa__done(m);
442
443     return -1;
444 }
445
446 void pa__done(pa_module *m) {
447     struct userdata *u;
448
449     pa_assert(m);
450
451     if (!(u = m->userdata))
452         return;
453
454     if (u->udev_io)
455         m->core->mainloop->io_free(u->udev_io);
456
457     if (u->monitor)
458         udev_monitor_unref(u->monitor);
459
460     if (u->udev)
461         udev_unref(u->udev);
462
463     if (u->inotify_io)
464         m->core->mainloop->io_free(u->inotify_io);
465
466     if (u->inotify_fd >= 0)
467         pa_close(u->inotify_fd);
468
469     if (u->devices) {
470         struct device *d;
471
472         while ((d = pa_hashmap_steal_first(u->devices)))
473             device_free(d);
474
475         pa_hashmap_free(u->devices, NULL, NULL);
476     }
477
478     pa_xfree(u);
479 }