~phablet-team/pulseaudio/ubuntu-touch-pulseaudio-saucy

« back to all changes in this revision

Viewing changes to debian/patches/0202-alsa-ucm-Make-combination-ports-have-lower-priority.patch

  • Committer: David Henningsson
  • Date: 2013-07-26 11:34:41 UTC
  • Revision ID: david.henningsson@canonical.com-20130726113441-t4bmq77my785yfmo
Add patches for Android jack detection

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
From dc9dfecfbe2268c48916a22e9d3e92f452a00762 Mon Sep 17 00:00:00 2001
 
2
From: David Henningsson <david.henningsson@canonical.com>
 
3
Date: Fri, 19 Jul 2013 10:50:07 +0200
 
4
Subject: [PATCH 1/2] ALSA: Add extcon (Android switch) jack detection
 
5
 
 
6
For headphone/headset only, so far.
 
7
---
 
8
 src/Makefile.am                     |    1 +
 
9
 src/modules/alsa/alsa-extcon.c      |  283 +++++++++++++++++++++++++++++++++++
 
10
 src/modules/alsa/alsa-extcon.h      |   33 ++++
 
11
 src/modules/alsa/alsa-ucm.c         |    4 +-
 
12
 src/modules/alsa/alsa-ucm.h         |    1 +
 
13
 src/modules/alsa/module-alsa-card.c |    5 +
 
14
 6 files changed, 325 insertions(+), 2 deletions(-)
 
15
 create mode 100644 src/modules/alsa/alsa-extcon.c
 
16
 create mode 100644 src/modules/alsa/alsa-extcon.h
 
17
 
 
18
diff --git a/src/Makefile.am b/src/Makefile.am
 
19
index a621a30..471dc72 100644
 
20
--- a/src/Makefile.am
 
21
+++ b/src/Makefile.am
 
22
@@ -1704,6 +1704,7 @@ module_coreaudio_device_la_LIBADD = $(MODULE_LIBADD)
 
23
 libalsa_util_la_SOURCES = \
 
24
                modules/alsa/alsa-util.c modules/alsa/alsa-util.h \
 
25
                modules/alsa/alsa-ucm.c modules/alsa/alsa-ucm.h \
 
26
+               modules/alsa/alsa-extcon.c modules/alsa/alsa-extcon.h \
 
27
                modules/alsa/alsa-mixer.c modules/alsa/alsa-mixer.h \
 
28
                modules/alsa/alsa-sink.c modules/alsa/alsa-sink.h \
 
29
                modules/alsa/alsa-source.c modules/alsa/alsa-source.h \
 
30
diff --git a/src/modules/alsa/alsa-extcon.c b/src/modules/alsa/alsa-extcon.c
 
31
new file mode 100644
 
32
index 0000000..5c60137
 
33
--- /dev/null
 
34
+++ b/src/modules/alsa/alsa-extcon.c
 
35
@@ -0,0 +1,283 @@
 
36
+/***
 
37
+  This file is part of PulseAudio.
 
38
+
 
39
+  Copyright 2013 David Henningsson, Canonical Ltd.
 
40
+
 
41
+  PulseAudio is free software; you can redistribute it and/or modify
 
42
+  it under the terms of the GNU Lesser General Public License as published
 
43
+  by the Free Software Foundation; either version 2.1 of the License,
 
44
+  or (at your option) any later version.
 
45
+
 
46
+  PulseAudio is distributed in the hope that it will be useful, but
 
47
+  WITHOUT ANY WARRANTY; without even the implied warranty of
 
48
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
49
+  General Public License for more details.
 
50
+
 
51
+  You should have received a copy of the GNU Lesser General Public License
 
52
+  along with PulseAudio; if not, write to the Free Software
 
53
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
54
+  USA.
 
55
+***/
 
56
+
 
57
+#ifdef HAVE_CONFIG_H
 
58
+#include <config.h>
 
59
+#endif
 
60
+
 
61
+#include <pulsecore/core-util.h>
 
62
+#include <pulsecore/device-port.h>
 
63
+#include <pulsecore/i18n.h>
 
64
+#include <libudev.h>
 
65
+
 
66
+#include "alsa-util.h"
 
67
+#include "alsa-extcon.h"
 
68
+
 
69
+/* IFDEF HAVE_UCM ? */
 
70
+#include <use-case.h>
 
71
+#include "alsa-ucm.h"
 
72
+/* ENDIF */
 
73
+
 
74
+/* For android */
 
75
+#define EXTCON_NAME "switch"
 
76
+/* For extcon */
 
77
+/* #define EXTCON_NAME "extcon" */
 
78
+
 
79
+
 
80
+/* TODO: Backport stuff to 4.0, remove before upstreaming */
 
81
+#ifndef PA_PORT_AVAILABLE_YES
 
82
+#define PA_PORT_AVAILABLE_YES PA_AVAILABLE_YES
 
83
+#define PA_PORT_AVAILABLE_NO PA_AVAILABLE_NO
 
84
+#define PA_PORT_AVAILABLE_UNKNOWN PA_AVAILABLE_UNKNOWN
 
85
+#define pa_port_available_t pa_available_t
 
86
+#endif
 
87
+
 
88
+static pa_port_available_t hp_avail(int state)
 
89
+{
 
90
+    return ((state & 3) != 0) ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO;
 
91
+}
 
92
+
 
93
+static pa_port_available_t hsmic_avail(int state)
 
94
+{
 
95
+    return (state & 1) ? PA_PORT_AVAILABLE_YES : PA_PORT_AVAILABLE_NO;
 
96
+}
 
97
+
 
98
+struct android_switch {
 
99
+    char *name;
 
100
+    uint32_t current_value;
 
101
+};
 
102
+
 
103
+static void android_switch_free(struct android_switch *as) {
 
104
+    if (!as)
 
105
+        return;
 
106
+    pa_xfree(as->name);
 
107
+    pa_xfree(as);
 
108
+}
 
109
+
 
110
+static struct android_switch *android_switch_new(const char *name) {
 
111
+
 
112
+    struct android_switch *as = NULL;
 
113
+    char *filename = pa_sprintf_malloc("/sys/class/%s/%s/state", EXTCON_NAME, name);
 
114
+    char *state = pa_read_line_from_file(filename);
 
115
+
 
116
+    if (state == NULL) {
 
117
+        pa_log_debug("Cannot open '%s'. Skipping.", filename);
 
118
+        pa_xfree(filename);
 
119
+        return NULL;
 
120
+    }
 
121
+    pa_xfree(filename);
 
122
+
 
123
+    as = pa_xnew0(struct android_switch, 1);
 
124
+    as->name = pa_xstrdup(name);
 
125
+
 
126
+    if (pa_atou(state, &as->current_value) < 0) {
 
127
+        pa_log_warn("Switch '%s' has invalid value '%s'", name, state);
 
128
+        pa_xfree(state);
 
129
+        android_switch_free(as);
 
130
+        return NULL;
 
131
+    }
 
132
+
 
133
+    return as;
 
134
+}
 
135
+
 
136
+struct udev_data {
 
137
+    struct udev *udev;
 
138
+    struct udev_monitor *monitor;
 
139
+    pa_io_event *event;
 
140
+};
 
141
+
 
142
+struct pa_alsa_extcon {
 
143
+    pa_card *card;
 
144
+    struct android_switch *h2w;
 
145
+    struct udev_data udev;
 
146
+};
 
147
+
 
148
+static struct android_switch *find_matching_switch(pa_alsa_extcon *u,
 
149
+                                                   const char *devpath) {
 
150
+
 
151
+    if (pa_streq(devpath, "/devices/virtual/" EXTCON_NAME "/h2w"))
 
152
+        return u->h2w;  /* To be extended if we ever support more switches */
 
153
+    return NULL;
 
154
+}
 
155
+
 
156
+static void notify_ports(pa_alsa_extcon *u, struct android_switch *as) {
 
157
+
 
158
+    pa_device_port *p;
 
159
+    void *state;
 
160
+
 
161
+    pa_assert(as == u->h2w); /* To be extended if we ever support more switches */
 
162
+
 
163
+    pa_log_debug("Value of switch %s is now %d.", as->name, as->current_value);
 
164
+
 
165
+    PA_HASHMAP_FOREACH(p, u->card->ports, state) {
 
166
+        if (p->is_output) {
 
167
+            if (!strcmp(p->name, "analog-output-headphones"))
 
168
+                 pa_device_port_set_available(p, hp_avail(as->current_value));
 
169
+/* IFDEF HAVE_UCM ? */
 
170
+            else if (pa_alsa_ucm_port_contains(p->name, SND_USE_CASE_DEV_HEADSET, true) ||
 
171
+                     pa_alsa_ucm_port_contains(p->name, SND_USE_CASE_DEV_HEADPHONES, true))
 
172
+                pa_device_port_set_available(p, hp_avail(as->current_value));
 
173
+/* ENDIF */
 
174
+        }
 
175
+        if (p->is_input) {
 
176
+            if (!strcmp(p->name, "analog-input-headset-mic"))
 
177
+                pa_device_port_set_available(p, hsmic_avail(as->current_value));
 
178
+/* IFDEF HAVE_UCM ? */
 
179
+            else if (pa_alsa_ucm_port_contains(p->name, SND_USE_CASE_DEV_HEADSET, false))
 
180
+                pa_device_port_set_available(p, hsmic_avail(as->current_value));
 
181
+/* ENDIF */
 
182
+        }
 
183
+    }
 
184
+}
 
185
+
 
186
+static void udev_cb(pa_mainloop_api *a, pa_io_event *e, int fd,
 
187
+                    pa_io_event_flags_t events, void *userdata) {
 
188
+
 
189
+    pa_alsa_extcon *u = userdata;
 
190
+    struct udev_device *d = udev_monitor_receive_device(u->udev.monitor);
 
191
+    struct udev_list_entry *entry;
 
192
+    struct android_switch *as;
 
193
+    const char *devpath, *state;
 
194
+
 
195
+    if (!d) {
 
196
+        pa_log("udev_monitor_receive_device failed.");
 
197
+        pa_assert(a);
 
198
+        a->io_free(u->udev.event);
 
199
+        u->udev.event = NULL;
 
200
+        return;
 
201
+    }
 
202
+
 
203
+    devpath = udev_device_get_devpath(d);
 
204
+    if (!devpath) {
 
205
+        pa_log("udev_device_get_devpath failed.");
 
206
+        goto out;
 
207
+    }
 
208
+    pa_log_debug("Got uevent with devpath=%s", devpath);
 
209
+
 
210
+    as = find_matching_switch(u, devpath);
 
211
+    if (!as)
 
212
+        goto out;
 
213
+
 
214
+    entry = udev_list_entry_get_by_name(
 
215
+            udev_device_get_properties_list_entry(d), "SWITCH_STATE");
 
216
+    if (!entry) {
 
217
+        pa_log("udev_list_entry_get_by_name failed to find 'SWITCH_STATE' entry.");
 
218
+        goto out;
 
219
+    }
 
220
+
 
221
+    state = udev_list_entry_get_value(entry);
 
222
+    if (!state) {
 
223
+        pa_log("udev_list_entry_get_by_name failed.");
 
224
+        goto out;
 
225
+    }
 
226
+
 
227
+    if (pa_atou(state, &as->current_value) < 0) {
 
228
+        pa_log_warn("Switch '%s' has invalid value '%s'", as->name, state);
 
229
+        goto out;
 
230
+    }
 
231
+
 
232
+    notify_ports(u, as);
 
233
+
 
234
+out:
 
235
+    udev_device_unref(d);
 
236
+}
 
237
+
 
238
+static bool init_udev(pa_alsa_extcon *u, pa_core *core) {
 
239
+
 
240
+    int fd;
 
241
+
 
242
+    u->udev.udev = udev_new();
 
243
+    if (!u->udev.udev) {
 
244
+        pa_log("udev_new failed.");
 
245
+        return false;
 
246
+    }
 
247
+
 
248
+    u->udev.monitor = udev_monitor_new_from_netlink(u->udev.udev, "udev");
 
249
+    if (!u->udev.monitor) {
 
250
+        pa_log("udev_monitor_new_from_netlink failed.");
 
251
+        return false;
 
252
+    }
 
253
+/*
 
254
+    if (udev_monitor_filter_add_match_subsystem_devtype(u->udev.monitor, EXTCON_NAME, NULL) < 0) {
 
255
+        pa_log("udev_monitor_filter_add_match_subsystem_devtype failed.");
 
256
+        return false;
 
257
+    }
 
258
+*/
 
259
+    if (udev_monitor_enable_receiving(u->udev.monitor) < 0) {
 
260
+        pa_log("udev_monitor_enable_receiving failed.");
 
261
+        return false;
 
262
+    }
 
263
+
 
264
+    fd = udev_monitor_get_fd(u->udev.monitor);
 
265
+    if (fd < 0) {
 
266
+        pa_log("udev_monitor_get_fd failed");
 
267
+        return false;
 
268
+    }
 
269
+
 
270
+    pa_assert_se(u->udev.event = core->mainloop->io_new(core->mainloop, fd,
 
271
+                 PA_IO_EVENT_INPUT, udev_cb, u));
 
272
+
 
273
+    return true;
 
274
+}
 
275
+
 
276
+pa_alsa_extcon *pa_alsa_extcon_new(pa_core *core, pa_card *card) {
 
277
+
 
278
+    pa_alsa_extcon *u = pa_xnew0(pa_alsa_extcon, 1);
 
279
+
 
280
+    pa_assert(core);
 
281
+    pa_assert(card);
 
282
+    pa_log_error("pa_alsa_extcon_new start 2");
 
283
+    u->card = card;
 
284
+    u->h2w = android_switch_new("h2w");
 
285
+    if (!u->h2w)
 
286
+        goto fail;
 
287
+
 
288
+    if (!init_udev(u, core))
 
289
+        goto fail;
 
290
+
 
291
+    notify_ports(u, u->h2w);
 
292
+    pa_log_error("pa_alsa_extcon_new finish");
 
293
+    return u;
 
294
+
 
295
+fail:
 
296
+    pa_alsa_extcon_free(u);
 
297
+    pa_log_error("pa_alsa_extcon_new fail");
 
298
+    return NULL;
 
299
+}
 
300
+
 
301
+void pa_alsa_extcon_free(pa_alsa_extcon *u) {
 
302
+
 
303
+    pa_assert(u);
 
304
+
 
305
+    if (u->udev.event)
 
306
+        u->card->core->mainloop->io_free(u->udev.event);
 
307
+
 
308
+    if (u->udev.monitor)
 
309
+        udev_monitor_unref(u->udev.monitor);
 
310
+
 
311
+    if (u->udev.udev)
 
312
+        udev_unref(u->udev.udev);
 
313
+
 
314
+    if (u->h2w)
 
315
+        android_switch_free(u->h2w);
 
316
+
 
317
+    pa_xfree(u);
 
318
+}
 
319
diff --git a/src/modules/alsa/alsa-extcon.h b/src/modules/alsa/alsa-extcon.h
 
320
new file mode 100644
 
321
index 0000000..7655746
 
322
--- /dev/null
 
323
+++ b/src/modules/alsa/alsa-extcon.h
 
324
@@ -0,0 +1,33 @@
 
325
+#ifndef fooalsaextconhfoo
 
326
+#define fooalsaextconhfoo
 
327
+
 
328
+/***
 
329
+  This file is part of PulseAudio.
 
330
+
 
331
+  Copyright 2013 David Henningsson, Canonical Ltd.
 
332
+
 
333
+  PulseAudio is free software; you can redistribute it and/or modify
 
334
+  it under the terms of the GNU Lesser General Public License as published
 
335
+  by the Free Software Foundation; either version 2.1 of the License,
 
336
+  or (at your option) any later version.
 
337
+
 
338
+  PulseAudio is distributed in the hope that it will be useful, but
 
339
+  WITHOUT ANY WARRANTY; without even the implied warranty of
 
340
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 
341
+  General Public License for more details.
 
342
+
 
343
+  You should have received a copy of the GNU Lesser General Public License
 
344
+  along with PulseAudio; if not, write to the Free Software
 
345
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
346
+  USA.
 
347
+***/
 
348
+
 
349
+/* TODO: Handle !HAVE_UDEV and !HAVE_UCM */
 
350
+
 
351
+typedef struct pa_alsa_extcon pa_alsa_extcon;
 
352
+
 
353
+pa_alsa_extcon *pa_alsa_extcon_new(pa_core *, pa_card *);
 
354
+
 
355
+void pa_alsa_extcon_free(pa_alsa_extcon *);
 
356
+
 
357
+#endif
 
358
diff --git a/src/modules/alsa/alsa-ucm.c b/src/modules/alsa/alsa-ucm.c
 
359
index f69ee89..ae90fec 100644
 
360
--- a/src/modules/alsa/alsa-ucm.c
 
361
+++ b/src/modules/alsa/alsa-ucm.c
 
362
@@ -719,7 +719,7 @@ static void ucm_add_port_combination(
 
363
     }
 
364
 }
 
365
 
 
366
-static int ucm_port_contains(const char *port_name, const char *dev_name, bool is_sink) {
 
367
+int pa_alsa_ucm_port_contains(const char *port_name, const char *dev_name, bool is_sink) {
 
368
     int ret = 0;
 
369
     const char *r;
 
370
     const char *state = NULL;
 
371
@@ -973,7 +973,7 @@ int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *p
 
372
     PA_IDXSET_FOREACH(dev, context->ucm_devices, idx) {
 
373
         const char *dev_name = pa_proplist_gets(dev->proplist, PA_ALSA_PROP_UCM_NAME);
 
374
 
 
375
-        if (ucm_port_contains(port->name, dev_name, is_sink))
 
376
+        if (pa_alsa_ucm_port_contains(port->name, dev_name, is_sink))
 
377
             enable_devs[enable_num++] = dev_name;
 
378
         else {
 
379
             pa_log_debug("Disable ucm device %s", dev_name);
 
380
diff --git a/src/modules/alsa/alsa-ucm.h b/src/modules/alsa/alsa-ucm.h
 
381
index cdeb469..8caa414 100644
 
382
--- a/src/modules/alsa/alsa-ucm.h
 
383
+++ b/src/modules/alsa/alsa-ucm.h
 
384
@@ -102,6 +102,7 @@ void pa_alsa_ucm_add_ports_combination(
 
385
         pa_card_profile *cp,
 
386
         pa_core *core);
 
387
 int pa_alsa_ucm_set_port(pa_alsa_ucm_mapping_context *context, pa_device_port *port, bool is_sink);
 
388
+int pa_alsa_ucm_port_contains(const char *port_name, const char *dev_name, bool is_sink);
 
389
 
 
390
 void pa_alsa_ucm_free(pa_alsa_ucm_config *ucm);
 
391
 void pa_alsa_ucm_mapping_context_free(pa_alsa_ucm_mapping_context *context);
 
392
diff --git a/src/modules/alsa/module-alsa-card.c b/src/modules/alsa/module-alsa-card.c
 
393
index fe05e3d..eb8f4e7 100644
 
394
--- a/src/modules/alsa/module-alsa-card.c
 
395
+++ b/src/modules/alsa/module-alsa-card.c
 
396
@@ -38,6 +38,7 @@
 
397
 
 
398
 #include "alsa-util.h"
 
399
 #include "alsa-ucm.h"
 
400
+#include "alsa-extcon.h"
 
401
 #include "alsa-sink.h"
 
402
 #include "alsa-source.h"
 
403
 #include "module-alsa-card-symdef.h"
 
404
@@ -114,6 +115,7 @@ struct userdata {
 
405
     snd_hctl_t *hctl_handle;
 
406
     pa_hashmap *jacks;
 
407
     pa_alsa_fdlist *mixer_fdl;
 
408
+    pa_alsa_extcon *extcon;
 
409
 
 
410
     pa_card *card;
 
411
 
 
412
@@ -752,6 +754,7 @@ int pa__init(pa_module *m) {
 
413
     u->card->set_profile = card_set_profile;
 
414
 
 
415
     init_jacks(u);
 
416
+    u->extcon = pa_alsa_extcon_new(m->core, u->card);
 
417
     init_profile(u);
 
418
     init_eld_ctls(u);
 
419
 
 
420
@@ -817,6 +820,8 @@ void pa__done(pa_module*m) {
 
421
     if (u->source_output_unlink_hook_slot)
 
422
         pa_hook_slot_free(u->source_output_unlink_hook_slot);
 
423
 
 
424
+    if (u->extcon)
 
425
+        pa_alsa_extcon_free(u->extcon);
 
426
     if (u->mixer_fdl)
 
427
         pa_alsa_fdlist_free(u->mixer_fdl);
 
428
     if (u->mixer_handle)
 
429
-- 
 
430
1.7.9.5
 
431