309b0060d3b549496893f1f469cd19cd7dd3dba3
[platform/upstream/pulseaudio.git] / src / modules / module-hal-detect.c
1 /***
2     This file is part of PulseAudio.
3
4     Copyright 2006 Lennart Poettering
5     Copyright 2006 Shams E. King
6
7     PulseAudio is free software; you can redistribute it and/or modify
8     it under the terms of the GNU Lesser General Public License as published
9     by the Free Software Foundation; either version 2 of the License,
10     or (at your option) any later version.
11
12     PulseAudio is distributed in the hope that it will be useful, but
13     WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     General Public License for more details.
16
17     You should have received a copy of the GNU Lesser General Public License
18     along with PulseAudio; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     USA.
21 ***/
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35
36 #include <pulse/xmalloc.h>
37 #include <pulse/timeval.h>
38
39 #include <pulsecore/core-error.h>
40 #include <pulsecore/module.h>
41 #include <pulsecore/log.h>
42 #include <pulsecore/hashmap.h>
43 #include <pulsecore/idxset.h>
44 #include <pulsecore/core-util.h>
45 #include <pulsecore/namereg.h>
46 #include <pulsecore/core-scache.h>
47 #include <pulsecore/modargs.h>
48
49 #include <hal/libhal.h>
50
51 #include "dbus-util.h"
52 #include "module-hal-detect-symdef.h"
53
54 PA_MODULE_AUTHOR("Shahms King");
55 PA_MODULE_DESCRIPTION("Detect available audio hardware and load matching drivers");
56 PA_MODULE_VERSION(PACKAGE_VERSION);
57 PA_MODULE_LOAD_ONCE(TRUE);
58 #if defined(HAVE_ALSA) && defined(HAVE_OSS)
59 PA_MODULE_USAGE("api=<alsa or oss> "
60                 "tsched=<enable system timer based scheduling mode?>");
61 #elif defined(HAVE_ALSA)
62 PA_MODULE_USAGE("api=<alsa> "
63                 "tsched=<enable system timer based scheduling mode?>");
64 #elif defined(HAVE_OSS)
65 PA_MODULE_USAGE("api=<oss>");
66 #endif
67
68 struct device {
69     char *udi, *originating_udi;
70     char *card_name, *sink_name, *source_name;
71     uint32_t module;
72     pa_bool_t acl_race_fix;
73 };
74
75 struct userdata {
76     pa_core *core;
77     LibHalContext *context;
78     pa_dbus_connection *connection;
79     pa_hashmap *devices; /* Every entry is indexed twice in this table: by the udi we found the device with and by the originating device's udi */
80     const char *capability;
81 #ifdef HAVE_ALSA
82     pa_bool_t use_tsched;
83 #endif
84 };
85
86 #define CAPABILITY_ALSA "alsa"
87 #define CAPABILITY_OSS "oss"
88
89 static const char* const valid_modargs[] = {
90     "api",
91 #ifdef HAVE_ALSA
92     "tsched",
93 #endif
94     NULL
95 };
96
97 static void device_free(struct device* d) {
98     pa_assert(d);
99
100     pa_xfree(d->udi);
101     pa_xfree(d->originating_udi);
102     pa_xfree(d->sink_name);
103     pa_xfree(d->source_name);
104     pa_xfree(d->card_name);
105     pa_xfree(d);
106 }
107
108 static const char *strip_udi(const char *udi) {
109     const char *slash;
110
111     pa_assert(udi);
112
113     if ((slash = strrchr(udi, '/')))
114         return slash+1;
115
116     return udi;
117 }
118
119 #ifdef HAVE_ALSA
120
121 enum alsa_type {
122     ALSA_TYPE_PLAYBACK,
123     ALSA_TYPE_CAPTURE,
124     ALSA_TYPE_OTHER
125 };
126
127 static enum alsa_type hal_alsa_device_get_type(LibHalContext *context, const char *udi) {
128     char *type;
129     enum alsa_type t = ALSA_TYPE_OTHER;
130     DBusError error;
131
132     dbus_error_init(&error);
133
134     pa_assert(context);
135     pa_assert(udi);
136
137     if (!(type = libhal_device_get_property_string(context, udi, "alsa.type", &error)))
138         goto finish;
139
140     if (pa_streq(type, "playback"))
141         t = ALSA_TYPE_PLAYBACK;
142     else if (pa_streq(type, "capture"))
143         t = ALSA_TYPE_CAPTURE;
144
145     libhal_free_string(type);
146
147 finish:
148     if (dbus_error_is_set(&error)) {
149         pa_log_error("D-Bus error while parsing HAL ALSA data: %s: %s", error.name, error.message);
150         dbus_error_free(&error);
151     }
152
153     return t;
154 }
155
156 static pa_bool_t hal_alsa_device_is_modem(LibHalContext *context, const char *udi) {
157     char *class;
158     pa_bool_t r = FALSE;
159     DBusError error;
160
161     dbus_error_init(&error);
162
163     pa_assert(context);
164     pa_assert(udi);
165
166     if (!(class = libhal_device_get_property_string(context, udi, "alsa.pcm_class", &error)))
167         goto finish;
168
169     r = pa_streq(class, "modem");
170     libhal_free_string(class);
171
172 finish:
173     if (dbus_error_is_set(&error)) {
174         pa_log_error("D-Bus error while parsing HAL ALSA data: %s: %s", error.name, error.message);
175         dbus_error_free(&error);
176     }
177
178     return r;
179 }
180
181 static int hal_device_load_alsa(struct userdata *u, const char *udi, struct device *d) {
182     enum alsa_type type;
183     int device, card;
184     DBusError error;
185     pa_module *m;
186     char *args, *originating_udi = NULL, *card_name = NULL;
187
188     dbus_error_init(&error);
189
190     pa_assert(u);
191     pa_assert(udi);
192     pa_assert(d);
193
194     /* We only care for PCM devices */
195     type = hal_alsa_device_get_type(u->context, udi);
196     if (type == ALSA_TYPE_OTHER)
197         goto fail;
198
199     /* We don't care for modems */
200     if (hal_alsa_device_is_modem(u->context, udi))
201         goto fail;
202
203     /* We only care for the main device */
204     device = libhal_device_get_property_int(u->context, udi, "alsa.device", &error);
205     if (dbus_error_is_set(&error) || device != 0)
206         goto fail;
207
208     /* We store only one entry per card, hence we look for the originating device */
209     originating_udi = libhal_device_get_property_string(u->context, udi, "alsa.originating_device", &error);
210     if (dbus_error_is_set(&error) || !originating_udi)
211         goto fail;
212
213     /* Make sure we only load one module per card */
214     if (pa_hashmap_get(u->devices, originating_udi))
215         goto fail;
216
217     /* We need the identifier */
218     card = libhal_device_get_property_int(u->context, udi, "alsa.card", &error);
219     if (dbus_error_is_set(&error))
220         goto fail;
221
222     card_name = pa_sprintf_malloc("alsa_card.%s", strip_udi(originating_udi));
223     args = pa_sprintf_malloc("device_id=%u name=%s card_name=%s tsched=%i", card, strip_udi(originating_udi), card_name, (int) u->use_tsched);
224
225     pa_log_debug("Loading module-alsa-card with arguments '%s'", args);
226     m = pa_module_load(u->core, "module-alsa-card", args);
227     pa_xfree(args);
228
229     if (!m)
230         goto fail;
231
232     d->originating_udi = originating_udi;
233     d->module = m->index;
234     d->card_name = card_name;
235
236     return 0;
237
238 fail:
239     if (dbus_error_is_set(&error)) {
240         pa_log_error("D-Bus error while parsing HAL ALSA data: %s: %s", error.name, error.message);
241         dbus_error_free(&error);
242     }
243
244     pa_xfree(originating_udi);
245     pa_xfree(card_name);
246
247     return -1;
248 }
249
250 #endif
251
252 #ifdef HAVE_OSS
253
254 static pa_bool_t hal_oss_device_is_pcm(LibHalContext *context, const char *udi) {
255     char *class = NULL, *dev = NULL, *e;
256     int device;
257     pa_bool_t r = FALSE;
258     DBusError error;
259
260     dbus_error_init(&error);
261
262     pa_assert(context);
263     pa_assert(udi);
264
265     /* We only care for PCM devices */
266     class = libhal_device_get_property_string(context, udi, "oss.type", &error);
267     if (dbus_error_is_set(&error) || !class)
268         goto finish;
269
270     if (!pa_streq(class, "pcm"))
271         goto finish;
272
273     /* We don't like /dev/audio */
274     dev = libhal_device_get_property_string(context, udi, "oss.device_file", &error);
275     if (dbus_error_is_set(&error) || !dev)
276         goto finish;
277
278     if ((e = strrchr(dev, '/')))
279         if (pa_startswith(e + 1, "audio"))
280             goto finish;
281
282     /* We only care for the main device */
283     device = libhal_device_get_property_int(context, udi, "oss.device", &error);
284     if (dbus_error_is_set(&error) || device != 0)
285         goto finish;
286
287     r = TRUE;
288
289 finish:
290
291     if (dbus_error_is_set(&error)) {
292         pa_log_error("D-Bus error while parsing HAL OSS data: %s: %s", error.name, error.message);
293         dbus_error_free(&error);
294     }
295
296     libhal_free_string(class);
297     libhal_free_string(dev);
298
299     return r;
300 }
301
302 static int hal_device_load_oss(struct userdata *u, const char *udi, struct device *d) {
303     DBusError error;
304     pa_module *m;
305     char *args, *originating_udi = NULL, *device, *sink_name = NULL, *source_name = NULL;
306
307     dbus_error_init(&error);
308
309     pa_assert(u);
310     pa_assert(udi);
311     pa_assert(d);
312
313     /* We only care for OSS PCM devices */
314     if (!hal_oss_device_is_pcm(u->context, udi))
315         goto fail;
316
317     /* We store only one entry per card, hence we look for the originating device */
318     originating_udi = libhal_device_get_property_string(u->context, udi, "oss.originating_device", &error);
319     if (dbus_error_is_set(&error) || !originating_udi)
320         goto fail;
321
322     /* Make sure we only load one module per card */
323     if (pa_hashmap_get(u->devices, originating_udi))
324         goto fail;
325
326     /* We need the device file */
327     device = libhal_device_get_property_string(u->context, udi, "oss.device_file", &error);
328     if (!device || dbus_error_is_set(&error))
329         goto fail;
330
331     sink_name = pa_sprintf_malloc("oss_output.%s", strip_udi(udi));
332     source_name = pa_sprintf_malloc("oss_input.%s", strip_udi(udi));
333     args = pa_sprintf_malloc("device=%s sink_name=%s source_name=%s", device, sink_name, source_name);
334
335     libhal_free_string(device);
336
337     pa_log_debug("Loading module-oss with arguments '%s'", args);
338     m = pa_module_load(u->core, "module-oss", args);
339     pa_xfree(args);
340
341     if (!m)
342         goto fail;
343
344     d->originating_udi = originating_udi;
345     d->module = m->index;
346     d->sink_name = sink_name;
347     d->source_name = source_name;
348
349     return 0;
350
351 fail:
352     if (dbus_error_is_set(&error)) {
353         pa_log_error("D-Bus error while parsing OSS HAL data: %s: %s", error.name, error.message);
354         dbus_error_free(&error);
355     }
356
357     pa_xfree(originating_udi);
358     pa_xfree(source_name);
359     pa_xfree(sink_name);
360
361     return -1;
362 }
363 #endif
364
365 static struct device* hal_device_add(struct userdata *u, const char *udi) {
366     struct device *d;
367     int r;
368
369     pa_assert(u);
370     pa_assert(u->capability);
371
372     d = pa_xnew(struct device, 1);
373     d->acl_race_fix = FALSE;
374     d->udi = pa_xstrdup(udi);
375     d->originating_udi = NULL;
376     d->module = PA_INVALID_INDEX;
377     d->sink_name = d->source_name = d->card_name = NULL;
378
379 #ifdef HAVE_ALSA
380     if (pa_streq(u->capability, CAPABILITY_ALSA))
381         r = hal_device_load_alsa(u, udi,  d);
382 #endif
383 #ifdef HAVE_OSS
384     if (pa_streq(u->capability, CAPABILITY_OSS))
385         r = hal_device_load_oss(u, udi, d);
386 #endif
387
388     if (r < 0) {
389         device_free(d);
390         return NULL;
391     }
392
393     pa_hashmap_put(u->devices, d->udi, d);
394     pa_hashmap_put(u->devices, d->originating_udi, d);
395
396     return d;
397 }
398
399 static int hal_device_add_all(struct userdata *u) {
400     int n, count = 0;
401     char** udis;
402     DBusError error;
403
404     dbus_error_init(&error);
405
406     pa_assert(u);
407
408     udis = libhal_find_device_by_capability(u->context, u->capability, &n, &error);
409     if (dbus_error_is_set(&error) || !udis)
410         goto fail;
411
412     if (n > 0) {
413         int i;
414
415         for (i = 0; i < n; i++) {
416             struct device *d;
417
418             if ((d = hal_device_add(u, udis[i])))
419                 count++;
420             else
421                 pa_log_debug("Not loaded device %s", udis[i]);
422         }
423     }
424
425     libhal_free_string_array(udis);
426
427     return count;
428
429 fail:
430     if (dbus_error_is_set(&error)) {
431         pa_log_error("D-Bus error while parsing HAL data: %s: %s", error.name, error.message);
432         dbus_error_free(&error);
433     }
434
435     return -1;
436 }
437
438 static void device_added_cb(LibHalContext *context, const char *udi) {
439     DBusError error;
440     struct userdata *u;
441     pa_bool_t good = FALSE;
442
443     dbus_error_init(&error);
444
445     pa_assert(context);
446     pa_assert(udi);
447
448     pa_assert_se(u = libhal_ctx_get_user_data(context));
449
450     good = libhal_device_query_capability(context, udi, u->capability, &error);
451     if (dbus_error_is_set(&error) || !good)
452         goto finish;
453
454     if (!hal_device_add(u, udi))
455         pa_log_debug("Not loaded device %s", udi);
456
457 finish:
458     if (dbus_error_is_set(&error)) {
459         pa_log_error("D-Bus error while parsing HAL data: %s: %s", error.name, error.message);
460         dbus_error_free(&error);
461     }
462 }
463
464 static void device_removed_cb(LibHalContext* context, const char *udi) {
465     struct device *d;
466     struct userdata *u;
467
468     pa_assert(context);
469     pa_assert(udi);
470
471     pa_assert_se(u = libhal_ctx_get_user_data(context));
472
473     if (!(d = pa_hashmap_get(u->devices, udi)))
474         return;
475
476     pa_hashmap_remove(u->devices, d->originating_udi);
477     pa_hashmap_remove(u->devices, d->udi);
478
479     pa_log_debug("Removing HAL device: %s", d->originating_udi);
480
481     pa_module_unload_request_by_index(u->core, d->module, TRUE);
482     device_free(d);
483 }
484
485 static void new_capability_cb(LibHalContext *context, const char *udi, const char* capability) {
486     struct userdata *u;
487
488     pa_assert(context);
489     pa_assert(udi);
490     pa_assert(capability);
491
492     pa_assert_se(u = libhal_ctx_get_user_data(context));
493
494     if (pa_streq(u->capability, capability))
495         /* capability we care about, pretend it's a new device */
496         device_added_cb(context, udi);
497 }
498
499 static void lost_capability_cb(LibHalContext *context, const char *udi, const char* capability) {
500     struct userdata *u;
501
502     pa_assert(context);
503     pa_assert(udi);
504     pa_assert(capability);
505
506     pa_assert_se(u = libhal_ctx_get_user_data(context));
507
508     if (pa_streq(u->capability, capability))
509         /* capability we care about, pretend it was removed */
510         device_removed_cb(context, udi);
511 }
512
513 static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *message, void *userdata) {
514     struct userdata*u;
515     DBusError error;
516
517     pa_assert(bus);
518     pa_assert(message);
519     pa_assert_se(u = userdata);
520
521     dbus_error_init(&error);
522
523     pa_log_debug("dbus: interface=%s, path=%s, member=%s\n",
524                  dbus_message_get_interface(message),
525                  dbus_message_get_path(message),
526                  dbus_message_get_member(message));
527
528     if (dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLAdded") ||
529         dbus_message_is_signal(message, "org.freedesktop.Hal.Device.AccessControl", "ACLRemoved")) {
530         uint32_t uid;
531         pa_bool_t suspend = strcmp(dbus_message_get_member(message), "ACLRemoved") == 0;
532
533         if (!dbus_message_get_args(message, &error, DBUS_TYPE_UINT32, &uid, DBUS_TYPE_INVALID) || dbus_error_is_set(&error)) {
534             pa_log_error("Failed to parse ACL message: %s: %s", error.name, error.message);
535             goto finish;
536         }
537
538         /* Check if this is about us? */
539         if (uid == getuid() || uid == geteuid()) {
540             struct device *d;
541             const char *udi;
542
543             udi = dbus_message_get_path(message);
544
545             if ((d = pa_hashmap_get(u->devices, udi))) {
546                 pa_bool_t send_acl_race_fix_message = FALSE;
547                 d->acl_race_fix = FALSE;
548
549                 if (d->sink_name) {
550                     pa_sink *sink;
551
552                     if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK))) {
553                         pa_bool_t success = pa_sink_suspend(sink, suspend) >= 0;
554
555                         if (!success && !suspend)
556                             d->acl_race_fix = TRUE; /* resume failed, let's try again */
557                         else if (suspend)
558                             send_acl_race_fix_message = TRUE; /* suspend finished, let's tell everyone to try again */
559                     }
560                 }
561
562                 if (d->source_name) {
563                     pa_source *source;
564
565                     if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE))) {
566                         pa_bool_t success = pa_source_suspend(source, suspend) >= 0;
567
568                         if (!success && !suspend)
569                             d->acl_race_fix = TRUE; /* resume failed, let's try again */
570                         else if (suspend)
571                             send_acl_race_fix_message = TRUE; /* suspend finished, let's tell everyone to try again */
572                     }
573                 }
574
575                 if (d->card_name) {
576                     pa_card *card;
577
578                     if ((card = pa_namereg_get(u->core, d->card_name, PA_NAMEREG_CARD))) {
579                         pa_bool_t success = pa_card_suspend(card, suspend) >= 0;
580
581                         if (!success && !suspend)
582                             d->acl_race_fix = TRUE; /* resume failed, let's try again */
583                         else if (suspend)
584                             send_acl_race_fix_message = TRUE; /* suspend finished, let's tell everyone to try again */
585                     }
586                 }
587
588                 if (send_acl_race_fix_message) {
589                     DBusMessage *msg;
590                     msg = dbus_message_new_signal(udi, "org.pulseaudio.Server", "DirtyGiveUpMessage");
591                     dbus_connection_send(pa_dbus_connection_get(u->connection), msg, NULL);
592                     dbus_message_unref(msg);
593                 }
594
595             } else if (!suspend)
596                 device_added_cb(u->context, udi);
597
598         }
599
600         return DBUS_HANDLER_RESULT_HANDLED;
601
602     } else if (dbus_message_is_signal(message, "org.pulseaudio.Server", "DirtyGiveUpMessage")) {
603         /* We use this message to avoid a dirty race condition when we
604            get an ACLAdded message before the previously owning PA
605            sever has closed the device. We can remove this as
606            soon as HAL learns frevoke() */
607
608         struct device *d;
609         const char *udi;
610
611         udi = dbus_message_get_path(message);
612
613         if ((d = pa_hashmap_get(u->devices, udi))) {
614
615             if (d->acl_race_fix) {
616                 d->acl_race_fix = FALSE;
617                 pa_log_debug("Got dirty give up message for '%s', trying resume ...", udi);
618
619                 if (d->sink_name) {
620                     pa_sink *sink;
621
622                     if ((sink = pa_namereg_get(u->core, d->sink_name, PA_NAMEREG_SINK)))
623                         pa_sink_suspend(sink, FALSE);
624                 }
625
626                 if (d->source_name) {
627                     pa_source *source;
628
629                     if ((source = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_SOURCE)))
630                         pa_source_suspend(source, FALSE);
631                 }
632
633                 if (d->card_name) {
634                     pa_card *card;
635
636                     if ((card = pa_namereg_get(u->core, d->source_name, PA_NAMEREG_CARD)))
637                         pa_card_suspend(card, FALSE);
638                 }
639             }
640
641         } else
642             /* Yes, we don't check the UDI for validity, but hopefully HAL will */
643             device_added_cb(u->context, udi);
644
645         return DBUS_HANDLER_RESULT_HANDLED;
646     }
647
648 finish:
649     dbus_error_free(&error);
650
651     return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
652 }
653
654 static void hal_context_free(LibHalContext* hal_context) {
655     DBusError error;
656
657     dbus_error_init(&error);
658
659     libhal_ctx_shutdown(hal_context, &error);
660     libhal_ctx_free(hal_context);
661
662     dbus_error_free(&error);
663 }
664
665 static LibHalContext* hal_context_new(DBusConnection *connection) {
666     DBusError error;
667     LibHalContext *hal_context = NULL;
668
669     dbus_error_init(&error);
670
671     pa_assert(connection);
672
673     if (!(hal_context = libhal_ctx_new())) {
674         pa_log_error("libhal_ctx_new() failed");
675         goto fail;
676     }
677
678     if (!libhal_ctx_set_dbus_connection(hal_context, connection)) {
679         pa_log_error("Error establishing DBUS connection: %s: %s", error.name, error.message);
680         goto fail;
681     }
682
683     if (!libhal_ctx_init(hal_context, &error)) {
684         pa_log_error("Couldn't connect to hald: %s: %s", error.name, error.message);
685         goto fail;
686     }
687
688     return hal_context;
689
690 fail:
691     if (hal_context)
692         hal_context_free(hal_context);
693
694     dbus_error_free(&error);
695
696     return NULL;
697 }
698
699 int pa__init(pa_module*m) {
700     DBusError error;
701     struct userdata *u = NULL;
702     int n = 0;
703     pa_modargs *ma;
704     const char *api;
705
706     pa_assert(m);
707
708     dbus_error_init(&error);
709
710     if (!(ma = pa_modargs_new(m->argument, valid_modargs))) {
711         pa_log("Failed to parse module arguments");
712         goto fail;
713     }
714
715     m->userdata = u = pa_xnew(struct userdata, 1);
716     u->core = m->core;
717     u->context = NULL;
718     u->connection = NULL;
719     u->devices = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
720     u->capability = NULL;
721
722 #ifdef HAVE_ALSA
723     u->use_tsched = TRUE;
724
725     if (pa_modargs_get_value_boolean(ma, "tsched", &u->use_tsched) < 0) {
726         pa_log("Failed to parse tsched argument.");
727         goto fail;
728     }
729
730     api = pa_modargs_get_value(ma, "api", "alsa");
731
732     if (pa_streq(api, "alsa"))
733         u->capability = CAPABILITY_ALSA;
734 #else
735     api = pa_modargs_get_value(ma, "api", "oss");
736 #endif
737
738 #ifdef HAVE_OSS
739     if (pa_streq(api, "oss"))
740         u->capability = CAPABILITY_OSS;
741 #endif
742
743     if (!u->capability) {
744         pa_log_error("Invalid API specification.");
745         goto fail;
746     }
747
748     if (!(u->connection = pa_dbus_bus_get(m->core, DBUS_BUS_SYSTEM, &error)) || dbus_error_is_set(&error)) {
749         pa_log_error("Unable to contact DBUS system bus: %s: %s", error.name, error.message);
750         goto fail;
751     }
752
753     if (!(u->context = hal_context_new(pa_dbus_connection_get(u->connection)))) {
754         /* pa_hal_context_new() logs appropriate errors */
755         goto fail;
756     }
757
758     n = hal_device_add_all(u);
759
760     libhal_ctx_set_user_data(u->context, u);
761     libhal_ctx_set_device_added(u->context, device_added_cb);
762     libhal_ctx_set_device_removed(u->context, device_removed_cb);
763     libhal_ctx_set_device_new_capability(u->context, new_capability_cb);
764     libhal_ctx_set_device_lost_capability(u->context, lost_capability_cb);
765
766     if (!libhal_device_property_watch_all(u->context, &error)) {
767         pa_log_error("Error monitoring device list: %s: %s", error.name, error.message);
768         goto fail;
769     }
770
771     if (!dbus_connection_add_filter(pa_dbus_connection_get(u->connection), filter_cb, u, NULL)) {
772         pa_log_error("Failed to add filter function");
773         goto fail;
774     }
775
776     dbus_bus_add_match(pa_dbus_connection_get(u->connection), "type='signal',sender='org.freedesktop.Hal', interface='org.freedesktop.Hal.Device.AccessControl'", &error);
777     if (dbus_error_is_set(&error)) {
778         pa_log_error("Unable to subscribe to HAL ACL signals: %s: %s", error.name, error.message);
779         goto fail;
780     }
781
782     dbus_bus_add_match(pa_dbus_connection_get(u->connection), "type='signal',interface='org.pulseaudio.Server'", &error);
783     if (dbus_error_is_set(&error)) {
784         pa_log_error("Unable to subscribe to PulseAudio signals: %s: %s", error.name, error.message);
785         goto fail;
786     }
787
788     pa_log_info("Loaded %i modules.", n);
789
790     pa_modargs_free(ma);
791
792     return 0;
793
794 fail:
795     if (ma)
796         pa_modargs_free(ma);
797
798     dbus_error_free(&error);
799     pa__done(m);
800
801     return -1;
802 }
803
804
805 void pa__done(pa_module *m) {
806     struct userdata *u;
807
808     pa_assert(m);
809
810     if (!(u = m->userdata))
811         return;
812
813     if (u->context)
814         hal_context_free(u->context);
815
816     if (u->devices) {
817         struct device *d;
818
819         while ((d = pa_hashmap_first(u->devices))) {
820             pa_hashmap_remove(u->devices, d->udi);
821             pa_hashmap_remove(u->devices, d->originating_udi);
822             device_free(d);
823         }
824
825         pa_hashmap_free(u->devices, NULL, NULL);
826     }
827
828     if (u->connection) {
829         DBusError error;
830         dbus_error_init(&error);
831
832         dbus_bus_remove_match(pa_dbus_connection_get(u->connection), "type='signal',sender='org.freedesktop.Hal', interface='org.freedesktop.Hal.Device.AccessControl'", &error);
833         dbus_error_free(&error);
834
835         dbus_bus_remove_match(pa_dbus_connection_get(u->connection), "type='signal',interface='org.pulseaudio.Server'", &error);
836         dbus_error_free(&error);
837
838         dbus_connection_remove_filter(pa_dbus_connection_get(u->connection), filter_cb, u);
839
840         pa_dbus_connection_unref(u->connection);
841     }
842
843     pa_xfree(u);
844 }