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