1 | // SPDX-License-Identifier: GPL-2.0-or-later
|
---|
2 | /*
|
---|
3 | * Loopback soundcard
|
---|
4 | *
|
---|
5 | * Original code:
|
---|
6 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
|
---|
7 | *
|
---|
8 | * More accurate positioning and full-duplex support:
|
---|
9 | * Copyright (c) Ahmet İnan <ainan at mathematik.uni-freiburg.de>
|
---|
10 | *
|
---|
11 | * Major (almost complete) rewrite:
|
---|
12 | * Copyright (c) by Takashi Iwai <tiwai@suse.de>
|
---|
13 | *
|
---|
14 | * A next major update in 2010 (separate timers for playback and capture):
|
---|
15 | * Copyright (c) Jaroslav Kysela <perex@perex.cz>
|
---|
16 | */
|
---|
17 |
|
---|
18 | #include <linux/init.h>
|
---|
19 | #include <linux/jiffies.h>
|
---|
20 | #include <linux/slab.h>
|
---|
21 | #include <linux/time.h>
|
---|
22 | #include <linux/wait.h>
|
---|
23 | #include <linux/module.h>
|
---|
24 | #include <linux/platform_device.h>
|
---|
25 | #include <sound/core.h>
|
---|
26 | #include <sound/control.h>
|
---|
27 | #include <sound/pcm.h>
|
---|
28 | #include <sound/pcm_params.h>
|
---|
29 | #include <sound/info.h>
|
---|
30 | #include <sound/initval.h>
|
---|
31 | #include <sound/timer.h>
|
---|
32 |
|
---|
33 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
|
---|
34 | MODULE_DESCRIPTION("A loopback soundcard");
|
---|
35 | MODULE_LICENSE("GPL");
|
---|
36 | MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");
|
---|
37 |
|
---|
38 | #define MAX_PCM_SUBSTREAMS 8
|
---|
39 |
|
---|
40 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
|
---|
41 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
|
---|
42 | static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
|
---|
43 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
|
---|
44 | static int pcm_notify[SNDRV_CARDS];
|
---|
45 | static char *timer_source[SNDRV_CARDS];
|
---|
46 |
|
---|
47 | module_param_array(index, int, NULL, 0444);
|
---|
48 | MODULE_PARM_DESC(index, "Index value for loopback soundcard.");
|
---|
49 | module_param_array(id, charp, NULL, 0444);
|
---|
50 | MODULE_PARM_DESC(id, "ID string for loopback soundcard.");
|
---|
51 | module_param_array(enable, bool, NULL, 0444);
|
---|
52 | MODULE_PARM_DESC(enable, "Enable this loopback soundcard.");
|
---|
53 | module_param_array(pcm_substreams, int, NULL, 0444);
|
---|
54 | MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver.");
|
---|
55 | module_param_array(pcm_notify, int, NULL, 0444);
|
---|
56 | MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes.");
|
---|
57 | module_param_array(timer_source, charp, NULL, 0444);
|
---|
58 | MODULE_PARM_DESC(timer_source, "Sound card name or number and device/subdevice number of timer to be used. Empty string for jiffies timer [default].");
|
---|
59 |
|
---|
60 | #define NO_PITCH 100000
|
---|
61 |
|
---|
62 | #define CABLE_VALID_PLAYBACK BIT(SNDRV_PCM_STREAM_PLAYBACK)
|
---|
63 | #define CABLE_VALID_CAPTURE BIT(SNDRV_PCM_STREAM_CAPTURE)
|
---|
64 | #define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK | CABLE_VALID_CAPTURE)
|
---|
65 |
|
---|
66 | struct loopback_cable;
|
---|
67 | struct loopback_pcm;
|
---|
68 |
|
---|
69 | struct loopback_ops {
|
---|
70 | /* optional
|
---|
71 | * call in loopback->cable_lock
|
---|
72 | */
|
---|
73 | int (*open)(struct loopback_pcm *dpcm);
|
---|
74 | /* required
|
---|
75 | * call in cable->lock
|
---|
76 | */
|
---|
77 | int (*start)(struct loopback_pcm *dpcm);
|
---|
78 | /* required
|
---|
79 | * call in cable->lock
|
---|
80 | */
|
---|
81 | int (*stop)(struct loopback_pcm *dpcm);
|
---|
82 | /* optional */
|
---|
83 | int (*stop_sync)(struct loopback_pcm *dpcm);
|
---|
84 | /* optional */
|
---|
85 | int (*close_substream)(struct loopback_pcm *dpcm);
|
---|
86 | /* optional
|
---|
87 | * call in loopback->cable_lock
|
---|
88 | */
|
---|
89 | int (*close_cable)(struct loopback_pcm *dpcm);
|
---|
90 | /* optional
|
---|
91 | * call in cable->lock
|
---|
92 | */
|
---|
93 | unsigned int (*pos_update)(struct loopback_cable *cable);
|
---|
94 | /* optional */
|
---|
95 | void (*dpcm_info)(struct loopback_pcm *dpcm,
|
---|
96 | struct snd_info_buffer *buffer);
|
---|
97 | };
|
---|
98 |
|
---|
99 | struct loopback_cable {
|
---|
100 | spinlock_t lock;
|
---|
101 | struct loopback_pcm *streams[2];
|
---|
102 | struct snd_pcm_hardware hw;
|
---|
103 | /* flags */
|
---|
104 | unsigned int valid;
|
---|
105 | unsigned int running;
|
---|
106 | unsigned int pause;
|
---|
107 | /* timer specific */
|
---|
108 | struct loopback_ops *ops;
|
---|
109 | /* If sound timer is used */
|
---|
110 | struct {
|
---|
111 | int stream;
|
---|
112 | struct snd_timer_id id;
|
---|
113 | struct work_struct event_work;
|
---|
114 | struct snd_timer_instance *instance;
|
---|
115 | } snd_timer;
|
---|
116 | };
|
---|
117 |
|
---|
118 | struct loopback_setup {
|
---|
119 | unsigned int notify: 1;
|
---|
120 | unsigned int rate_shift;
|
---|
121 | snd_pcm_format_t format;
|
---|
122 | unsigned int rate;
|
---|
123 | unsigned int channels;
|
---|
124 | struct snd_ctl_elem_id active_id;
|
---|
125 | struct snd_ctl_elem_id format_id;
|
---|
126 | struct snd_ctl_elem_id rate_id;
|
---|
127 | struct snd_ctl_elem_id channels_id;
|
---|
128 | };
|
---|
129 |
|
---|
130 | struct loopback {
|
---|
131 | struct snd_card *card;
|
---|
132 | struct mutex cable_lock;
|
---|
133 | struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2];
|
---|
134 | struct snd_pcm *pcm[2];
|
---|
135 | struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2];
|
---|
136 | const char *timer_source;
|
---|
137 | };
|
---|
138 |
|
---|
139 | struct loopback_pcm {
|
---|
140 | struct loopback *loopback;
|
---|
141 | struct snd_pcm_substream *substream;
|
---|
142 | struct loopback_cable *cable;
|
---|
143 | unsigned int pcm_buffer_size;
|
---|
144 | unsigned int buf_pos; /* position in buffer */
|
---|
145 | unsigned int silent_size;
|
---|
146 | /* PCM parameters */
|
---|
147 | unsigned int pcm_period_size;
|
---|
148 | unsigned int pcm_bps; /* bytes per second */
|
---|
149 | unsigned int pcm_salign; /* bytes per sample * channels */
|
---|
150 | unsigned int pcm_rate_shift; /* rate shift value */
|
---|
151 | /* flags */
|
---|
152 | unsigned int period_update_pending :1;
|
---|
153 | /* timer stuff */
|
---|
154 | unsigned int irq_pos; /* fractional IRQ position in jiffies
|
---|
155 | * ticks
|
---|
156 | */
|
---|
157 | unsigned int period_size_frac; /* period size in jiffies ticks */
|
---|
158 | unsigned int last_drift;
|
---|
159 | unsigned long last_jiffies;
|
---|
160 | /* If jiffies timer is used */
|
---|
161 | struct timer_list timer;
|
---|
162 | };
|
---|
163 |
|
---|
164 | static struct platform_device *devices[SNDRV_CARDS];
|
---|
165 |
|
---|
166 | static inline unsigned int byte_pos(struct loopback_pcm *dpcm, unsigned int x)
|
---|
167 | {
|
---|
168 | if (dpcm->pcm_rate_shift == NO_PITCH) {
|
---|
169 | x /= HZ;
|
---|
170 | } else {
|
---|
171 | x = div_u64(NO_PITCH * (unsigned long long)x,
|
---|
172 | HZ * (unsigned long long)dpcm->pcm_rate_shift);
|
---|
173 | }
|
---|
174 | return x - (x % dpcm->pcm_salign);
|
---|
175 | }
|
---|
176 |
|
---|
177 | static inline unsigned int frac_pos(struct loopback_pcm *dpcm, unsigned int x)
|
---|
178 | {
|
---|
179 | if (dpcm->pcm_rate_shift == NO_PITCH) { /* no pitch */
|
---|
180 | return x * HZ;
|
---|
181 | } else {
|
---|
182 | x = div_u64(dpcm->pcm_rate_shift * (unsigned long long)x * HZ,
|
---|
183 | NO_PITCH);
|
---|
184 | }
|
---|
185 | return x;
|
---|
186 | }
|
---|
187 |
|
---|
188 | static inline struct loopback_setup *get_setup(struct loopback_pcm *dpcm)
|
---|
189 | {
|
---|
190 | int device = dpcm->substream->pstr->pcm->device;
|
---|
191 |
|
---|
192 | if (dpcm->substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
---|
193 | device ^= 1;
|
---|
194 | return &dpcm->loopback->setup[dpcm->substream->number][device];
|
---|
195 | }
|
---|
196 |
|
---|
197 | static inline unsigned int get_notify(struct loopback_pcm *dpcm)
|
---|
198 | {
|
---|
199 | return get_setup(dpcm)->notify;
|
---|
200 | }
|
---|
201 |
|
---|
202 | static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm)
|
---|
203 | {
|
---|
204 | return get_setup(dpcm)->rate_shift;
|
---|
205 | }
|
---|
206 |
|
---|
207 | /* call in cable->lock */
|
---|
208 | static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm)
|
---|
209 | {
|
---|
210 | unsigned long tick;
|
---|
211 | unsigned int rate_shift = get_rate_shift(dpcm);
|
---|
212 |
|
---|
213 | if (rate_shift != dpcm->pcm_rate_shift) {
|
---|
214 | dpcm->pcm_rate_shift = rate_shift;
|
---|
215 | dpcm->period_size_frac = frac_pos(dpcm, dpcm->pcm_period_size);
|
---|
216 | }
|
---|
217 | if (dpcm->period_size_frac <= dpcm->irq_pos) {
|
---|
218 | dpcm->irq_pos %= dpcm->period_size_frac;
|
---|
219 | dpcm->period_update_pending = 1;
|
---|
220 | }
|
---|
221 | tick = dpcm->period_size_frac - dpcm->irq_pos;
|
---|
222 | tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps;
|
---|
223 | mod_timer(&dpcm->timer, jiffies + tick);
|
---|
224 |
|
---|
225 | return 0;
|
---|
226 | }
|
---|
227 |
|
---|
228 | /* call in cable->lock */
|
---|
229 | static int loopback_snd_timer_start(struct loopback_pcm *dpcm)
|
---|
230 | {
|
---|
231 | struct loopback_cable *cable = dpcm->cable;
|
---|
232 | int err;
|
---|
233 |
|
---|
234 | /* Loopback device has to use same period as timer card. Therefore
|
---|
235 | * wake up for each snd_pcm_period_elapsed() call of timer card.
|
---|
236 | */
|
---|
237 | err = snd_timer_start(cable->snd_timer.instance, 1);
|
---|
238 | if (err < 0) {
|
---|
239 | /* do not report error if trying to start but already
|
---|
240 | * running. For example called by opposite substream
|
---|
241 | * of the same cable
|
---|
242 | */
|
---|
243 | if (err == -EBUSY)
|
---|
244 | return 0;
|
---|
245 |
|
---|
246 | pcm_err(dpcm->substream->pcm,
|
---|
247 | "snd_timer_start(%d,%d,%d) failed with %d",
|
---|
248 | cable->snd_timer.id.card,
|
---|
249 | cable->snd_timer.id.device,
|
---|
250 | cable->snd_timer.id.subdevice,
|
---|
251 | err);
|
---|
252 | }
|
---|
253 |
|
---|
254 | return err;
|
---|
255 | }
|
---|
256 |
|
---|
257 | /* call in cable->lock */
|
---|
258 | static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm)
|
---|
259 | {
|
---|
260 | del_timer(&dpcm->timer);
|
---|
261 | dpcm->timer.expires = 0;
|
---|
262 |
|
---|
263 | return 0;
|
---|
264 | }
|
---|
265 |
|
---|
266 | /* call in cable->lock */
|
---|
267 | static int loopback_snd_timer_stop(struct loopback_pcm *dpcm)
|
---|
268 | {
|
---|
269 | struct loopback_cable *cable = dpcm->cable;
|
---|
270 | int err;
|
---|
271 |
|
---|
272 | /* only stop if both devices (playback and capture) are not running */
|
---|
273 | if (cable->running ^ cable->pause)
|
---|
274 | return 0;
|
---|
275 |
|
---|
276 | err = snd_timer_stop(cable->snd_timer.instance);
|
---|
277 | if (err < 0) {
|
---|
278 | pcm_err(dpcm->substream->pcm,
|
---|
279 | "snd_timer_stop(%d,%d,%d) failed with %d",
|
---|
280 | cable->snd_timer.id.card,
|
---|
281 | cable->snd_timer.id.device,
|
---|
282 | cable->snd_timer.id.subdevice,
|
---|
283 | err);
|
---|
284 | }
|
---|
285 |
|
---|
286 | return err;
|
---|
287 | }
|
---|
288 |
|
---|
289 | static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm)
|
---|
290 | {
|
---|
291 | del_timer_sync(&dpcm->timer);
|
---|
292 |
|
---|
293 | return 0;
|
---|
294 | }
|
---|
295 |
|
---|
296 | /* call in loopback->cable_lock */
|
---|
297 | static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
|
---|
298 | {
|
---|
299 | struct loopback_cable *cable = dpcm->cable;
|
---|
300 |
|
---|
301 | /* snd_timer was not opened */
|
---|
302 | if (!cable->snd_timer.instance)
|
---|
303 | return 0;
|
---|
304 |
|
---|
305 | /* will only be called from free_cable() when other stream was
|
---|
306 | * already closed. Other stream cannot be reopened as long as
|
---|
307 | * loopback->cable_lock is locked. Therefore no need to lock
|
---|
308 | * cable->lock;
|
---|
309 | */
|
---|
310 | snd_timer_close(cable->snd_timer.instance);
|
---|
311 |
|
---|
312 | /* wait till drain work has finished if requested */
|
---|
313 | cancel_work_sync(&cable->snd_timer.event_work);
|
---|
314 |
|
---|
315 | snd_timer_instance_free(cable->snd_timer.instance);
|
---|
316 | memset(&cable->snd_timer, 0, sizeof(cable->snd_timer));
|
---|
317 |
|
---|
318 | return 0;
|
---|
319 | }
|
---|
320 |
|
---|
321 | static int loopback_check_format(struct loopback_cable *cable, int stream)
|
---|
322 | {
|
---|
323 | struct snd_pcm_runtime *runtime, *cruntime;
|
---|
324 | struct loopback_setup *setup;
|
---|
325 | struct snd_card *card;
|
---|
326 | int check;
|
---|
327 |
|
---|
328 | if (cable->valid != CABLE_VALID_BOTH) {
|
---|
329 | if (stream == SNDRV_PCM_STREAM_PLAYBACK)
|
---|
330 | goto __notify;
|
---|
331 | return 0;
|
---|
332 | }
|
---|
333 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
|
---|
334 | substream->runtime;
|
---|
335 | cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
|
---|
336 | substream->runtime;
|
---|
337 | check = runtime->format != cruntime->format ||
|
---|
338 | runtime->rate != cruntime->rate ||
|
---|
339 | runtime->channels != cruntime->channels;
|
---|
340 | if (!check)
|
---|
341 | return 0;
|
---|
342 | if (stream == SNDRV_PCM_STREAM_CAPTURE) {
|
---|
343 | return -EIO;
|
---|
344 | } else {
|
---|
345 | snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
|
---|
346 | substream, SNDRV_PCM_STATE_DRAINING);
|
---|
347 | __notify:
|
---|
348 | runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
|
---|
349 | substream->runtime;
|
---|
350 | setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]);
|
---|
351 | card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card;
|
---|
352 | if (setup->format != runtime->format) {
|
---|
353 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
---|
354 | &setup->format_id);
|
---|
355 | setup->format = runtime->format;
|
---|
356 | }
|
---|
357 | if (setup->rate != runtime->rate) {
|
---|
358 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
---|
359 | &setup->rate_id);
|
---|
360 | setup->rate = runtime->rate;
|
---|
361 | }
|
---|
362 | if (setup->channels != runtime->channels) {
|
---|
363 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
---|
364 | &setup->channels_id);
|
---|
365 | setup->channels = runtime->channels;
|
---|
366 | }
|
---|
367 | }
|
---|
368 | return 0;
|
---|
369 | }
|
---|
370 |
|
---|
371 | static void loopback_active_notify(struct loopback_pcm *dpcm)
|
---|
372 | {
|
---|
373 | snd_ctl_notify(dpcm->loopback->card,
|
---|
374 | SNDRV_CTL_EVENT_MASK_VALUE,
|
---|
375 | &get_setup(dpcm)->active_id);
|
---|
376 | }
|
---|
377 |
|
---|
378 | static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)
|
---|
379 | {
|
---|
380 | struct snd_pcm_runtime *runtime = substream->runtime;
|
---|
381 | struct loopback_pcm *dpcm = runtime->private_data;
|
---|
382 | struct loopback_cable *cable = dpcm->cable;
|
---|
383 | int err = 0, stream = 1 << substream->stream;
|
---|
384 |
|
---|
385 | switch (cmd) {
|
---|
386 | case SNDRV_PCM_TRIGGER_START:
|
---|
387 | err = loopback_check_format(cable, substream->stream);
|
---|
388 | if (err < 0)
|
---|
389 | return err;
|
---|
390 | dpcm->last_jiffies = jiffies;
|
---|
391 | dpcm->pcm_rate_shift = 0;
|
---|
392 | dpcm->last_drift = 0;
|
---|
393 | spin_lock(&cable->lock);
|
---|
394 | cable->running |= stream;
|
---|
395 | cable->pause &= ~stream;
|
---|
396 | err = cable->ops->start(dpcm);
|
---|
397 | spin_unlock(&cable->lock);
|
---|
398 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
---|
399 | loopback_active_notify(dpcm);
|
---|
400 | break;
|
---|
401 | case SNDRV_PCM_TRIGGER_STOP:
|
---|
402 | spin_lock(&cable->lock);
|
---|
403 | cable->running &= ~stream;
|
---|
404 | cable->pause &= ~stream;
|
---|
405 | err = cable->ops->stop(dpcm);
|
---|
406 | spin_unlock(&cable->lock);
|
---|
407 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
---|
408 | loopback_active_notify(dpcm);
|
---|
409 | break;
|
---|
410 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
---|
411 | case SNDRV_PCM_TRIGGER_SUSPEND:
|
---|
412 | spin_lock(&cable->lock);
|
---|
413 | cable->pause |= stream;
|
---|
414 | err = cable->ops->stop(dpcm);
|
---|
415 | spin_unlock(&cable->lock);
|
---|
416 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
---|
417 | loopback_active_notify(dpcm);
|
---|
418 | break;
|
---|
419 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
---|
420 | case SNDRV_PCM_TRIGGER_RESUME:
|
---|
421 | spin_lock(&cable->lock);
|
---|
422 | dpcm->last_jiffies = jiffies;
|
---|
423 | cable->pause &= ~stream;
|
---|
424 | err = cable->ops->start(dpcm);
|
---|
425 | spin_unlock(&cable->lock);
|
---|
426 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
---|
427 | loopback_active_notify(dpcm);
|
---|
428 | break;
|
---|
429 | default:
|
---|
430 | return -EINVAL;
|
---|
431 | }
|
---|
432 | return err;
|
---|
433 | }
|
---|
434 |
|
---|
435 | static void params_change(struct snd_pcm_substream *substream)
|
---|
436 | {
|
---|
437 | struct snd_pcm_runtime *runtime = substream->runtime;
|
---|
438 | struct loopback_pcm *dpcm = runtime->private_data;
|
---|
439 | struct loopback_cable *cable = dpcm->cable;
|
---|
440 |
|
---|
441 | cable->hw.formats = pcm_format_to_bits(runtime->format);
|
---|
442 | cable->hw.rate_min = runtime->rate;
|
---|
443 | cable->hw.rate_max = runtime->rate;
|
---|
444 | cable->hw.channels_min = runtime->channels;
|
---|
445 | cable->hw.channels_max = runtime->channels;
|
---|
446 |
|
---|
447 | if (cable->snd_timer.instance) {
|
---|
448 | cable->hw.period_bytes_min =
|
---|
449 | frames_to_bytes(runtime, runtime->period_size);
|
---|
450 | cable->hw.period_bytes_max = cable->hw.period_bytes_min;
|
---|
451 | }
|
---|
452 |
|
---|
453 | }
|
---|
454 |
|
---|
455 | static int loopback_prepare(struct snd_pcm_substream *substream)
|
---|
456 | {
|
---|
457 | struct snd_pcm_runtime *runtime = substream->runtime;
|
---|
458 | struct loopback_pcm *dpcm = runtime->private_data;
|
---|
459 | struct loopback_cable *cable = dpcm->cable;
|
---|
460 | int err, bps, salign;
|
---|
461 |
|
---|
462 | if (cable->ops->stop_sync) {
|
---|
463 | err = cable->ops->stop_sync(dpcm);
|
---|
464 | if (err < 0)
|
---|
465 | return err;
|
---|
466 | }
|
---|
467 |
|
---|
468 | salign = (snd_pcm_format_physical_width(runtime->format) *
|
---|
469 | runtime->channels) / 8;
|
---|
470 | bps = salign * runtime->rate;
|
---|
471 | if (bps <= 0 || salign <= 0)
|
---|
472 | return -EINVAL;
|
---|
473 |
|
---|
474 | dpcm->buf_pos = 0;
|
---|
475 | dpcm->pcm_buffer_size = frames_to_bytes(runtime, runtime->buffer_size);
|
---|
476 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
|
---|
477 | /* clear capture buffer */
|
---|
478 | dpcm->silent_size = dpcm->pcm_buffer_size;
|
---|
479 | snd_pcm_format_set_silence(runtime->format, runtime->dma_area,
|
---|
480 | runtime->buffer_size * runtime->channels);
|
---|
481 | }
|
---|
482 |
|
---|
483 | dpcm->irq_pos = 0;
|
---|
484 | dpcm->period_update_pending = 0;
|
---|
485 | dpcm->pcm_bps = bps;
|
---|
486 | dpcm->pcm_salign = salign;
|
---|
487 | dpcm->pcm_period_size = frames_to_bytes(runtime, runtime->period_size);
|
---|
488 |
|
---|
489 | mutex_lock(&dpcm->loopback->cable_lock);
|
---|
490 | if (!(cable->valid & ~(1 << substream->stream)) ||
|
---|
491 | (get_setup(dpcm)->notify &&
|
---|
492 | substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
|
---|
493 | params_change(substream);
|
---|
494 | cable->valid |= 1 << substream->stream;
|
---|
495 | mutex_unlock(&dpcm->loopback->cable_lock);
|
---|
496 |
|
---|
497 | return 0;
|
---|
498 | }
|
---|
499 |
|
---|
500 | static void clear_capture_buf(struct loopback_pcm *dpcm, unsigned int bytes)
|
---|
501 | {
|
---|
502 | struct snd_pcm_runtime *runtime = dpcm->substream->runtime;
|
---|
503 | char *dst = runtime->dma_area;
|
---|
504 | unsigned int dst_off = dpcm->buf_pos;
|
---|
505 |
|
---|
506 | if (dpcm->silent_size >= dpcm->pcm_buffer_size)
|
---|
507 | return;
|
---|
508 | if (dpcm->silent_size + bytes > dpcm->pcm_buffer_size)
|
---|
509 | bytes = dpcm->pcm_buffer_size - dpcm->silent_size;
|
---|
510 |
|
---|
511 | for (;;) {
|
---|
512 | unsigned int size = bytes;
|
---|
513 | if (dst_off + size > dpcm->pcm_buffer_size)
|
---|
514 | size = dpcm->pcm_buffer_size - dst_off;
|
---|
515 | snd_pcm_format_set_silence(runtime->format, dst + dst_off,
|
---|
516 | bytes_to_frames(runtime, size) *
|
---|
517 | runtime->channels);
|
---|
518 | dpcm->silent_size += size;
|
---|
519 | bytes -= size;
|
---|
520 | if (!bytes)
|
---|
521 | break;
|
---|
522 | dst_off = 0;
|
---|
523 | }
|
---|
524 | }
|
---|
525 |
|
---|
526 | static void copy_play_buf(struct loopback_pcm *play,
|
---|
527 | struct loopback_pcm *capt,
|
---|
528 | unsigned int bytes)
|
---|
529 | {
|
---|
530 | struct snd_pcm_runtime *runtime = play->substream->runtime;
|
---|
531 | char *src = runtime->dma_area;
|
---|
532 | char *dst = capt->substream->runtime->dma_area;
|
---|
533 | unsigned int src_off = play->buf_pos;
|
---|
534 | unsigned int dst_off = capt->buf_pos;
|
---|
535 | unsigned int clear_bytes = 0;
|
---|
536 |
|
---|
537 | /* check if playback is draining, trim the capture copy size
|
---|
538 | * when our pointer is at the end of playback ring buffer */
|
---|
539 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
|
---|
540 | snd_pcm_playback_hw_avail(runtime) < runtime->buffer_size) {
|
---|
541 | snd_pcm_uframes_t appl_ptr, appl_ptr1, diff;
|
---|
542 | appl_ptr = appl_ptr1 = runtime->control->appl_ptr;
|
---|
543 | appl_ptr1 -= appl_ptr1 % runtime->buffer_size;
|
---|
544 | appl_ptr1 += play->buf_pos / play->pcm_salign;
|
---|
545 | if (appl_ptr < appl_ptr1)
|
---|
546 | appl_ptr1 -= runtime->buffer_size;
|
---|
547 | diff = (appl_ptr - appl_ptr1) * play->pcm_salign;
|
---|
548 | if (diff < bytes) {
|
---|
549 | clear_bytes = bytes - diff;
|
---|
550 | bytes = diff;
|
---|
551 | }
|
---|
552 | }
|
---|
553 |
|
---|
554 | for (;;) {
|
---|
555 | unsigned int size = bytes;
|
---|
556 | if (src_off + size > play->pcm_buffer_size)
|
---|
557 | size = play->pcm_buffer_size - src_off;
|
---|
558 | if (dst_off + size > capt->pcm_buffer_size)
|
---|
559 | size = capt->pcm_buffer_size - dst_off;
|
---|
560 | memcpy(dst + dst_off, src + src_off, size);
|
---|
561 | capt->silent_size = 0;
|
---|
562 | bytes -= size;
|
---|
563 | if (!bytes)
|
---|
564 | break;
|
---|
565 | src_off = (src_off + size) % play->pcm_buffer_size;
|
---|
566 | dst_off = (dst_off + size) % capt->pcm_buffer_size;
|
---|
567 | }
|
---|
568 |
|
---|
569 | if (clear_bytes > 0) {
|
---|
570 | clear_capture_buf(capt, clear_bytes);
|
---|
571 | capt->silent_size = 0;
|
---|
572 | }
|
---|
573 | }
|
---|
574 |
|
---|
575 | static inline unsigned int bytepos_delta(struct loopback_pcm *dpcm,
|
---|
576 | unsigned int jiffies_delta)
|
---|
577 | {
|
---|
578 | unsigned long last_pos;
|
---|
579 | unsigned int delta;
|
---|
580 |
|
---|
581 | last_pos = byte_pos(dpcm, dpcm->irq_pos);
|
---|
582 | dpcm->irq_pos += jiffies_delta * dpcm->pcm_bps;
|
---|
583 | delta = byte_pos(dpcm, dpcm->irq_pos) - last_pos;
|
---|
584 | if (delta >= dpcm->last_drift)
|
---|
585 | delta -= dpcm->last_drift;
|
---|
586 | dpcm->last_drift = 0;
|
---|
587 | if (dpcm->irq_pos >= dpcm->period_size_frac) {
|
---|
588 | dpcm->irq_pos %= dpcm->period_size_frac;
|
---|
589 | dpcm->period_update_pending = 1;
|
---|
590 | }
|
---|
591 | return delta;
|
---|
592 | }
|
---|
593 |
|
---|
594 | static inline void bytepos_finish(struct loopback_pcm *dpcm,
|
---|
595 | unsigned int delta)
|
---|
596 | {
|
---|
597 | dpcm->buf_pos += delta;
|
---|
598 | dpcm->buf_pos %= dpcm->pcm_buffer_size;
|
---|
599 | }
|
---|
600 |
|
---|
601 | /* call in cable->lock */
|
---|
602 | static unsigned int loopback_jiffies_timer_pos_update
|
---|
603 | (struct loopback_cable *cable)
|
---|
604 | {
|
---|
605 | struct loopback_pcm *dpcm_play =
|
---|
606 | cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
|
---|
607 | struct loopback_pcm *dpcm_capt =
|
---|
608 | cable->streams[SNDRV_PCM_STREAM_CAPTURE];
|
---|
609 | unsigned long delta_play = 0, delta_capt = 0;
|
---|
610 | unsigned int running, count1, count2;
|
---|
611 |
|
---|
612 | running = cable->running ^ cable->pause;
|
---|
613 | if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
|
---|
614 | delta_play = jiffies - dpcm_play->last_jiffies;
|
---|
615 | dpcm_play->last_jiffies += delta_play;
|
---|
616 | }
|
---|
617 |
|
---|
618 | if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
|
---|
619 | delta_capt = jiffies - dpcm_capt->last_jiffies;
|
---|
620 | dpcm_capt->last_jiffies += delta_capt;
|
---|
621 | }
|
---|
622 |
|
---|
623 | if (delta_play == 0 && delta_capt == 0)
|
---|
624 | goto unlock;
|
---|
625 |
|
---|
626 | if (delta_play > delta_capt) {
|
---|
627 | count1 = bytepos_delta(dpcm_play, delta_play - delta_capt);
|
---|
628 | bytepos_finish(dpcm_play, count1);
|
---|
629 | delta_play = delta_capt;
|
---|
630 | } else if (delta_play < delta_capt) {
|
---|
631 | count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play);
|
---|
632 | clear_capture_buf(dpcm_capt, count1);
|
---|
633 | bytepos_finish(dpcm_capt, count1);
|
---|
634 | delta_capt = delta_play;
|
---|
635 | }
|
---|
636 |
|
---|
637 | if (delta_play == 0 && delta_capt == 0)
|
---|
638 | goto unlock;
|
---|
639 |
|
---|
640 | /* note delta_capt == delta_play at this moment */
|
---|
641 | count1 = bytepos_delta(dpcm_play, delta_play);
|
---|
642 | count2 = bytepos_delta(dpcm_capt, delta_capt);
|
---|
643 | if (count1 < count2) {
|
---|
644 | dpcm_capt->last_drift = count2 - count1;
|
---|
645 | count1 = count2;
|
---|
646 | } else if (count1 > count2) {
|
---|
647 | dpcm_play->last_drift = count1 - count2;
|
---|
648 | }
|
---|
649 | copy_play_buf(dpcm_play, dpcm_capt, count1);
|
---|
650 | bytepos_finish(dpcm_play, count1);
|
---|
651 | bytepos_finish(dpcm_capt, count1);
|
---|
652 | unlock:
|
---|
653 | return running;
|
---|
654 | }
|
---|
655 |
|
---|
656 | static void loopback_jiffies_timer_function(struct timer_list *t)
|
---|
657 | {
|
---|
658 | struct loopback_pcm *dpcm = from_timer(dpcm, t, timer);
|
---|
659 | unsigned long flags;
|
---|
660 |
|
---|
661 | spin_lock_irqsave(&dpcm->cable->lock, flags);
|
---|
662 | if (loopback_jiffies_timer_pos_update(dpcm->cable) &
|
---|
663 | (1 << dpcm->substream->stream)) {
|
---|
664 | loopback_jiffies_timer_start(dpcm);
|
---|
665 | if (dpcm->period_update_pending) {
|
---|
666 | dpcm->period_update_pending = 0;
|
---|
667 | spin_unlock_irqrestore(&dpcm->cable->lock, flags);
|
---|
668 | /* need to unlock before calling below */
|
---|
669 | snd_pcm_period_elapsed(dpcm->substream);
|
---|
670 | return;
|
---|
671 | }
|
---|
672 | }
|
---|
673 | spin_unlock_irqrestore(&dpcm->cable->lock, flags);
|
---|
674 | }
|
---|
675 |
|
---|
676 | /* call in cable->lock */
|
---|
677 | static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime,
|
---|
678 | unsigned long resolution)
|
---|
679 | {
|
---|
680 | if (resolution != runtime->timer_resolution) {
|
---|
681 | struct loopback_pcm *dpcm = runtime->private_data;
|
---|
682 | struct loopback_cable *cable = dpcm->cable;
|
---|
683 | /* Worst case estimation of possible values for resolution
|
---|
684 | * resolution <= (512 * 1024) frames / 8kHz in nsec
|
---|
685 | * resolution <= 65.536.000.000 nsec
|
---|
686 | *
|
---|
687 | * period_size <= 65.536.000.000 nsec / 1000nsec/usec * 192kHz +
|
---|
688 | * 500.000
|
---|
689 | * period_size <= 12.582.912.000.000 <64bit
|
---|
690 | * / 1.000.000 usec/sec
|
---|
691 | */
|
---|
692 | snd_pcm_uframes_t period_size_usec =
|
---|
693 | resolution / 1000 * runtime->rate;
|
---|
694 | /* round to nearest sample rate */
|
---|
695 | snd_pcm_uframes_t period_size =
|
---|
696 | (period_size_usec + 500 * 1000) / (1000 * 1000);
|
---|
697 |
|
---|
698 | pcm_err(dpcm->substream->pcm,
|
---|
699 | "Period size (%lu frames) of loopback device is not corresponding to timer resolution (%lu nsec = %lu frames) of card timer %d,%d,%d. Use period size of %lu frames for loopback device.",
|
---|
700 | runtime->period_size, resolution, period_size,
|
---|
701 | cable->snd_timer.id.card,
|
---|
702 | cable->snd_timer.id.device,
|
---|
703 | cable->snd_timer.id.subdevice,
|
---|
704 | period_size);
|
---|
705 | return -EINVAL;
|
---|
706 | }
|
---|
707 | return 0;
|
---|
708 | }
|
---|
709 |
|
---|
710 | static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable,
|
---|
711 | int event,
|
---|
712 | unsigned long resolution)
|
---|
713 | {
|
---|
714 | struct loopback_pcm *dpcm_play, *dpcm_capt;
|
---|
715 | struct snd_pcm_substream *substream_play, *substream_capt;
|
---|
716 | struct snd_pcm_runtime *valid_runtime;
|
---|
717 | unsigned int running, elapsed_bytes;
|
---|
718 | unsigned long flags;
|
---|
719 |
|
---|
720 | spin_lock_irqsave(&cable->lock, flags);
|
---|
721 | running = cable->running ^ cable->pause;
|
---|
722 | /* no need to do anything if no stream is running */
|
---|
723 | if (!running) {
|
---|
724 | spin_unlock_irqrestore(&cable->lock, flags);
|
---|
725 | return;
|
---|
726 | }
|
---|
727 |
|
---|
728 | dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK];
|
---|
729 | dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE];
|
---|
730 |
|
---|
731 | if (event == SNDRV_TIMER_EVENT_MSTOP) {
|
---|
732 | if (!dpcm_play ||
|
---|
733 | dpcm_play->substream->runtime->status->state !=
|
---|
734 | SNDRV_PCM_STATE_DRAINING) {
|
---|
735 | spin_unlock_irqrestore(&cable->lock, flags);
|
---|
736 | return;
|
---|
737 | }
|
---|
738 | }
|
---|
739 |
|
---|
740 | substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
|
---|
741 | dpcm_play->substream : NULL;
|
---|
742 | substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ?
|
---|
743 | dpcm_capt->substream : NULL;
|
---|
744 | valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ?
|
---|
745 | dpcm_play->substream->runtime :
|
---|
746 | dpcm_capt->substream->runtime;
|
---|
747 |
|
---|
748 | /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */
|
---|
749 | if (event == SNDRV_TIMER_EVENT_TICK) {
|
---|
750 | /* The hardware rules guarantee that playback and capture period
|
---|
751 | * are the same. Therefore only one device has to be checked
|
---|
752 | * here.
|
---|
753 | */
|
---|
754 | if (loopback_snd_timer_check_resolution(valid_runtime,
|
---|
755 | resolution) < 0) {
|
---|
756 | spin_unlock_irqrestore(&cable->lock, flags);
|
---|
757 | if (substream_play)
|
---|
758 | snd_pcm_stop_xrun(substream_play);
|
---|
759 | if (substream_capt)
|
---|
760 | snd_pcm_stop_xrun(substream_capt);
|
---|
761 | return;
|
---|
762 | }
|
---|
763 | }
|
---|
764 |
|
---|
765 | elapsed_bytes = frames_to_bytes(valid_runtime,
|
---|
766 | valid_runtime->period_size);
|
---|
767 | /* The same timer interrupt is used for playback and capture device */
|
---|
768 | if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) &&
|
---|
769 | (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) {
|
---|
770 | copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes);
|
---|
771 | bytepos_finish(dpcm_play, elapsed_bytes);
|
---|
772 | bytepos_finish(dpcm_capt, elapsed_bytes);
|
---|
773 | } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {
|
---|
774 | bytepos_finish(dpcm_play, elapsed_bytes);
|
---|
775 | } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) {
|
---|
776 | clear_capture_buf(dpcm_capt, elapsed_bytes);
|
---|
777 | bytepos_finish(dpcm_capt, elapsed_bytes);
|
---|
778 | }
|
---|
779 | spin_unlock_irqrestore(&cable->lock, flags);
|
---|
780 |
|
---|
781 | if (substream_play)
|
---|
782 | snd_pcm_period_elapsed(substream_play);
|
---|
783 | if (substream_capt)
|
---|
784 | snd_pcm_period_elapsed(substream_capt);
|
---|
785 | }
|
---|
786 |
|
---|
787 | static void loopback_snd_timer_function(struct snd_timer_instance *timeri,
|
---|
788 | unsigned long resolution,
|
---|
789 | unsigned long ticks)
|
---|
790 | {
|
---|
791 | struct loopback_cable *cable = timeri->callback_data;
|
---|
792 |
|
---|
793 | loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_TICK,
|
---|
794 | resolution);
|
---|
795 | }
|
---|
796 |
|
---|
797 | static void loopback_snd_timer_work(struct work_struct *work)
|
---|
798 | {
|
---|
799 | struct loopback_cable *cable;
|
---|
800 |
|
---|
801 | cable = container_of(work, struct loopback_cable, snd_timer.event_work);
|
---|
802 | loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_MSTOP, 0);
|
---|
803 | }
|
---|
804 |
|
---|
805 | static void loopback_snd_timer_event(struct snd_timer_instance *timeri,
|
---|
806 | int event,
|
---|
807 | struct timespec64 *tstamp,
|
---|
808 | unsigned long resolution)
|
---|
809 | {
|
---|
810 | /* Do not lock cable->lock here because timer->lock is already hold.
|
---|
811 | * There are other functions which first lock cable->lock and than
|
---|
812 | * timer->lock e.g.
|
---|
813 | * loopback_trigger()
|
---|
814 | * spin_lock(&cable->lock)
|
---|
815 | * loopback_snd_timer_start()
|
---|
816 | * snd_timer_start()
|
---|
817 | * spin_lock(&timer->lock)
|
---|
818 | * Therefore when using the oposit order of locks here it could result
|
---|
819 | * in a deadlock.
|
---|
820 | */
|
---|
821 |
|
---|
822 | if (event == SNDRV_TIMER_EVENT_MSTOP) {
|
---|
823 | struct loopback_cable *cable = timeri->callback_data;
|
---|
824 |
|
---|
825 | /* sound card of the timer was stopped. Therefore there will not
|
---|
826 | * be any further timer callbacks. Due to this forward audio
|
---|
827 | * data from here if in draining state. When still in running
|
---|
828 | * state the streaming will be aborted by the usual timeout. It
|
---|
829 | * should not be aborted here because may be the timer sound
|
---|
830 | * card does only a recovery and the timer is back soon.
|
---|
831 | * This work triggers loopback_snd_timer_work()
|
---|
832 | */
|
---|
833 | schedule_work(&cable->snd_timer.event_work);
|
---|
834 | }
|
---|
835 | }
|
---|
836 |
|
---|
837 | static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm,
|
---|
838 | struct snd_info_buffer *buffer)
|
---|
839 | {
|
---|
840 | snd_iprintf(buffer, " update_pending:\t%u\n",
|
---|
841 | dpcm->period_update_pending);
|
---|
842 | snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos);
|
---|
843 | snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac);
|
---|
844 | snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n",
|
---|
845 | dpcm->last_jiffies, jiffies);
|
---|
846 | snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires);
|
---|
847 | }
|
---|
848 |
|
---|
849 | static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm,
|
---|
850 | struct snd_info_buffer *buffer)
|
---|
851 | {
|
---|
852 | struct loopback_cable *cable = dpcm->cable;
|
---|
853 |
|
---|
854 | snd_iprintf(buffer, " sound timer:\thw:%d,%d,%d\n",
|
---|
855 | cable->snd_timer.id.card,
|
---|
856 | cable->snd_timer.id.device,
|
---|
857 | cable->snd_timer.id.subdevice);
|
---|
858 | snd_iprintf(buffer, " timer open:\t\t%s\n",
|
---|
859 | (cable->snd_timer.stream == SNDRV_PCM_STREAM_CAPTURE) ?
|
---|
860 | "capture" : "playback");
|
---|
861 | }
|
---|
862 |
|
---|
863 | static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
|
---|
864 | {
|
---|
865 | struct snd_pcm_runtime *runtime = substream->runtime;
|
---|
866 | struct loopback_pcm *dpcm = runtime->private_data;
|
---|
867 | snd_pcm_uframes_t pos;
|
---|
868 |
|
---|
869 | spin_lock(&dpcm->cable->lock);
|
---|
870 | if (dpcm->cable->ops->pos_update)
|
---|
871 | dpcm->cable->ops->pos_update(dpcm->cable);
|
---|
872 | pos = dpcm->buf_pos;
|
---|
873 | spin_unlock(&dpcm->cable->lock);
|
---|
874 | return bytes_to_frames(runtime, pos);
|
---|
875 | }
|
---|
876 |
|
---|
877 | static const struct snd_pcm_hardware loopback_pcm_hardware =
|
---|
878 | {
|
---|
879 | .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP |
|
---|
880 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE |
|
---|
881 | SNDRV_PCM_INFO_RESUME),
|
---|
882 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |
|
---|
883 | SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |
|
---|
884 | SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |
|
---|
885 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |
|
---|
886 | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE),
|
---|
887 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000,
|
---|
888 | .rate_min = 8000,
|
---|
889 | .rate_max = 192000,
|
---|
890 | .channels_min = 1,
|
---|
891 | .channels_max = 32,
|
---|
892 | .buffer_bytes_max = 2 * 1024 * 1024,
|
---|
893 | .period_bytes_min = 64,
|
---|
894 | /* note check overflow in frac_pos() using pcm_rate_shift before
|
---|
895 | changing period_bytes_max value */
|
---|
896 | .period_bytes_max = 1024 * 1024,
|
---|
897 | .periods_min = 1,
|
---|
898 | .periods_max = 1024,
|
---|
899 | .fifo_size = 0,
|
---|
900 | };
|
---|
901 |
|
---|
902 | static void loopback_runtime_free(struct snd_pcm_runtime *runtime)
|
---|
903 | {
|
---|
904 | struct loopback_pcm *dpcm = runtime->private_data;
|
---|
905 | kfree(dpcm);
|
---|
906 | }
|
---|
907 |
|
---|
908 | static int loopback_hw_free(struct snd_pcm_substream *substream)
|
---|
909 | {
|
---|
910 | struct snd_pcm_runtime *runtime = substream->runtime;
|
---|
911 | struct loopback_pcm *dpcm = runtime->private_data;
|
---|
912 | struct loopback_cable *cable = dpcm->cable;
|
---|
913 |
|
---|
914 | mutex_lock(&dpcm->loopback->cable_lock);
|
---|
915 | cable->valid &= ~(1 << substream->stream);
|
---|
916 | mutex_unlock(&dpcm->loopback->cable_lock);
|
---|
917 | return 0;
|
---|
918 | }
|
---|
919 |
|
---|
920 | static unsigned int get_cable_index(struct snd_pcm_substream *substream)
|
---|
921 | {
|
---|
922 | if (!substream->pcm->device)
|
---|
923 | return substream->stream;
|
---|
924 | else
|
---|
925 | return !substream->stream;
|
---|
926 | }
|
---|
927 |
|
---|
928 | static int rule_format(struct snd_pcm_hw_params *params,
|
---|
929 | struct snd_pcm_hw_rule *rule)
|
---|
930 | {
|
---|
931 | struct loopback_pcm *dpcm = rule->private;
|
---|
932 | struct loopback_cable *cable = dpcm->cable;
|
---|
933 | struct snd_mask m;
|
---|
934 |
|
---|
935 | snd_mask_none(&m);
|
---|
936 | mutex_lock(&dpcm->loopback->cable_lock);
|
---|
937 | m.bits[0] = (u_int32_t)cable->hw.formats;
|
---|
938 | m.bits[1] = (u_int32_t)(cable->hw.formats >> 32);
|
---|
939 | mutex_unlock(&dpcm->loopback->cable_lock);
|
---|
940 | return snd_mask_refine(hw_param_mask(params, rule->var), &m);
|
---|
941 | }
|
---|
942 |
|
---|
943 | static int rule_rate(struct snd_pcm_hw_params *params,
|
---|
944 | struct snd_pcm_hw_rule *rule)
|
---|
945 | {
|
---|
946 | struct loopback_pcm *dpcm = rule->private;
|
---|
947 | struct loopback_cable *cable = dpcm->cable;
|
---|
948 | struct snd_interval t;
|
---|
949 |
|
---|
950 | mutex_lock(&dpcm->loopback->cable_lock);
|
---|
951 | t.min = cable->hw.rate_min;
|
---|
952 | t.max = cable->hw.rate_max;
|
---|
953 | mutex_unlock(&dpcm->loopback->cable_lock);
|
---|
954 | t.openmin = t.openmax = 0;
|
---|
955 | t.integer = 0;
|
---|
956 | return snd_interval_refine(hw_param_interval(params, rule->var), &t);
|
---|
957 | }
|
---|
958 |
|
---|
959 | static int rule_channels(struct snd_pcm_hw_params *params,
|
---|
960 | struct snd_pcm_hw_rule *rule)
|
---|
961 | {
|
---|
962 | struct loopback_pcm *dpcm = rule->private;
|
---|
963 | struct loopback_cable *cable = dpcm->cable;
|
---|
964 | struct snd_interval t;
|
---|
965 |
|
---|
966 | mutex_lock(&dpcm->loopback->cable_lock);
|
---|
967 | t.min = cable->hw.channels_min;
|
---|
968 | t.max = cable->hw.channels_max;
|
---|
969 | mutex_unlock(&dpcm->loopback->cable_lock);
|
---|
970 | t.openmin = t.openmax = 0;
|
---|
971 | t.integer = 0;
|
---|
972 | return snd_interval_refine(hw_param_interval(params, rule->var), &t);
|
---|
973 | }
|
---|
974 |
|
---|
975 | static int rule_period_bytes(struct snd_pcm_hw_params *params,
|
---|
976 | struct snd_pcm_hw_rule *rule)
|
---|
977 | {
|
---|
978 | struct loopback_pcm *dpcm = rule->private;
|
---|
979 | struct loopback_cable *cable = dpcm->cable;
|
---|
980 | struct snd_interval t;
|
---|
981 |
|
---|
982 | mutex_lock(&dpcm->loopback->cable_lock);
|
---|
983 | t.min = cable->hw.period_bytes_min;
|
---|
984 | t.max = cable->hw.period_bytes_max;
|
---|
985 | mutex_unlock(&dpcm->loopback->cable_lock);
|
---|
986 | t.openmin = 0;
|
---|
987 | t.openmax = 0;
|
---|
988 | t.integer = 0;
|
---|
989 | return snd_interval_refine(hw_param_interval(params, rule->var), &t);
|
---|
990 | }
|
---|
991 |
|
---|
992 | static void free_cable(struct snd_pcm_substream *substream)
|
---|
993 | {
|
---|
994 | struct loopback *loopback = substream->private_data;
|
---|
995 | int dev = get_cable_index(substream);
|
---|
996 | struct loopback_cable *cable;
|
---|
997 |
|
---|
998 | cable = loopback->cables[substream->number][dev];
|
---|
999 | if (!cable)
|
---|
1000 | return;
|
---|
1001 | if (cable->streams[!substream->stream]) {
|
---|
1002 | /* other stream is still alive */
|
---|
1003 | spin_lock_irq(&cable->lock);
|
---|
1004 | cable->streams[substream->stream] = NULL;
|
---|
1005 | spin_unlock_irq(&cable->lock);
|
---|
1006 | } else {
|
---|
1007 | struct loopback_pcm *dpcm = substream->runtime->private_data;
|
---|
1008 |
|
---|
1009 | if (cable->ops && cable->ops->close_cable && dpcm)
|
---|
1010 | cable->ops->close_cable(dpcm);
|
---|
1011 | /* free the cable */
|
---|
1012 | loopback->cables[substream->number][dev] = NULL;
|
---|
1013 | kfree(cable);
|
---|
1014 | }
|
---|
1015 | }
|
---|
1016 |
|
---|
1017 | static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
|
---|
1018 | {
|
---|
1019 | timer_setup(&dpcm->timer, loopback_jiffies_timer_function, 0);
|
---|
1020 |
|
---|
1021 | return 0;
|
---|
1022 | }
|
---|
1023 |
|
---|
1024 | static struct loopback_ops loopback_jiffies_timer_ops = {
|
---|
1025 | .open = loopback_jiffies_timer_open,
|
---|
1026 | .start = loopback_jiffies_timer_start,
|
---|
1027 | .stop = loopback_jiffies_timer_stop,
|
---|
1028 | .stop_sync = loopback_jiffies_timer_stop_sync,
|
---|
1029 | .close_substream = loopback_jiffies_timer_stop_sync,
|
---|
1030 | .pos_update = loopback_jiffies_timer_pos_update,
|
---|
1031 | .dpcm_info = loopback_jiffies_timer_dpcm_info,
|
---|
1032 | };
|
---|
1033 |
|
---|
1034 | static int loopback_parse_timer_id(const char *str,
|
---|
1035 | struct snd_timer_id *tid)
|
---|
1036 | {
|
---|
1037 | /* [<pref>:](<card name>|<card idx>)[{.,}<dev idx>[{.,}<subdev idx>]] */
|
---|
1038 | const char * const sep_dev = ".,";
|
---|
1039 | const char * const sep_pref = ":";
|
---|
1040 | const char *name = str;
|
---|
1041 | char *sep, save = '\0';
|
---|
1042 | int card_idx = 0, dev = 0, subdev = 0;
|
---|
1043 | int err;
|
---|
1044 |
|
---|
1045 | sep = strpbrk(str, sep_pref);
|
---|
1046 | if (sep)
|
---|
1047 | name = sep + 1;
|
---|
1048 | sep = strpbrk(name, sep_dev);
|
---|
1049 | if (sep) {
|
---|
1050 | save = *sep;
|
---|
1051 | *sep = '\0';
|
---|
1052 | }
|
---|
1053 | err = kstrtoint(name, 0, &card_idx);
|
---|
1054 | if (err == -EINVAL) {
|
---|
1055 | /* Must be the name, not number */
|
---|
1056 | for (card_idx = 0; card_idx < snd_ecards_limit; card_idx++) {
|
---|
1057 | struct snd_card *card = snd_card_ref(card_idx);
|
---|
1058 |
|
---|
1059 | if (card) {
|
---|
1060 | if (!strcmp(card->id, name))
|
---|
1061 | err = 0;
|
---|
1062 | snd_card_unref(card);
|
---|
1063 | }
|
---|
1064 | if (!err)
|
---|
1065 | break;
|
---|
1066 | }
|
---|
1067 | }
|
---|
1068 | if (sep) {
|
---|
1069 | *sep = save;
|
---|
1070 | if (!err) {
|
---|
1071 | char *sep2, save2 = '\0';
|
---|
1072 |
|
---|
1073 | sep2 = strpbrk(sep + 1, sep_dev);
|
---|
1074 | if (sep2) {
|
---|
1075 | save2 = *sep2;
|
---|
1076 | *sep2 = '\0';
|
---|
1077 | }
|
---|
1078 | err = kstrtoint(sep + 1, 0, &dev);
|
---|
1079 | if (sep2) {
|
---|
1080 | *sep2 = save2;
|
---|
1081 | if (!err)
|
---|
1082 | err = kstrtoint(sep2 + 1, 0, &subdev);
|
---|
1083 | }
|
---|
1084 | }
|
---|
1085 | }
|
---|
1086 | if (!err && tid) {
|
---|
1087 | tid->card = card_idx;
|
---|
1088 | tid->device = dev;
|
---|
1089 | tid->subdevice = subdev;
|
---|
1090 | }
|
---|
1091 | return err;
|
---|
1092 | }
|
---|
1093 |
|
---|
1094 | /* call in loopback->cable_lock */
|
---|
1095 | static int loopback_snd_timer_open(struct loopback_pcm *dpcm)
|
---|
1096 | {
|
---|
1097 | int err = 0;
|
---|
1098 | struct snd_timer_id tid = {
|
---|
1099 | .dev_class = SNDRV_TIMER_CLASS_PCM,
|
---|
1100 | .dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION,
|
---|
1101 | };
|
---|
1102 | struct snd_timer_instance *timeri;
|
---|
1103 | struct loopback_cable *cable = dpcm->cable;
|
---|
1104 |
|
---|
1105 | /* check if timer was already opened. It is only opened once
|
---|
1106 | * per playback and capture subdevice (aka cable).
|
---|
1107 | */
|
---|
1108 | if (cable->snd_timer.instance)
|
---|
1109 | goto exit;
|
---|
1110 |
|
---|
1111 | err = loopback_parse_timer_id(dpcm->loopback->timer_source, &tid);
|
---|
1112 | if (err < 0) {
|
---|
1113 | pcm_err(dpcm->substream->pcm,
|
---|
1114 | "Parsing timer source \'%s\' failed with %d",
|
---|
1115 | dpcm->loopback->timer_source, err);
|
---|
1116 | goto exit;
|
---|
1117 | }
|
---|
1118 |
|
---|
1119 | cable->snd_timer.stream = dpcm->substream->stream;
|
---|
1120 | cable->snd_timer.id = tid;
|
---|
1121 |
|
---|
1122 | timeri = snd_timer_instance_new(dpcm->loopback->card->id);
|
---|
1123 | if (!timeri) {
|
---|
1124 | err = -ENOMEM;
|
---|
1125 | goto exit;
|
---|
1126 | }
|
---|
1127 | /* The callback has to be called from another work. If
|
---|
1128 | * SNDRV_TIMER_IFLG_FAST is specified it will be called from the
|
---|
1129 | * snd_pcm_period_elapsed() call of the selected sound card.
|
---|
1130 | * snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave().
|
---|
1131 | * Due to our callback loopback_snd_timer_function() also calls
|
---|
1132 | * snd_pcm_period_elapsed() which calls snd_pcm_stream_lock_irqsave().
|
---|
1133 | * This would end up in a dead lock.
|
---|
1134 | */
|
---|
1135 | timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
|
---|
1136 | timeri->callback = loopback_snd_timer_function;
|
---|
1137 | timeri->callback_data = (void *)cable;
|
---|
1138 | timeri->ccallback = loopback_snd_timer_event;
|
---|
1139 |
|
---|
1140 | /* initialise a work used for draining */
|
---|
1141 | INIT_WORK(&cable->snd_timer.event_work, loopback_snd_timer_work);
|
---|
1142 |
|
---|
1143 | /* The mutex loopback->cable_lock is kept locked.
|
---|
1144 | * Therefore snd_timer_open() cannot be called a second time
|
---|
1145 | * by the other device of the same cable.
|
---|
1146 | * Therefore the following issue cannot happen:
|
---|
1147 | * [proc1] Call loopback_timer_open() ->
|
---|
1148 | * Unlock cable->lock for snd_timer_close/open() call
|
---|
1149 | * [proc2] Call loopback_timer_open() -> snd_timer_open(),
|
---|
1150 | * snd_timer_start()
|
---|
1151 | * [proc1] Call snd_timer_open() and overwrite running timer
|
---|
1152 | * instance
|
---|
1153 | */
|
---|
1154 | err = snd_timer_open(timeri, &cable->snd_timer.id, current->pid);
|
---|
1155 | if (err < 0) {
|
---|
1156 | pcm_err(dpcm->substream->pcm,
|
---|
1157 | "snd_timer_open (%d,%d,%d) failed with %d",
|
---|
1158 | cable->snd_timer.id.card,
|
---|
1159 | cable->snd_timer.id.device,
|
---|
1160 | cable->snd_timer.id.subdevice,
|
---|
1161 | err);
|
---|
1162 | snd_timer_instance_free(timeri);
|
---|
1163 | goto exit;
|
---|
1164 | }
|
---|
1165 |
|
---|
1166 | cable->snd_timer.instance = timeri;
|
---|
1167 |
|
---|
1168 | exit:
|
---|
1169 | return err;
|
---|
1170 | }
|
---|
1171 |
|
---|
1172 | /* stop_sync() is not required for sound timer because it does not need to be
|
---|
1173 | * restarted in loopback_prepare() on Xrun recovery
|
---|
1174 | */
|
---|
1175 | static struct loopback_ops loopback_snd_timer_ops = {
|
---|
1176 | .open = loopback_snd_timer_open,
|
---|
1177 | .start = loopback_snd_timer_start,
|
---|
1178 | .stop = loopback_snd_timer_stop,
|
---|
1179 | .close_cable = loopback_snd_timer_close_cable,
|
---|
1180 | .dpcm_info = loopback_snd_timer_dpcm_info,
|
---|
1181 | };
|
---|
1182 |
|
---|
1183 | static int loopback_open(struct snd_pcm_substream *substream)
|
---|
1184 | {
|
---|
1185 | struct snd_pcm_runtime *runtime = substream->runtime;
|
---|
1186 | struct loopback *loopback = substream->private_data;
|
---|
1187 | struct loopback_pcm *dpcm;
|
---|
1188 | struct loopback_cable *cable = NULL;
|
---|
1189 | int err = 0;
|
---|
1190 | int dev = get_cable_index(substream);
|
---|
1191 |
|
---|
1192 | mutex_lock(&loopback->cable_lock);
|
---|
1193 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
|
---|
1194 | if (!dpcm) {
|
---|
1195 | err = -ENOMEM;
|
---|
1196 | goto unlock;
|
---|
1197 | }
|
---|
1198 | dpcm->loopback = loopback;
|
---|
1199 | dpcm->substream = substream;
|
---|
1200 |
|
---|
1201 | cable = loopback->cables[substream->number][dev];
|
---|
1202 | if (!cable) {
|
---|
1203 | cable = kzalloc(sizeof(*cable), GFP_KERNEL);
|
---|
1204 | if (!cable) {
|
---|
1205 | err = -ENOMEM;
|
---|
1206 | goto unlock;
|
---|
1207 | }
|
---|
1208 | spin_lock_init(&cable->lock);
|
---|
1209 | cable->hw = loopback_pcm_hardware;
|
---|
1210 | if (loopback->timer_source)
|
---|
1211 | cable->ops = &loopback_snd_timer_ops;
|
---|
1212 | else
|
---|
1213 | cable->ops = &loopback_jiffies_timer_ops;
|
---|
1214 | loopback->cables[substream->number][dev] = cable;
|
---|
1215 | }
|
---|
1216 | dpcm->cable = cable;
|
---|
1217 | runtime->private_data = dpcm;
|
---|
1218 |
|
---|
1219 | if (cable->ops->open) {
|
---|
1220 | err = cable->ops->open(dpcm);
|
---|
1221 | if (err < 0)
|
---|
1222 | goto unlock;
|
---|
1223 | }
|
---|
1224 |
|
---|
1225 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
---|
1226 |
|
---|
1227 | /* use dynamic rules based on actual runtime->hw values */
|
---|
1228 | /* note that the default rules created in the PCM midlevel code */
|
---|
1229 | /* are cached -> they do not reflect the actual state */
|
---|
1230 | err = snd_pcm_hw_rule_add(runtime, 0,
|
---|
1231 | SNDRV_PCM_HW_PARAM_FORMAT,
|
---|
1232 | rule_format, dpcm,
|
---|
1233 | SNDRV_PCM_HW_PARAM_FORMAT, -1);
|
---|
1234 | if (err < 0)
|
---|
1235 | goto unlock;
|
---|
1236 | err = snd_pcm_hw_rule_add(runtime, 0,
|
---|
1237 | SNDRV_PCM_HW_PARAM_RATE,
|
---|
1238 | rule_rate, dpcm,
|
---|
1239 | SNDRV_PCM_HW_PARAM_RATE, -1);
|
---|
1240 | if (err < 0)
|
---|
1241 | goto unlock;
|
---|
1242 | err = snd_pcm_hw_rule_add(runtime, 0,
|
---|
1243 | SNDRV_PCM_HW_PARAM_CHANNELS,
|
---|
1244 | rule_channels, dpcm,
|
---|
1245 | SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
---|
1246 | if (err < 0)
|
---|
1247 | goto unlock;
|
---|
1248 |
|
---|
1249 | /* In case of sound timer the period time of both devices of the same
|
---|
1250 | * loop has to be the same.
|
---|
1251 | * This rule only takes effect if a sound timer was chosen
|
---|
1252 | */
|
---|
1253 | if (cable->snd_timer.instance) {
|
---|
1254 | err = snd_pcm_hw_rule_add(runtime, 0,
|
---|
1255 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
---|
1256 | rule_period_bytes, dpcm,
|
---|
1257 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1);
|
---|
1258 | if (err < 0)
|
---|
1259 | goto unlock;
|
---|
1260 | }
|
---|
1261 |
|
---|
1262 | /* loopback_runtime_free() has not to be called if kfree(dpcm) was
|
---|
1263 | * already called here. Otherwise it will end up with a double free.
|
---|
1264 | */
|
---|
1265 | runtime->private_free = loopback_runtime_free;
|
---|
1266 | if (get_notify(dpcm))
|
---|
1267 | runtime->hw = loopback_pcm_hardware;
|
---|
1268 | else
|
---|
1269 | runtime->hw = cable->hw;
|
---|
1270 |
|
---|
1271 | spin_lock_irq(&cable->lock);
|
---|
1272 | cable->streams[substream->stream] = dpcm;
|
---|
1273 | spin_unlock_irq(&cable->lock);
|
---|
1274 |
|
---|
1275 | unlock:
|
---|
1276 | if (err < 0) {
|
---|
1277 | free_cable(substream);
|
---|
1278 | kfree(dpcm);
|
---|
1279 | }
|
---|
1280 | mutex_unlock(&loopback->cable_lock);
|
---|
1281 | return err;
|
---|
1282 | }
|
---|
1283 |
|
---|
1284 | static int loopback_close(struct snd_pcm_substream *substream)
|
---|
1285 | {
|
---|
1286 | struct loopback *loopback = substream->private_data;
|
---|
1287 | struct loopback_pcm *dpcm = substream->runtime->private_data;
|
---|
1288 | int err = 0;
|
---|
1289 |
|
---|
1290 | if (dpcm->cable->ops->close_substream)
|
---|
1291 | err = dpcm->cable->ops->close_substream(dpcm);
|
---|
1292 | mutex_lock(&loopback->cable_lock);
|
---|
1293 | free_cable(substream);
|
---|
1294 | mutex_unlock(&loopback->cable_lock);
|
---|
1295 | return err;
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | static const struct snd_pcm_ops loopback_pcm_ops = {
|
---|
1299 | .open = loopback_open,
|
---|
1300 | .close = loopback_close,
|
---|
1301 | .hw_free = loopback_hw_free,
|
---|
1302 | .prepare = loopback_prepare,
|
---|
1303 | .trigger = loopback_trigger,
|
---|
1304 | .pointer = loopback_pointer,
|
---|
1305 | };
|
---|
1306 |
|
---|
1307 | static int loopback_pcm_new(struct loopback *loopback,
|
---|
1308 | int device, int substreams)
|
---|
1309 | {
|
---|
1310 | struct snd_pcm *pcm;
|
---|
1311 | int err;
|
---|
1312 |
|
---|
1313 | err = snd_pcm_new(loopback->card, "Loopback PCM", device,
|
---|
1314 | substreams, substreams, &pcm);
|
---|
1315 | if (err < 0)
|
---|
1316 | return err;
|
---|
1317 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops);
|
---|
1318 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops);
|
---|
1319 | snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
|
---|
1320 |
|
---|
1321 | pcm->private_data = loopback;
|
---|
1322 | pcm->info_flags = 0;
|
---|
1323 | strcpy(pcm->name, "Loopback PCM");
|
---|
1324 |
|
---|
1325 | loopback->pcm[device] = pcm;
|
---|
1326 | return 0;
|
---|
1327 | }
|
---|
1328 |
|
---|
1329 | static int loopback_rate_shift_info(struct snd_kcontrol *kcontrol,
|
---|
1330 | struct snd_ctl_elem_info *uinfo)
|
---|
1331 | {
|
---|
1332 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
1333 | uinfo->count = 1;
|
---|
1334 | uinfo->value.integer.min = 80000;
|
---|
1335 | uinfo->value.integer.max = 120000;
|
---|
1336 | uinfo->value.integer.step = 1;
|
---|
1337 | return 0;
|
---|
1338 | }
|
---|
1339 |
|
---|
1340 | static int loopback_rate_shift_get(struct snd_kcontrol *kcontrol,
|
---|
1341 | struct snd_ctl_elem_value *ucontrol)
|
---|
1342 | {
|
---|
1343 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1344 |
|
---|
1345 | mutex_lock(&loopback->cable_lock);
|
---|
1346 | ucontrol->value.integer.value[0] =
|
---|
1347 | loopback->setup[kcontrol->id.subdevice]
|
---|
1348 | [kcontrol->id.device].rate_shift;
|
---|
1349 | mutex_unlock(&loopback->cable_lock);
|
---|
1350 | return 0;
|
---|
1351 | }
|
---|
1352 |
|
---|
1353 | static int loopback_rate_shift_put(struct snd_kcontrol *kcontrol,
|
---|
1354 | struct snd_ctl_elem_value *ucontrol)
|
---|
1355 | {
|
---|
1356 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1357 | unsigned int val;
|
---|
1358 | int change = 0;
|
---|
1359 |
|
---|
1360 | val = ucontrol->value.integer.value[0];
|
---|
1361 | if (val < 80000)
|
---|
1362 | val = 80000;
|
---|
1363 | if (val > 120000)
|
---|
1364 | val = 120000;
|
---|
1365 | mutex_lock(&loopback->cable_lock);
|
---|
1366 | if (val != loopback->setup[kcontrol->id.subdevice]
|
---|
1367 | [kcontrol->id.device].rate_shift) {
|
---|
1368 | loopback->setup[kcontrol->id.subdevice]
|
---|
1369 | [kcontrol->id.device].rate_shift = val;
|
---|
1370 | change = 1;
|
---|
1371 | }
|
---|
1372 | mutex_unlock(&loopback->cable_lock);
|
---|
1373 | return change;
|
---|
1374 | }
|
---|
1375 |
|
---|
1376 | static int loopback_notify_get(struct snd_kcontrol *kcontrol,
|
---|
1377 | struct snd_ctl_elem_value *ucontrol)
|
---|
1378 | {
|
---|
1379 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1380 |
|
---|
1381 | mutex_lock(&loopback->cable_lock);
|
---|
1382 | ucontrol->value.integer.value[0] =
|
---|
1383 | loopback->setup[kcontrol->id.subdevice]
|
---|
1384 | [kcontrol->id.device].notify;
|
---|
1385 | mutex_unlock(&loopback->cable_lock);
|
---|
1386 | return 0;
|
---|
1387 | }
|
---|
1388 |
|
---|
1389 | static int loopback_notify_put(struct snd_kcontrol *kcontrol,
|
---|
1390 | struct snd_ctl_elem_value *ucontrol)
|
---|
1391 | {
|
---|
1392 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1393 | unsigned int val;
|
---|
1394 | int change = 0;
|
---|
1395 |
|
---|
1396 | val = ucontrol->value.integer.value[0] ? 1 : 0;
|
---|
1397 | mutex_lock(&loopback->cable_lock);
|
---|
1398 | if (val != loopback->setup[kcontrol->id.subdevice]
|
---|
1399 | [kcontrol->id.device].notify) {
|
---|
1400 | loopback->setup[kcontrol->id.subdevice]
|
---|
1401 | [kcontrol->id.device].notify = val;
|
---|
1402 | change = 1;
|
---|
1403 | }
|
---|
1404 | mutex_unlock(&loopback->cable_lock);
|
---|
1405 | return change;
|
---|
1406 | }
|
---|
1407 |
|
---|
1408 | static int loopback_active_get(struct snd_kcontrol *kcontrol,
|
---|
1409 | struct snd_ctl_elem_value *ucontrol)
|
---|
1410 | {
|
---|
1411 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1412 | struct loopback_cable *cable;
|
---|
1413 |
|
---|
1414 | unsigned int val = 0;
|
---|
1415 |
|
---|
1416 | mutex_lock(&loopback->cable_lock);
|
---|
1417 | cable = loopback->cables[kcontrol->id.subdevice][kcontrol->id.device ^ 1];
|
---|
1418 | if (cable != NULL) {
|
---|
1419 | unsigned int running = cable->running ^ cable->pause;
|
---|
1420 |
|
---|
1421 | val = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? 1 : 0;
|
---|
1422 | }
|
---|
1423 | mutex_unlock(&loopback->cable_lock);
|
---|
1424 | ucontrol->value.integer.value[0] = val;
|
---|
1425 | return 0;
|
---|
1426 | }
|
---|
1427 |
|
---|
1428 | static int loopback_format_info(struct snd_kcontrol *kcontrol,
|
---|
1429 | struct snd_ctl_elem_info *uinfo)
|
---|
1430 | {
|
---|
1431 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
1432 | uinfo->count = 1;
|
---|
1433 | uinfo->value.integer.min = 0;
|
---|
1434 | uinfo->value.integer.max = (__force int)SNDRV_PCM_FORMAT_LAST;
|
---|
1435 | uinfo->value.integer.step = 1;
|
---|
1436 | return 0;
|
---|
1437 | }
|
---|
1438 |
|
---|
1439 | static int loopback_format_get(struct snd_kcontrol *kcontrol,
|
---|
1440 | struct snd_ctl_elem_value *ucontrol)
|
---|
1441 | {
|
---|
1442 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1443 |
|
---|
1444 | ucontrol->value.integer.value[0] =
|
---|
1445 | (__force int)loopback->setup[kcontrol->id.subdevice]
|
---|
1446 | [kcontrol->id.device].format;
|
---|
1447 | return 0;
|
---|
1448 | }
|
---|
1449 |
|
---|
1450 | static int loopback_rate_info(struct snd_kcontrol *kcontrol,
|
---|
1451 | struct snd_ctl_elem_info *uinfo)
|
---|
1452 | {
|
---|
1453 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
1454 | uinfo->count = 1;
|
---|
1455 | uinfo->value.integer.min = 0;
|
---|
1456 | uinfo->value.integer.max = 192000;
|
---|
1457 | uinfo->value.integer.step = 1;
|
---|
1458 | return 0;
|
---|
1459 | }
|
---|
1460 |
|
---|
1461 | static int loopback_rate_get(struct snd_kcontrol *kcontrol,
|
---|
1462 | struct snd_ctl_elem_value *ucontrol)
|
---|
1463 | {
|
---|
1464 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1465 |
|
---|
1466 | mutex_lock(&loopback->cable_lock);
|
---|
1467 | ucontrol->value.integer.value[0] =
|
---|
1468 | loopback->setup[kcontrol->id.subdevice]
|
---|
1469 | [kcontrol->id.device].rate;
|
---|
1470 | mutex_unlock(&loopback->cable_lock);
|
---|
1471 | return 0;
|
---|
1472 | }
|
---|
1473 |
|
---|
1474 | static int loopback_channels_info(struct snd_kcontrol *kcontrol,
|
---|
1475 | struct snd_ctl_elem_info *uinfo)
|
---|
1476 | {
|
---|
1477 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
---|
1478 | uinfo->count = 1;
|
---|
1479 | uinfo->value.integer.min = 1;
|
---|
1480 | uinfo->value.integer.max = 1024;
|
---|
1481 | uinfo->value.integer.step = 1;
|
---|
1482 | return 0;
|
---|
1483 | }
|
---|
1484 |
|
---|
1485 | static int loopback_channels_get(struct snd_kcontrol *kcontrol,
|
---|
1486 | struct snd_ctl_elem_value *ucontrol)
|
---|
1487 | {
|
---|
1488 | struct loopback *loopback = snd_kcontrol_chip(kcontrol);
|
---|
1489 |
|
---|
1490 | mutex_lock(&loopback->cable_lock);
|
---|
1491 | ucontrol->value.integer.value[0] =
|
---|
1492 | loopback->setup[kcontrol->id.subdevice]
|
---|
1493 | [kcontrol->id.device].channels;
|
---|
1494 | mutex_unlock(&loopback->cable_lock);
|
---|
1495 | return 0;
|
---|
1496 | }
|
---|
1497 |
|
---|
1498 | static const struct snd_kcontrol_new loopback_controls[] = {
|
---|
1499 | {
|
---|
1500 | .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
---|
1501 | .name = "PCM Rate Shift 100000",
|
---|
1502 | .info = loopback_rate_shift_info,
|
---|
1503 | .get = loopback_rate_shift_get,
|
---|
1504 | .put = loopback_rate_shift_put,
|
---|
1505 | },
|
---|
1506 | {
|
---|
1507 | .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
---|
1508 | .name = "PCM Notify",
|
---|
1509 | .info = snd_ctl_boolean_mono_info,
|
---|
1510 | .get = loopback_notify_get,
|
---|
1511 | .put = loopback_notify_put,
|
---|
1512 | },
|
---|
1513 | #define ACTIVE_IDX 2
|
---|
1514 | {
|
---|
1515 | .access = SNDRV_CTL_ELEM_ACCESS_READ,
|
---|
1516 | .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
---|
1517 | .name = "PCM Slave Active",
|
---|
1518 | .info = snd_ctl_boolean_mono_info,
|
---|
1519 | .get = loopback_active_get,
|
---|
1520 | },
|
---|
1521 | #define FORMAT_IDX 3
|
---|
1522 | {
|
---|
1523 | .access = SNDRV_CTL_ELEM_ACCESS_READ,
|
---|
1524 | .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
---|
1525 | .name = "PCM Slave Format",
|
---|
1526 | .info = loopback_format_info,
|
---|
1527 | .get = loopback_format_get
|
---|
1528 | },
|
---|
1529 | #define RATE_IDX 4
|
---|
1530 | {
|
---|
1531 | .access = SNDRV_CTL_ELEM_ACCESS_READ,
|
---|
1532 | .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
---|
1533 | .name = "PCM Slave Rate",
|
---|
1534 | .info = loopback_rate_info,
|
---|
1535 | .get = loopback_rate_get
|
---|
1536 | },
|
---|
1537 | #define CHANNELS_IDX 5
|
---|
1538 | {
|
---|
1539 | .access = SNDRV_CTL_ELEM_ACCESS_READ,
|
---|
1540 | .iface = SNDRV_CTL_ELEM_IFACE_PCM,
|
---|
1541 | .name = "PCM Slave Channels",
|
---|
1542 | .info = loopback_channels_info,
|
---|
1543 | .get = loopback_channels_get
|
---|
1544 | }
|
---|
1545 | };
|
---|
1546 |
|
---|
1547 | static int loopback_mixer_new(struct loopback *loopback, int notify)
|
---|
1548 | {
|
---|
1549 | struct snd_card *card = loopback->card;
|
---|
1550 | struct snd_pcm *pcm;
|
---|
1551 | struct snd_kcontrol *kctl;
|
---|
1552 | struct loopback_setup *setup;
|
---|
1553 | int err, dev, substr, substr_count, idx;
|
---|
1554 |
|
---|
1555 | strcpy(card->mixername, "Loopback Mixer");
|
---|
1556 | for (dev = 0; dev < 2; dev++) {
|
---|
1557 | pcm = loopback->pcm[dev];
|
---|
1558 | substr_count =
|
---|
1559 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count;
|
---|
1560 | for (substr = 0; substr < substr_count; substr++) {
|
---|
1561 | setup = &loopback->setup[substr][dev];
|
---|
1562 | setup->notify = notify;
|
---|
1563 | setup->rate_shift = NO_PITCH;
|
---|
1564 | setup->format = SNDRV_PCM_FORMAT_S16_LE;
|
---|
1565 | setup->rate = 48000;
|
---|
1566 | setup->channels = 2;
|
---|
1567 | for (idx = 0; idx < ARRAY_SIZE(loopback_controls);
|
---|
1568 | idx++) {
|
---|
1569 | kctl = snd_ctl_new1(&loopback_controls[idx],
|
---|
1570 | loopback);
|
---|
1571 | if (!kctl)
|
---|
1572 | return -ENOMEM;
|
---|
1573 | kctl->id.device = dev;
|
---|
1574 | kctl->id.subdevice = substr;
|
---|
1575 |
|
---|
1576 | /* Add the control before copying the id so that
|
---|
1577 | * the numid field of the id is set in the copy.
|
---|
1578 | */
|
---|
1579 | err = snd_ctl_add(card, kctl);
|
---|
1580 | if (err < 0)
|
---|
1581 | return err;
|
---|
1582 |
|
---|
1583 | switch (idx) {
|
---|
1584 | case ACTIVE_IDX:
|
---|
1585 | setup->active_id = kctl->id;
|
---|
1586 | break;
|
---|
1587 | case FORMAT_IDX:
|
---|
1588 | setup->format_id = kctl->id;
|
---|
1589 | break;
|
---|
1590 | case RATE_IDX:
|
---|
1591 | setup->rate_id = kctl->id;
|
---|
1592 | break;
|
---|
1593 | case CHANNELS_IDX:
|
---|
1594 | setup->channels_id = kctl->id;
|
---|
1595 | break;
|
---|
1596 | default:
|
---|
1597 | break;
|
---|
1598 | }
|
---|
1599 | }
|
---|
1600 | }
|
---|
1601 | }
|
---|
1602 | return 0;
|
---|
1603 | }
|
---|
1604 |
|
---|
1605 | static void print_dpcm_info(struct snd_info_buffer *buffer,
|
---|
1606 | struct loopback_pcm *dpcm,
|
---|
1607 | const char *id)
|
---|
1608 | {
|
---|
1609 | snd_iprintf(buffer, " %s\n", id);
|
---|
1610 | if (dpcm == NULL) {
|
---|
1611 | snd_iprintf(buffer, " inactive\n");
|
---|
1612 | return;
|
---|
1613 | }
|
---|
1614 | snd_iprintf(buffer, " buffer_size:\t%u\n", dpcm->pcm_buffer_size);
|
---|
1615 | snd_iprintf(buffer, " buffer_pos:\t\t%u\n", dpcm->buf_pos);
|
---|
1616 | snd_iprintf(buffer, " silent_size:\t%u\n", dpcm->silent_size);
|
---|
1617 | snd_iprintf(buffer, " period_size:\t%u\n", dpcm->pcm_period_size);
|
---|
1618 | snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps);
|
---|
1619 | snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign);
|
---|
1620 | snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift);
|
---|
1621 | if (dpcm->cable->ops->dpcm_info)
|
---|
1622 | dpcm->cable->ops->dpcm_info(dpcm, buffer);
|
---|
1623 | }
|
---|
1624 |
|
---|
1625 | static void print_substream_info(struct snd_info_buffer *buffer,
|
---|
1626 | struct loopback *loopback,
|
---|
1627 | int sub,
|
---|
1628 | int num)
|
---|
1629 | {
|
---|
1630 | struct loopback_cable *cable = loopback->cables[sub][num];
|
---|
1631 |
|
---|
1632 | snd_iprintf(buffer, "Cable %i substream %i:\n", num, sub);
|
---|
1633 | if (cable == NULL) {
|
---|
1634 | snd_iprintf(buffer, " inactive\n");
|
---|
1635 | return;
|
---|
1636 | }
|
---|
1637 | snd_iprintf(buffer, " valid: %u\n", cable->valid);
|
---|
1638 | snd_iprintf(buffer, " running: %u\n", cable->running);
|
---|
1639 | snd_iprintf(buffer, " pause: %u\n", cable->pause);
|
---|
1640 | print_dpcm_info(buffer, cable->streams[0], "Playback");
|
---|
1641 | print_dpcm_info(buffer, cable->streams[1], "Capture");
|
---|
1642 | }
|
---|
1643 |
|
---|
1644 | static void print_cable_info(struct snd_info_entry *entry,
|
---|
1645 | struct snd_info_buffer *buffer)
|
---|
1646 | {
|
---|
1647 | struct loopback *loopback = entry->private_data;
|
---|
1648 | int sub, num;
|
---|
1649 |
|
---|
1650 | mutex_lock(&loopback->cable_lock);
|
---|
1651 | num = entry->name[strlen(entry->name)-1];
|
---|
1652 | num = num == '0' ? 0 : 1;
|
---|
1653 | for (sub = 0; sub < MAX_PCM_SUBSTREAMS; sub++)
|
---|
1654 | print_substream_info(buffer, loopback, sub, num);
|
---|
1655 | mutex_unlock(&loopback->cable_lock);
|
---|
1656 | }
|
---|
1657 |
|
---|
1658 | static int loopback_cable_proc_new(struct loopback *loopback, int cidx)
|
---|
1659 | {
|
---|
1660 | char name[32];
|
---|
1661 |
|
---|
1662 | snprintf(name, sizeof(name), "cable#%d", cidx);
|
---|
1663 | return snd_card_ro_proc_new(loopback->card, name, loopback,
|
---|
1664 | print_cable_info);
|
---|
1665 | }
|
---|
1666 |
|
---|
1667 | static void loopback_set_timer_source(struct loopback *loopback,
|
---|
1668 | const char *value)
|
---|
1669 | {
|
---|
1670 | if (loopback->timer_source) {
|
---|
1671 | devm_kfree(loopback->card->dev, loopback->timer_source);
|
---|
1672 | loopback->timer_source = NULL;
|
---|
1673 | }
|
---|
1674 | if (value && *value)
|
---|
1675 | loopback->timer_source = devm_kstrdup(loopback->card->dev,
|
---|
1676 | value, GFP_KERNEL);
|
---|
1677 | }
|
---|
1678 |
|
---|
1679 | static void print_timer_source_info(struct snd_info_entry *entry,
|
---|
1680 | struct snd_info_buffer *buffer)
|
---|
1681 | {
|
---|
1682 | struct loopback *loopback = entry->private_data;
|
---|
1683 |
|
---|
1684 | mutex_lock(&loopback->cable_lock);
|
---|
1685 | snd_iprintf(buffer, "%s\n",
|
---|
1686 | loopback->timer_source ? loopback->timer_source : "");
|
---|
1687 | mutex_unlock(&loopback->cable_lock);
|
---|
1688 | }
|
---|
1689 |
|
---|
1690 | static void change_timer_source_info(struct snd_info_entry *entry,
|
---|
1691 | struct snd_info_buffer *buffer)
|
---|
1692 | {
|
---|
1693 | struct loopback *loopback = entry->private_data;
|
---|
1694 | char line[64];
|
---|
1695 |
|
---|
1696 | mutex_lock(&loopback->cable_lock);
|
---|
1697 | if (!snd_info_get_line(buffer, line, sizeof(line)))
|
---|
1698 | loopback_set_timer_source(loopback, strim(line));
|
---|
1699 | mutex_unlock(&loopback->cable_lock);
|
---|
1700 | }
|
---|
1701 |
|
---|
1702 | static int loopback_timer_source_proc_new(struct loopback *loopback)
|
---|
1703 | {
|
---|
1704 | return snd_card_rw_proc_new(loopback->card, "timer_source", loopback,
|
---|
1705 | print_timer_source_info,
|
---|
1706 | change_timer_source_info);
|
---|
1707 | }
|
---|
1708 |
|
---|
1709 | static int loopback_probe(struct platform_device *devptr)
|
---|
1710 | {
|
---|
1711 | struct snd_card *card;
|
---|
1712 | struct loopback *loopback;
|
---|
1713 | int dev = devptr->id;
|
---|
1714 | int err;
|
---|
1715 |
|
---|
1716 | err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
|
---|
1717 | sizeof(struct loopback), &card);
|
---|
1718 | if (err < 0)
|
---|
1719 | return err;
|
---|
1720 | loopback = card->private_data;
|
---|
1721 |
|
---|
1722 | if (pcm_substreams[dev] < 1)
|
---|
1723 | pcm_substreams[dev] = 1;
|
---|
1724 | if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
|
---|
1725 | pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
|
---|
1726 |
|
---|
1727 | loopback->card = card;
|
---|
1728 | loopback_set_timer_source(loopback, timer_source[dev]);
|
---|
1729 |
|
---|
1730 | mutex_init(&loopback->cable_lock);
|
---|
1731 |
|
---|
1732 | err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]);
|
---|
1733 | if (err < 0)
|
---|
1734 | goto __nodev;
|
---|
1735 | err = loopback_pcm_new(loopback, 1, pcm_substreams[dev]);
|
---|
1736 | if (err < 0)
|
---|
1737 | goto __nodev;
|
---|
1738 | err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0);
|
---|
1739 | if (err < 0)
|
---|
1740 | goto __nodev;
|
---|
1741 | loopback_cable_proc_new(loopback, 0);
|
---|
1742 | loopback_cable_proc_new(loopback, 1);
|
---|
1743 | loopback_timer_source_proc_new(loopback);
|
---|
1744 | strcpy(card->driver, "Loopback");
|
---|
1745 | strcpy(card->shortname, "Loopback");
|
---|
1746 | sprintf(card->longname, "Loopback %i", dev + 1);
|
---|
1747 | err = snd_card_register(card);
|
---|
1748 | if (!err) {
|
---|
1749 | platform_set_drvdata(devptr, card);
|
---|
1750 | return 0;
|
---|
1751 | }
|
---|
1752 | __nodev:
|
---|
1753 | snd_card_free(card);
|
---|
1754 | return err;
|
---|
1755 | }
|
---|
1756 |
|
---|
1757 | static int loopback_remove(struct platform_device *devptr)
|
---|
1758 | {
|
---|
1759 | snd_card_free(platform_get_drvdata(devptr));
|
---|
1760 | return 0;
|
---|
1761 | }
|
---|
1762 |
|
---|
1763 | #ifdef CONFIG_PM_SLEEP
|
---|
1764 | static int loopback_suspend(struct device *pdev)
|
---|
1765 | {
|
---|
1766 | struct snd_card *card = dev_get_drvdata(pdev);
|
---|
1767 |
|
---|
1768 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
|
---|
1769 | return 0;
|
---|
1770 | }
|
---|
1771 |
|
---|
1772 | static int loopback_resume(struct device *pdev)
|
---|
1773 | {
|
---|
1774 | struct snd_card *card = dev_get_drvdata(pdev);
|
---|
1775 |
|
---|
1776 | snd_power_change_state(card, SNDRV_CTL_POWER_D0);
|
---|
1777 | return 0;
|
---|
1778 | }
|
---|
1779 |
|
---|
1780 | static SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume);
|
---|
1781 | #define LOOPBACK_PM_OPS &loopback_pm
|
---|
1782 | #else
|
---|
1783 | #define LOOPBACK_PM_OPS NULL
|
---|
1784 | #endif
|
---|
1785 |
|
---|
1786 | #define SND_LOOPBACK_DRIVER "snd_aloop"
|
---|
1787 |
|
---|
1788 | static struct platform_driver loopback_driver = {
|
---|
1789 | .probe = loopback_probe,
|
---|
1790 | .remove = loopback_remove,
|
---|
1791 | .driver = {
|
---|
1792 | .name = SND_LOOPBACK_DRIVER,
|
---|
1793 | .pm = LOOPBACK_PM_OPS,
|
---|
1794 | },
|
---|
1795 | };
|
---|
1796 |
|
---|
1797 | static void loopback_unregister_all(void)
|
---|
1798 | {
|
---|
1799 | int i;
|
---|
1800 |
|
---|
1801 | for (i = 0; i < ARRAY_SIZE(devices); ++i)
|
---|
1802 | platform_device_unregister(devices[i]);
|
---|
1803 | platform_driver_unregister(&loopback_driver);
|
---|
1804 | }
|
---|
1805 |
|
---|
1806 | static int __init alsa_card_loopback_init(void)
|
---|
1807 | {
|
---|
1808 | int i, err, cards;
|
---|
1809 |
|
---|
1810 | err = platform_driver_register(&loopback_driver);
|
---|
1811 | if (err < 0)
|
---|
1812 | return err;
|
---|
1813 |
|
---|
1814 |
|
---|
1815 | cards = 0;
|
---|
1816 | for (i = 0; i < SNDRV_CARDS; i++) {
|
---|
1817 | struct platform_device *device;
|
---|
1818 | if (!enable[i])
|
---|
1819 | continue;
|
---|
1820 | device = platform_device_register_simple(SND_LOOPBACK_DRIVER,
|
---|
1821 | i, NULL, 0);
|
---|
1822 | if (IS_ERR(device))
|
---|
1823 | continue;
|
---|
1824 | if (!platform_get_drvdata(device)) {
|
---|
1825 | platform_device_unregister(device);
|
---|
1826 | continue;
|
---|
1827 | }
|
---|
1828 | devices[i] = device;
|
---|
1829 | cards++;
|
---|
1830 | }
|
---|
1831 | if (!cards) {
|
---|
1832 | #ifdef MODULE
|
---|
1833 | printk(KERN_ERR "aloop: No loopback enabled\n");
|
---|
1834 | #endif
|
---|
1835 | loopback_unregister_all();
|
---|
1836 | return -ENODEV;
|
---|
1837 | }
|
---|
1838 | return 0;
|
---|
1839 | }
|
---|
1840 |
|
---|
1841 | static void __exit alsa_card_loopback_exit(void)
|
---|
1842 | {
|
---|
1843 | loopback_unregister_all();
|
---|
1844 | }
|
---|
1845 |
|
---|
1846 | module_init(alsa_card_loopback_init)
|
---|
1847 | module_exit(alsa_card_loopback_exit)
|
---|