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