.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Loopback soundcard |
---|
3 | 4 | * |
---|
.. | .. |
---|
12 | 13 | * |
---|
13 | 14 | * A next major update in 2010 (separate timers for playback and capture): |
---|
14 | 15 | * Copyright (c) Jaroslav Kysela <perex@perex.cz> |
---|
15 | | - * |
---|
16 | | - * This program is free software; you can redistribute it and/or modify |
---|
17 | | - * it under the terms of the GNU General Public License as published by |
---|
18 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
19 | | - * (at your option) any later version. |
---|
20 | | - * |
---|
21 | | - * This program is distributed in the hope that it will be useful, |
---|
22 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
23 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
24 | | - * GNU General Public License for more details. |
---|
25 | | - * |
---|
26 | | - * You should have received a copy of the GNU General Public License |
---|
27 | | - * along with this program; if not, write to the Free Software |
---|
28 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
29 | | - * |
---|
30 | 16 | */ |
---|
31 | 17 | |
---|
32 | 18 | #include <linux/init.h> |
---|
.. | .. |
---|
42 | 28 | #include <sound/pcm_params.h> |
---|
43 | 29 | #include <sound/info.h> |
---|
44 | 30 | #include <sound/initval.h> |
---|
| 31 | +#include <sound/timer.h> |
---|
45 | 32 | |
---|
46 | 33 | MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); |
---|
47 | 34 | MODULE_DESCRIPTION("A loopback soundcard"); |
---|
.. | .. |
---|
56 | 43 | static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; |
---|
57 | 44 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; |
---|
58 | 45 | static int pcm_notify[SNDRV_CARDS]; |
---|
| 46 | +static char *timer_source[SNDRV_CARDS]; |
---|
59 | 47 | |
---|
60 | 48 | module_param(use_raw_jiffies, bool, 0444); |
---|
61 | 49 | MODULE_PARM_DESC(use_raw_jiffies, "Use raw jiffies follows local clocks."); |
---|
.. | .. |
---|
69 | 57 | MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-8) for loopback driver."); |
---|
70 | 58 | module_param_array(pcm_notify, int, NULL, 0444); |
---|
71 | 59 | MODULE_PARM_DESC(pcm_notify, "Break capture when PCM format/rate/channels changes."); |
---|
| 60 | +module_param_array(timer_source, charp, NULL, 0444); |
---|
| 61 | +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]."); |
---|
72 | 62 | |
---|
73 | 63 | #define NO_PITCH 100000 |
---|
74 | 64 | |
---|
| 65 | +#define CABLE_VALID_PLAYBACK BIT(SNDRV_PCM_STREAM_PLAYBACK) |
---|
| 66 | +#define CABLE_VALID_CAPTURE BIT(SNDRV_PCM_STREAM_CAPTURE) |
---|
| 67 | +#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK | CABLE_VALID_CAPTURE) |
---|
| 68 | + |
---|
| 69 | +struct loopback_cable; |
---|
75 | 70 | struct loopback_pcm; |
---|
| 71 | + |
---|
| 72 | +struct loopback_ops { |
---|
| 73 | + /* optional |
---|
| 74 | + * call in loopback->cable_lock |
---|
| 75 | + */ |
---|
| 76 | + int (*open)(struct loopback_pcm *dpcm); |
---|
| 77 | + /* required |
---|
| 78 | + * call in cable->lock |
---|
| 79 | + */ |
---|
| 80 | + int (*start)(struct loopback_pcm *dpcm); |
---|
| 81 | + /* required |
---|
| 82 | + * call in cable->lock |
---|
| 83 | + */ |
---|
| 84 | + int (*stop)(struct loopback_pcm *dpcm); |
---|
| 85 | + /* optional */ |
---|
| 86 | + int (*stop_sync)(struct loopback_pcm *dpcm); |
---|
| 87 | + /* optional */ |
---|
| 88 | + int (*close_substream)(struct loopback_pcm *dpcm); |
---|
| 89 | + /* optional |
---|
| 90 | + * call in loopback->cable_lock |
---|
| 91 | + */ |
---|
| 92 | + int (*close_cable)(struct loopback_pcm *dpcm); |
---|
| 93 | + /* optional |
---|
| 94 | + * call in cable->lock |
---|
| 95 | + */ |
---|
| 96 | + unsigned int (*pos_update)(struct loopback_cable *cable); |
---|
| 97 | + /* optional */ |
---|
| 98 | + void (*dpcm_info)(struct loopback_pcm *dpcm, |
---|
| 99 | + struct snd_info_buffer *buffer); |
---|
| 100 | +}; |
---|
76 | 101 | |
---|
77 | 102 | struct loopback_cable { |
---|
78 | 103 | spinlock_t lock; |
---|
.. | .. |
---|
82 | 107 | unsigned int valid; |
---|
83 | 108 | unsigned int running; |
---|
84 | 109 | unsigned int pause; |
---|
| 110 | + /* timer specific */ |
---|
| 111 | + struct loopback_ops *ops; |
---|
| 112 | + /* If sound timer is used */ |
---|
| 113 | + struct { |
---|
| 114 | + int stream; |
---|
| 115 | + struct snd_timer_id id; |
---|
| 116 | + struct work_struct event_work; |
---|
| 117 | + struct snd_timer_instance *instance; |
---|
| 118 | + } snd_timer; |
---|
85 | 119 | }; |
---|
86 | 120 | |
---|
87 | 121 | struct loopback_setup { |
---|
88 | 122 | unsigned int notify: 1; |
---|
89 | 123 | unsigned int rate_shift; |
---|
90 | | - unsigned int format; |
---|
| 124 | + snd_pcm_format_t format; |
---|
91 | 125 | unsigned int rate; |
---|
92 | 126 | unsigned int channels; |
---|
93 | 127 | struct snd_ctl_elem_id active_id; |
---|
.. | .. |
---|
102 | 136 | struct loopback_cable *cables[MAX_PCM_SUBSTREAMS][2]; |
---|
103 | 137 | struct snd_pcm *pcm[2]; |
---|
104 | 138 | struct loopback_setup setup[MAX_PCM_SUBSTREAMS][2]; |
---|
| 139 | + const char *timer_source; |
---|
105 | 140 | }; |
---|
106 | 141 | |
---|
107 | 142 | struct loopback_pcm { |
---|
.. | .. |
---|
119 | 154 | /* flags */ |
---|
120 | 155 | unsigned int period_update_pending :1; |
---|
121 | 156 | /* timer stuff */ |
---|
122 | | - unsigned int irq_pos; /* fractional IRQ position */ |
---|
123 | | - unsigned int period_size_frac; |
---|
| 157 | + unsigned int irq_pos; /* fractional IRQ position in jiffies |
---|
| 158 | + * ticks |
---|
| 159 | + */ |
---|
| 160 | + unsigned int period_size_frac; /* period size in jiffies ticks */ |
---|
124 | 161 | unsigned int last_drift; |
---|
125 | 162 | unsigned long last_jiffies; |
---|
| 163 | + /* If jiffies timer is used */ |
---|
126 | 164 | struct timer_list timer; |
---|
127 | 165 | }; |
---|
128 | 166 | |
---|
.. | .. |
---|
132 | 170 | { |
---|
133 | 171 | struct timespec64 ts64; |
---|
134 | 172 | |
---|
135 | | - getrawmonotonic64(&ts64); |
---|
| 173 | + ktime_get_raw_ts64(&ts64); |
---|
136 | 174 | return timespec64_to_jiffies(&ts64); |
---|
137 | 175 | } |
---|
138 | 176 | |
---|
.. | .. |
---|
186 | 224 | } |
---|
187 | 225 | |
---|
188 | 226 | /* call in cable->lock */ |
---|
189 | | -static void loopback_timer_start(struct loopback_pcm *dpcm) |
---|
| 227 | +static int loopback_jiffies_timer_start(struct loopback_pcm *dpcm) |
---|
190 | 228 | { |
---|
191 | 229 | unsigned long tick; |
---|
192 | 230 | unsigned int rate_shift = get_rate_shift(dpcm); |
---|
.. | .. |
---|
202 | 240 | tick = dpcm->period_size_frac - dpcm->irq_pos; |
---|
203 | 241 | tick = (tick + dpcm->pcm_bps - 1) / dpcm->pcm_bps; |
---|
204 | 242 | mod_timer(&dpcm->timer, jiffies + tick); |
---|
| 243 | + |
---|
| 244 | + return 0; |
---|
205 | 245 | } |
---|
206 | 246 | |
---|
207 | 247 | /* call in cable->lock */ |
---|
208 | | -static inline void loopback_timer_stop(struct loopback_pcm *dpcm) |
---|
| 248 | +static int loopback_snd_timer_start(struct loopback_pcm *dpcm) |
---|
| 249 | +{ |
---|
| 250 | + struct loopback_cable *cable = dpcm->cable; |
---|
| 251 | + int err; |
---|
| 252 | + |
---|
| 253 | + /* Loopback device has to use same period as timer card. Therefore |
---|
| 254 | + * wake up for each snd_pcm_period_elapsed() call of timer card. |
---|
| 255 | + */ |
---|
| 256 | + err = snd_timer_start(cable->snd_timer.instance, 1); |
---|
| 257 | + if (err < 0) { |
---|
| 258 | + /* do not report error if trying to start but already |
---|
| 259 | + * running. For example called by opposite substream |
---|
| 260 | + * of the same cable |
---|
| 261 | + */ |
---|
| 262 | + if (err == -EBUSY) |
---|
| 263 | + return 0; |
---|
| 264 | + |
---|
| 265 | + pcm_err(dpcm->substream->pcm, |
---|
| 266 | + "snd_timer_start(%d,%d,%d) failed with %d", |
---|
| 267 | + cable->snd_timer.id.card, |
---|
| 268 | + cable->snd_timer.id.device, |
---|
| 269 | + cable->snd_timer.id.subdevice, |
---|
| 270 | + err); |
---|
| 271 | + } |
---|
| 272 | + |
---|
| 273 | + return err; |
---|
| 274 | +} |
---|
| 275 | + |
---|
| 276 | +/* call in cable->lock */ |
---|
| 277 | +static inline int loopback_jiffies_timer_stop(struct loopback_pcm *dpcm) |
---|
209 | 278 | { |
---|
210 | 279 | del_timer(&dpcm->timer); |
---|
211 | 280 | dpcm->timer.expires = 0; |
---|
| 281 | + |
---|
| 282 | + return 0; |
---|
212 | 283 | } |
---|
213 | 284 | |
---|
214 | | -static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm) |
---|
| 285 | +/* call in cable->lock */ |
---|
| 286 | +static int loopback_snd_timer_stop(struct loopback_pcm *dpcm) |
---|
| 287 | +{ |
---|
| 288 | + struct loopback_cable *cable = dpcm->cable; |
---|
| 289 | + int err; |
---|
| 290 | + |
---|
| 291 | + /* only stop if both devices (playback and capture) are not running */ |
---|
| 292 | + if (cable->running ^ cable->pause) |
---|
| 293 | + return 0; |
---|
| 294 | + |
---|
| 295 | + err = snd_timer_stop(cable->snd_timer.instance); |
---|
| 296 | + if (err < 0) { |
---|
| 297 | + pcm_err(dpcm->substream->pcm, |
---|
| 298 | + "snd_timer_stop(%d,%d,%d) failed with %d", |
---|
| 299 | + cable->snd_timer.id.card, |
---|
| 300 | + cable->snd_timer.id.device, |
---|
| 301 | + cable->snd_timer.id.subdevice, |
---|
| 302 | + err); |
---|
| 303 | + } |
---|
| 304 | + |
---|
| 305 | + return err; |
---|
| 306 | +} |
---|
| 307 | + |
---|
| 308 | +static inline int loopback_jiffies_timer_stop_sync(struct loopback_pcm *dpcm) |
---|
215 | 309 | { |
---|
216 | 310 | del_timer_sync(&dpcm->timer); |
---|
| 311 | + |
---|
| 312 | + return 0; |
---|
217 | 313 | } |
---|
218 | 314 | |
---|
219 | | -#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) |
---|
220 | | -#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) |
---|
221 | | -#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) |
---|
| 315 | +/* call in loopback->cable_lock */ |
---|
| 316 | +static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm) |
---|
| 317 | +{ |
---|
| 318 | + struct loopback_cable *cable = dpcm->cable; |
---|
| 319 | + |
---|
| 320 | + /* snd_timer was not opened */ |
---|
| 321 | + if (!cable->snd_timer.instance) |
---|
| 322 | + return 0; |
---|
| 323 | + |
---|
| 324 | + /* will only be called from free_cable() when other stream was |
---|
| 325 | + * already closed. Other stream cannot be reopened as long as |
---|
| 326 | + * loopback->cable_lock is locked. Therefore no need to lock |
---|
| 327 | + * cable->lock; |
---|
| 328 | + */ |
---|
| 329 | + snd_timer_close(cable->snd_timer.instance); |
---|
| 330 | + |
---|
| 331 | + /* wait till drain work has finished if requested */ |
---|
| 332 | + cancel_work_sync(&cable->snd_timer.event_work); |
---|
| 333 | + |
---|
| 334 | + snd_timer_instance_free(cable->snd_timer.instance); |
---|
| 335 | + memset(&cable->snd_timer, 0, sizeof(cable->snd_timer)); |
---|
| 336 | + |
---|
| 337 | + return 0; |
---|
| 338 | +} |
---|
222 | 339 | |
---|
223 | 340 | static int loopback_check_format(struct loopback_cable *cable, int stream) |
---|
224 | 341 | { |
---|
.. | .. |
---|
282 | 399 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
283 | 400 | struct loopback_pcm *dpcm = runtime->private_data; |
---|
284 | 401 | struct loopback_cable *cable = dpcm->cable; |
---|
285 | | - int err, stream = 1 << substream->stream; |
---|
| 402 | + int err = 0, stream = 1 << substream->stream; |
---|
286 | 403 | |
---|
287 | 404 | switch (cmd) { |
---|
288 | 405 | case SNDRV_PCM_TRIGGER_START: |
---|
.. | .. |
---|
295 | 412 | spin_lock(&cable->lock); |
---|
296 | 413 | cable->running |= stream; |
---|
297 | 414 | cable->pause &= ~stream; |
---|
298 | | - loopback_timer_start(dpcm); |
---|
| 415 | + err = cable->ops->start(dpcm); |
---|
299 | 416 | spin_unlock(&cable->lock); |
---|
300 | 417 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
301 | 418 | loopback_active_notify(dpcm); |
---|
.. | .. |
---|
304 | 421 | spin_lock(&cable->lock); |
---|
305 | 422 | cable->running &= ~stream; |
---|
306 | 423 | cable->pause &= ~stream; |
---|
307 | | - loopback_timer_stop(dpcm); |
---|
| 424 | + err = cable->ops->stop(dpcm); |
---|
308 | 425 | spin_unlock(&cable->lock); |
---|
309 | 426 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
310 | 427 | loopback_active_notify(dpcm); |
---|
.. | .. |
---|
313 | 430 | case SNDRV_PCM_TRIGGER_SUSPEND: |
---|
314 | 431 | spin_lock(&cable->lock); |
---|
315 | 432 | cable->pause |= stream; |
---|
316 | | - loopback_timer_stop(dpcm); |
---|
| 433 | + err = cable->ops->stop(dpcm); |
---|
317 | 434 | spin_unlock(&cable->lock); |
---|
318 | 435 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
319 | 436 | loopback_active_notify(dpcm); |
---|
.. | .. |
---|
323 | 440 | spin_lock(&cable->lock); |
---|
324 | 441 | dpcm->last_jiffies = cycles_to_jiffies(); |
---|
325 | 442 | cable->pause &= ~stream; |
---|
326 | | - loopback_timer_start(dpcm); |
---|
| 443 | + err = cable->ops->start(dpcm); |
---|
327 | 444 | spin_unlock(&cable->lock); |
---|
328 | 445 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
329 | 446 | loopback_active_notify(dpcm); |
---|
.. | .. |
---|
331 | 448 | default: |
---|
332 | 449 | return -EINVAL; |
---|
333 | 450 | } |
---|
334 | | - return 0; |
---|
| 451 | + return err; |
---|
335 | 452 | } |
---|
336 | 453 | |
---|
337 | 454 | static void params_change(struct snd_pcm_substream *substream) |
---|
.. | .. |
---|
345 | 462 | cable->hw.rate_max = runtime->rate; |
---|
346 | 463 | cable->hw.channels_min = runtime->channels; |
---|
347 | 464 | cable->hw.channels_max = runtime->channels; |
---|
| 465 | + |
---|
| 466 | + if (cable->snd_timer.instance) { |
---|
| 467 | + cable->hw.period_bytes_min = |
---|
| 468 | + frames_to_bytes(runtime, runtime->period_size); |
---|
| 469 | + cable->hw.period_bytes_max = cable->hw.period_bytes_min; |
---|
| 470 | + } |
---|
| 471 | + |
---|
348 | 472 | } |
---|
349 | 473 | |
---|
350 | 474 | static int loopback_prepare(struct snd_pcm_substream *substream) |
---|
.. | .. |
---|
352 | 476 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
353 | 477 | struct loopback_pcm *dpcm = runtime->private_data; |
---|
354 | 478 | struct loopback_cable *cable = dpcm->cable; |
---|
355 | | - int bps, salign; |
---|
| 479 | + int err, bps, salign; |
---|
356 | 480 | |
---|
357 | | - loopback_timer_stop_sync(dpcm); |
---|
| 481 | + if (cable->ops->stop_sync) { |
---|
| 482 | + err = cable->ops->stop_sync(dpcm); |
---|
| 483 | + if (err < 0) |
---|
| 484 | + return err; |
---|
| 485 | + } |
---|
358 | 486 | |
---|
359 | | - salign = (snd_pcm_format_width(runtime->format) * |
---|
| 487 | + salign = (snd_pcm_format_physical_width(runtime->format) * |
---|
360 | 488 | runtime->channels) / 8; |
---|
361 | 489 | bps = salign * runtime->rate; |
---|
362 | 490 | if (bps <= 0 || salign <= 0) |
---|
.. | .. |
---|
490 | 618 | } |
---|
491 | 619 | |
---|
492 | 620 | /* call in cable->lock */ |
---|
493 | | -static unsigned int loopback_pos_update(struct loopback_cable *cable) |
---|
| 621 | +static unsigned int loopback_jiffies_timer_pos_update |
---|
| 622 | + (struct loopback_cable *cable) |
---|
494 | 623 | { |
---|
495 | 624 | struct loopback_pcm *dpcm_play = |
---|
496 | 625 | cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
---|
497 | 626 | struct loopback_pcm *dpcm_capt = |
---|
498 | 627 | cable->streams[SNDRV_PCM_STREAM_CAPTURE]; |
---|
499 | | - unsigned long delta_play = 0, delta_capt = 0; |
---|
| 628 | + unsigned long delta_play = 0, delta_capt = 0, cur_jiffies; |
---|
500 | 629 | unsigned int running, count1, count2; |
---|
501 | | - unsigned long cur_jiffies = cycles_to_jiffies(); |
---|
502 | 630 | |
---|
| 631 | + cur_jiffies = cycles_to_jiffies(); |
---|
503 | 632 | running = cable->running ^ cable->pause; |
---|
504 | 633 | if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { |
---|
505 | 634 | delta_play = cur_jiffies - dpcm_play->last_jiffies; |
---|
.. | .. |
---|
544 | 673 | return running; |
---|
545 | 674 | } |
---|
546 | 675 | |
---|
547 | | -static void loopback_timer_function(struct timer_list *t) |
---|
| 676 | +static void loopback_jiffies_timer_function(struct timer_list *t) |
---|
548 | 677 | { |
---|
549 | 678 | struct loopback_pcm *dpcm = from_timer(dpcm, t, timer); |
---|
550 | 679 | unsigned long flags; |
---|
551 | 680 | |
---|
552 | 681 | spin_lock_irqsave(&dpcm->cable->lock, flags); |
---|
553 | | - if (loopback_pos_update(dpcm->cable) & (1 << dpcm->substream->stream)) { |
---|
554 | | - loopback_timer_start(dpcm); |
---|
| 682 | + if (loopback_jiffies_timer_pos_update(dpcm->cable) & |
---|
| 683 | + (1 << dpcm->substream->stream)) { |
---|
| 684 | + loopback_jiffies_timer_start(dpcm); |
---|
555 | 685 | if (dpcm->period_update_pending) { |
---|
556 | 686 | dpcm->period_update_pending = 0; |
---|
557 | 687 | spin_unlock_irqrestore(&dpcm->cable->lock, flags); |
---|
.. | .. |
---|
563 | 693 | spin_unlock_irqrestore(&dpcm->cable->lock, flags); |
---|
564 | 694 | } |
---|
565 | 695 | |
---|
| 696 | +/* call in cable->lock */ |
---|
| 697 | +static int loopback_snd_timer_check_resolution(struct snd_pcm_runtime *runtime, |
---|
| 698 | + unsigned long resolution) |
---|
| 699 | +{ |
---|
| 700 | + if (resolution != runtime->timer_resolution) { |
---|
| 701 | + struct loopback_pcm *dpcm = runtime->private_data; |
---|
| 702 | + struct loopback_cable *cable = dpcm->cable; |
---|
| 703 | + /* Worst case estimation of possible values for resolution |
---|
| 704 | + * resolution <= (512 * 1024) frames / 8kHz in nsec |
---|
| 705 | + * resolution <= 65.536.000.000 nsec |
---|
| 706 | + * |
---|
| 707 | + * period_size <= 65.536.000.000 nsec / 1000nsec/usec * 192kHz + |
---|
| 708 | + * 500.000 |
---|
| 709 | + * period_size <= 12.582.912.000.000 <64bit |
---|
| 710 | + * / 1.000.000 usec/sec |
---|
| 711 | + */ |
---|
| 712 | + snd_pcm_uframes_t period_size_usec = |
---|
| 713 | + resolution / 1000 * runtime->rate; |
---|
| 714 | + /* round to nearest sample rate */ |
---|
| 715 | + snd_pcm_uframes_t period_size = |
---|
| 716 | + (period_size_usec + 500 * 1000) / (1000 * 1000); |
---|
| 717 | + |
---|
| 718 | + pcm_err(dpcm->substream->pcm, |
---|
| 719 | + "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.", |
---|
| 720 | + runtime->period_size, resolution, period_size, |
---|
| 721 | + cable->snd_timer.id.card, |
---|
| 722 | + cable->snd_timer.id.device, |
---|
| 723 | + cable->snd_timer.id.subdevice, |
---|
| 724 | + period_size); |
---|
| 725 | + return -EINVAL; |
---|
| 726 | + } |
---|
| 727 | + return 0; |
---|
| 728 | +} |
---|
| 729 | + |
---|
| 730 | +static void loopback_snd_timer_period_elapsed(struct loopback_cable *cable, |
---|
| 731 | + int event, |
---|
| 732 | + unsigned long resolution) |
---|
| 733 | +{ |
---|
| 734 | + struct loopback_pcm *dpcm_play, *dpcm_capt; |
---|
| 735 | + struct snd_pcm_substream *substream_play, *substream_capt; |
---|
| 736 | + struct snd_pcm_runtime *valid_runtime; |
---|
| 737 | + unsigned int running, elapsed_bytes; |
---|
| 738 | + unsigned long flags; |
---|
| 739 | + |
---|
| 740 | + spin_lock_irqsave(&cable->lock, flags); |
---|
| 741 | + running = cable->running ^ cable->pause; |
---|
| 742 | + /* no need to do anything if no stream is running */ |
---|
| 743 | + if (!running) { |
---|
| 744 | + spin_unlock_irqrestore(&cable->lock, flags); |
---|
| 745 | + return; |
---|
| 746 | + } |
---|
| 747 | + |
---|
| 748 | + dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; |
---|
| 749 | + dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; |
---|
| 750 | + |
---|
| 751 | + if (event == SNDRV_TIMER_EVENT_MSTOP) { |
---|
| 752 | + if (!dpcm_play || |
---|
| 753 | + dpcm_play->substream->runtime->status->state != |
---|
| 754 | + SNDRV_PCM_STATE_DRAINING) { |
---|
| 755 | + spin_unlock_irqrestore(&cable->lock, flags); |
---|
| 756 | + return; |
---|
| 757 | + } |
---|
| 758 | + } |
---|
| 759 | + |
---|
| 760 | + substream_play = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? |
---|
| 761 | + dpcm_play->substream : NULL; |
---|
| 762 | + substream_capt = (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) ? |
---|
| 763 | + dpcm_capt->substream : NULL; |
---|
| 764 | + valid_runtime = (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) ? |
---|
| 765 | + dpcm_play->substream->runtime : |
---|
| 766 | + dpcm_capt->substream->runtime; |
---|
| 767 | + |
---|
| 768 | + /* resolution is only valid for SNDRV_TIMER_EVENT_TICK events */ |
---|
| 769 | + if (event == SNDRV_TIMER_EVENT_TICK) { |
---|
| 770 | + /* The hardware rules guarantee that playback and capture period |
---|
| 771 | + * are the same. Therefore only one device has to be checked |
---|
| 772 | + * here. |
---|
| 773 | + */ |
---|
| 774 | + if (loopback_snd_timer_check_resolution(valid_runtime, |
---|
| 775 | + resolution) < 0) { |
---|
| 776 | + spin_unlock_irqrestore(&cable->lock, flags); |
---|
| 777 | + if (substream_play) |
---|
| 778 | + snd_pcm_stop_xrun(substream_play); |
---|
| 779 | + if (substream_capt) |
---|
| 780 | + snd_pcm_stop_xrun(substream_capt); |
---|
| 781 | + return; |
---|
| 782 | + } |
---|
| 783 | + } |
---|
| 784 | + |
---|
| 785 | + elapsed_bytes = frames_to_bytes(valid_runtime, |
---|
| 786 | + valid_runtime->period_size); |
---|
| 787 | + /* The same timer interrupt is used for playback and capture device */ |
---|
| 788 | + if ((running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && |
---|
| 789 | + (running & (1 << SNDRV_PCM_STREAM_CAPTURE))) { |
---|
| 790 | + copy_play_buf(dpcm_play, dpcm_capt, elapsed_bytes); |
---|
| 791 | + bytepos_finish(dpcm_play, elapsed_bytes); |
---|
| 792 | + bytepos_finish(dpcm_capt, elapsed_bytes); |
---|
| 793 | + } else if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) { |
---|
| 794 | + bytepos_finish(dpcm_play, elapsed_bytes); |
---|
| 795 | + } else if (running & (1 << SNDRV_PCM_STREAM_CAPTURE)) { |
---|
| 796 | + clear_capture_buf(dpcm_capt, elapsed_bytes); |
---|
| 797 | + bytepos_finish(dpcm_capt, elapsed_bytes); |
---|
| 798 | + } |
---|
| 799 | + spin_unlock_irqrestore(&cable->lock, flags); |
---|
| 800 | + |
---|
| 801 | + if (substream_play) |
---|
| 802 | + snd_pcm_period_elapsed(substream_play); |
---|
| 803 | + if (substream_capt) |
---|
| 804 | + snd_pcm_period_elapsed(substream_capt); |
---|
| 805 | +} |
---|
| 806 | + |
---|
| 807 | +static void loopback_snd_timer_function(struct snd_timer_instance *timeri, |
---|
| 808 | + unsigned long resolution, |
---|
| 809 | + unsigned long ticks) |
---|
| 810 | +{ |
---|
| 811 | + struct loopback_cable *cable = timeri->callback_data; |
---|
| 812 | + |
---|
| 813 | + loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_TICK, |
---|
| 814 | + resolution); |
---|
| 815 | +} |
---|
| 816 | + |
---|
| 817 | +static void loopback_snd_timer_work(struct work_struct *work) |
---|
| 818 | +{ |
---|
| 819 | + struct loopback_cable *cable; |
---|
| 820 | + |
---|
| 821 | + cable = container_of(work, struct loopback_cable, snd_timer.event_work); |
---|
| 822 | + loopback_snd_timer_period_elapsed(cable, SNDRV_TIMER_EVENT_MSTOP, 0); |
---|
| 823 | +} |
---|
| 824 | + |
---|
| 825 | +static void loopback_snd_timer_event(struct snd_timer_instance *timeri, |
---|
| 826 | + int event, |
---|
| 827 | + struct timespec64 *tstamp, |
---|
| 828 | + unsigned long resolution) |
---|
| 829 | +{ |
---|
| 830 | + /* Do not lock cable->lock here because timer->lock is already hold. |
---|
| 831 | + * There are other functions which first lock cable->lock and than |
---|
| 832 | + * timer->lock e.g. |
---|
| 833 | + * loopback_trigger() |
---|
| 834 | + * spin_lock(&cable->lock) |
---|
| 835 | + * loopback_snd_timer_start() |
---|
| 836 | + * snd_timer_start() |
---|
| 837 | + * spin_lock(&timer->lock) |
---|
| 838 | + * Therefore when using the oposit order of locks here it could result |
---|
| 839 | + * in a deadlock. |
---|
| 840 | + */ |
---|
| 841 | + |
---|
| 842 | + if (event == SNDRV_TIMER_EVENT_MSTOP) { |
---|
| 843 | + struct loopback_cable *cable = timeri->callback_data; |
---|
| 844 | + |
---|
| 845 | + /* sound card of the timer was stopped. Therefore there will not |
---|
| 846 | + * be any further timer callbacks. Due to this forward audio |
---|
| 847 | + * data from here if in draining state. When still in running |
---|
| 848 | + * state the streaming will be aborted by the usual timeout. It |
---|
| 849 | + * should not be aborted here because may be the timer sound |
---|
| 850 | + * card does only a recovery and the timer is back soon. |
---|
| 851 | + * This work triggers loopback_snd_timer_work() |
---|
| 852 | + */ |
---|
| 853 | + schedule_work(&cable->snd_timer.event_work); |
---|
| 854 | + } |
---|
| 855 | +} |
---|
| 856 | + |
---|
| 857 | +static void loopback_jiffies_timer_dpcm_info(struct loopback_pcm *dpcm, |
---|
| 858 | + struct snd_info_buffer *buffer) |
---|
| 859 | +{ |
---|
| 860 | + snd_iprintf(buffer, " update_pending:\t%u\n", |
---|
| 861 | + dpcm->period_update_pending); |
---|
| 862 | + snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); |
---|
| 863 | + snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); |
---|
| 864 | + snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", |
---|
| 865 | + dpcm->last_jiffies, cycles_to_jiffies()); |
---|
| 866 | + snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); |
---|
| 867 | +} |
---|
| 868 | + |
---|
| 869 | +static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm, |
---|
| 870 | + struct snd_info_buffer *buffer) |
---|
| 871 | +{ |
---|
| 872 | + struct loopback_cable *cable = dpcm->cable; |
---|
| 873 | + |
---|
| 874 | + snd_iprintf(buffer, " sound timer:\thw:%d,%d,%d\n", |
---|
| 875 | + cable->snd_timer.id.card, |
---|
| 876 | + cable->snd_timer.id.device, |
---|
| 877 | + cable->snd_timer.id.subdevice); |
---|
| 878 | + snd_iprintf(buffer, " timer open:\t\t%s\n", |
---|
| 879 | + (cable->snd_timer.stream == SNDRV_PCM_STREAM_CAPTURE) ? |
---|
| 880 | + "capture" : "playback"); |
---|
| 881 | +} |
---|
| 882 | + |
---|
566 | 883 | static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) |
---|
567 | 884 | { |
---|
568 | 885 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
.. | .. |
---|
570 | 887 | snd_pcm_uframes_t pos; |
---|
571 | 888 | |
---|
572 | 889 | spin_lock(&dpcm->cable->lock); |
---|
573 | | - loopback_pos_update(dpcm->cable); |
---|
| 890 | + if (dpcm->cable->ops->pos_update) |
---|
| 891 | + dpcm->cable->ops->pos_update(dpcm->cable); |
---|
574 | 892 | pos = dpcm->buf_pos; |
---|
575 | 893 | spin_unlock(&dpcm->cable->lock); |
---|
576 | 894 | return bytes_to_frames(runtime, pos); |
---|
.. | .. |
---|
582 | 900 | SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | |
---|
583 | 901 | SNDRV_PCM_INFO_RESUME), |
---|
584 | 902 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE | |
---|
| 903 | + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE | |
---|
| 904 | + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE | |
---|
585 | 905 | SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE | |
---|
586 | 906 | SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), |
---|
587 | 907 | .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_192000, |
---|
.. | .. |
---|
605 | 925 | kfree(dpcm); |
---|
606 | 926 | } |
---|
607 | 927 | |
---|
608 | | -static int loopback_hw_params(struct snd_pcm_substream *substream, |
---|
609 | | - struct snd_pcm_hw_params *params) |
---|
610 | | -{ |
---|
611 | | - return snd_pcm_lib_alloc_vmalloc_buffer(substream, |
---|
612 | | - params_buffer_bytes(params)); |
---|
613 | | -} |
---|
614 | | - |
---|
615 | 928 | static int loopback_hw_free(struct snd_pcm_substream *substream) |
---|
616 | 929 | { |
---|
617 | 930 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
.. | .. |
---|
621 | 934 | mutex_lock(&dpcm->loopback->cable_lock); |
---|
622 | 935 | cable->valid &= ~(1 << substream->stream); |
---|
623 | 936 | mutex_unlock(&dpcm->loopback->cable_lock); |
---|
624 | | - return snd_pcm_lib_free_vmalloc_buffer(substream); |
---|
| 937 | + return 0; |
---|
625 | 938 | } |
---|
626 | 939 | |
---|
627 | 940 | static unsigned int get_cable_index(struct snd_pcm_substream *substream) |
---|
.. | .. |
---|
679 | 992 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); |
---|
680 | 993 | } |
---|
681 | 994 | |
---|
| 995 | +static int rule_period_bytes(struct snd_pcm_hw_params *params, |
---|
| 996 | + struct snd_pcm_hw_rule *rule) |
---|
| 997 | +{ |
---|
| 998 | + struct loopback_pcm *dpcm = rule->private; |
---|
| 999 | + struct loopback_cable *cable = dpcm->cable; |
---|
| 1000 | + struct snd_interval t; |
---|
| 1001 | + |
---|
| 1002 | + mutex_lock(&dpcm->loopback->cable_lock); |
---|
| 1003 | + t.min = cable->hw.period_bytes_min; |
---|
| 1004 | + t.max = cable->hw.period_bytes_max; |
---|
| 1005 | + mutex_unlock(&dpcm->loopback->cable_lock); |
---|
| 1006 | + t.openmin = 0; |
---|
| 1007 | + t.openmax = 0; |
---|
| 1008 | + t.integer = 0; |
---|
| 1009 | + return snd_interval_refine(hw_param_interval(params, rule->var), &t); |
---|
| 1010 | +} |
---|
| 1011 | + |
---|
682 | 1012 | static void free_cable(struct snd_pcm_substream *substream) |
---|
683 | 1013 | { |
---|
684 | 1014 | struct loopback *loopback = substream->private_data; |
---|
.. | .. |
---|
694 | 1024 | cable->streams[substream->stream] = NULL; |
---|
695 | 1025 | spin_unlock_irq(&cable->lock); |
---|
696 | 1026 | } else { |
---|
| 1027 | + struct loopback_pcm *dpcm = substream->runtime->private_data; |
---|
| 1028 | + |
---|
| 1029 | + if (cable->ops && cable->ops->close_cable && dpcm) |
---|
| 1030 | + cable->ops->close_cable(dpcm); |
---|
697 | 1031 | /* free the cable */ |
---|
698 | 1032 | loopback->cables[substream->number][dev] = NULL; |
---|
699 | 1033 | kfree(cable); |
---|
700 | 1034 | } |
---|
701 | 1035 | } |
---|
| 1036 | + |
---|
| 1037 | +static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm) |
---|
| 1038 | +{ |
---|
| 1039 | + timer_setup(&dpcm->timer, loopback_jiffies_timer_function, 0); |
---|
| 1040 | + |
---|
| 1041 | + return 0; |
---|
| 1042 | +} |
---|
| 1043 | + |
---|
| 1044 | +static struct loopback_ops loopback_jiffies_timer_ops = { |
---|
| 1045 | + .open = loopback_jiffies_timer_open, |
---|
| 1046 | + .start = loopback_jiffies_timer_start, |
---|
| 1047 | + .stop = loopback_jiffies_timer_stop, |
---|
| 1048 | + .stop_sync = loopback_jiffies_timer_stop_sync, |
---|
| 1049 | + .close_substream = loopback_jiffies_timer_stop_sync, |
---|
| 1050 | + .pos_update = loopback_jiffies_timer_pos_update, |
---|
| 1051 | + .dpcm_info = loopback_jiffies_timer_dpcm_info, |
---|
| 1052 | +}; |
---|
| 1053 | + |
---|
| 1054 | +static int loopback_parse_timer_id(const char *str, |
---|
| 1055 | + struct snd_timer_id *tid) |
---|
| 1056 | +{ |
---|
| 1057 | + /* [<pref>:](<card name>|<card idx>)[{.,}<dev idx>[{.,}<subdev idx>]] */ |
---|
| 1058 | + const char * const sep_dev = ".,"; |
---|
| 1059 | + const char * const sep_pref = ":"; |
---|
| 1060 | + const char *name = str; |
---|
| 1061 | + char *sep, save = '\0'; |
---|
| 1062 | + int card_idx = 0, dev = 0, subdev = 0; |
---|
| 1063 | + int err; |
---|
| 1064 | + |
---|
| 1065 | + sep = strpbrk(str, sep_pref); |
---|
| 1066 | + if (sep) |
---|
| 1067 | + name = sep + 1; |
---|
| 1068 | + sep = strpbrk(name, sep_dev); |
---|
| 1069 | + if (sep) { |
---|
| 1070 | + save = *sep; |
---|
| 1071 | + *sep = '\0'; |
---|
| 1072 | + } |
---|
| 1073 | + err = kstrtoint(name, 0, &card_idx); |
---|
| 1074 | + if (err == -EINVAL) { |
---|
| 1075 | + /* Must be the name, not number */ |
---|
| 1076 | + for (card_idx = 0; card_idx < snd_ecards_limit; card_idx++) { |
---|
| 1077 | + struct snd_card *card = snd_card_ref(card_idx); |
---|
| 1078 | + |
---|
| 1079 | + if (card) { |
---|
| 1080 | + if (!strcmp(card->id, name)) |
---|
| 1081 | + err = 0; |
---|
| 1082 | + snd_card_unref(card); |
---|
| 1083 | + } |
---|
| 1084 | + if (!err) |
---|
| 1085 | + break; |
---|
| 1086 | + } |
---|
| 1087 | + } |
---|
| 1088 | + if (sep) { |
---|
| 1089 | + *sep = save; |
---|
| 1090 | + if (!err) { |
---|
| 1091 | + char *sep2, save2 = '\0'; |
---|
| 1092 | + |
---|
| 1093 | + sep2 = strpbrk(sep + 1, sep_dev); |
---|
| 1094 | + if (sep2) { |
---|
| 1095 | + save2 = *sep2; |
---|
| 1096 | + *sep2 = '\0'; |
---|
| 1097 | + } |
---|
| 1098 | + err = kstrtoint(sep + 1, 0, &dev); |
---|
| 1099 | + if (sep2) { |
---|
| 1100 | + *sep2 = save2; |
---|
| 1101 | + if (!err) |
---|
| 1102 | + err = kstrtoint(sep2 + 1, 0, &subdev); |
---|
| 1103 | + } |
---|
| 1104 | + } |
---|
| 1105 | + } |
---|
| 1106 | + if (!err && tid) { |
---|
| 1107 | + tid->card = card_idx; |
---|
| 1108 | + tid->device = dev; |
---|
| 1109 | + tid->subdevice = subdev; |
---|
| 1110 | + } |
---|
| 1111 | + return err; |
---|
| 1112 | +} |
---|
| 1113 | + |
---|
| 1114 | +/* call in loopback->cable_lock */ |
---|
| 1115 | +static int loopback_snd_timer_open(struct loopback_pcm *dpcm) |
---|
| 1116 | +{ |
---|
| 1117 | + int err = 0; |
---|
| 1118 | + struct snd_timer_id tid = { |
---|
| 1119 | + .dev_class = SNDRV_TIMER_CLASS_PCM, |
---|
| 1120 | + .dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION, |
---|
| 1121 | + }; |
---|
| 1122 | + struct snd_timer_instance *timeri; |
---|
| 1123 | + struct loopback_cable *cable = dpcm->cable; |
---|
| 1124 | + |
---|
| 1125 | + /* check if timer was already opened. It is only opened once |
---|
| 1126 | + * per playback and capture subdevice (aka cable). |
---|
| 1127 | + */ |
---|
| 1128 | + if (cable->snd_timer.instance) |
---|
| 1129 | + goto exit; |
---|
| 1130 | + |
---|
| 1131 | + err = loopback_parse_timer_id(dpcm->loopback->timer_source, &tid); |
---|
| 1132 | + if (err < 0) { |
---|
| 1133 | + pcm_err(dpcm->substream->pcm, |
---|
| 1134 | + "Parsing timer source \'%s\' failed with %d", |
---|
| 1135 | + dpcm->loopback->timer_source, err); |
---|
| 1136 | + goto exit; |
---|
| 1137 | + } |
---|
| 1138 | + |
---|
| 1139 | + cable->snd_timer.stream = dpcm->substream->stream; |
---|
| 1140 | + cable->snd_timer.id = tid; |
---|
| 1141 | + |
---|
| 1142 | + timeri = snd_timer_instance_new(dpcm->loopback->card->id); |
---|
| 1143 | + if (!timeri) { |
---|
| 1144 | + err = -ENOMEM; |
---|
| 1145 | + goto exit; |
---|
| 1146 | + } |
---|
| 1147 | + /* The callback has to be called from another work. If |
---|
| 1148 | + * SNDRV_TIMER_IFLG_FAST is specified it will be called from the |
---|
| 1149 | + * snd_pcm_period_elapsed() call of the selected sound card. |
---|
| 1150 | + * snd_pcm_period_elapsed() helds snd_pcm_stream_lock_irqsave(). |
---|
| 1151 | + * Due to our callback loopback_snd_timer_function() also calls |
---|
| 1152 | + * snd_pcm_period_elapsed() which calls snd_pcm_stream_lock_irqsave(). |
---|
| 1153 | + * This would end up in a dead lock. |
---|
| 1154 | + */ |
---|
| 1155 | + timeri->flags |= SNDRV_TIMER_IFLG_AUTO; |
---|
| 1156 | + timeri->callback = loopback_snd_timer_function; |
---|
| 1157 | + timeri->callback_data = (void *)cable; |
---|
| 1158 | + timeri->ccallback = loopback_snd_timer_event; |
---|
| 1159 | + |
---|
| 1160 | + /* initialise a work used for draining */ |
---|
| 1161 | + INIT_WORK(&cable->snd_timer.event_work, loopback_snd_timer_work); |
---|
| 1162 | + |
---|
| 1163 | + /* The mutex loopback->cable_lock is kept locked. |
---|
| 1164 | + * Therefore snd_timer_open() cannot be called a second time |
---|
| 1165 | + * by the other device of the same cable. |
---|
| 1166 | + * Therefore the following issue cannot happen: |
---|
| 1167 | + * [proc1] Call loopback_timer_open() -> |
---|
| 1168 | + * Unlock cable->lock for snd_timer_close/open() call |
---|
| 1169 | + * [proc2] Call loopback_timer_open() -> snd_timer_open(), |
---|
| 1170 | + * snd_timer_start() |
---|
| 1171 | + * [proc1] Call snd_timer_open() and overwrite running timer |
---|
| 1172 | + * instance |
---|
| 1173 | + */ |
---|
| 1174 | + err = snd_timer_open(timeri, &cable->snd_timer.id, current->pid); |
---|
| 1175 | + if (err < 0) { |
---|
| 1176 | + pcm_err(dpcm->substream->pcm, |
---|
| 1177 | + "snd_timer_open (%d,%d,%d) failed with %d", |
---|
| 1178 | + cable->snd_timer.id.card, |
---|
| 1179 | + cable->snd_timer.id.device, |
---|
| 1180 | + cable->snd_timer.id.subdevice, |
---|
| 1181 | + err); |
---|
| 1182 | + snd_timer_instance_free(timeri); |
---|
| 1183 | + goto exit; |
---|
| 1184 | + } |
---|
| 1185 | + |
---|
| 1186 | + cable->snd_timer.instance = timeri; |
---|
| 1187 | + |
---|
| 1188 | +exit: |
---|
| 1189 | + return err; |
---|
| 1190 | +} |
---|
| 1191 | + |
---|
| 1192 | +/* stop_sync() is not required for sound timer because it does not need to be |
---|
| 1193 | + * restarted in loopback_prepare() on Xrun recovery |
---|
| 1194 | + */ |
---|
| 1195 | +static struct loopback_ops loopback_snd_timer_ops = { |
---|
| 1196 | + .open = loopback_snd_timer_open, |
---|
| 1197 | + .start = loopback_snd_timer_start, |
---|
| 1198 | + .stop = loopback_snd_timer_stop, |
---|
| 1199 | + .close_cable = loopback_snd_timer_close_cable, |
---|
| 1200 | + .dpcm_info = loopback_snd_timer_dpcm_info, |
---|
| 1201 | +}; |
---|
702 | 1202 | |
---|
703 | 1203 | static int loopback_open(struct snd_pcm_substream *substream) |
---|
704 | 1204 | { |
---|
.. | .. |
---|
717 | 1217 | } |
---|
718 | 1218 | dpcm->loopback = loopback; |
---|
719 | 1219 | dpcm->substream = substream; |
---|
720 | | - timer_setup(&dpcm->timer, loopback_timer_function, 0); |
---|
721 | 1220 | |
---|
722 | 1221 | cable = loopback->cables[substream->number][dev]; |
---|
723 | 1222 | if (!cable) { |
---|
.. | .. |
---|
728 | 1227 | } |
---|
729 | 1228 | spin_lock_init(&cable->lock); |
---|
730 | 1229 | cable->hw = loopback_pcm_hardware; |
---|
| 1230 | + if (loopback->timer_source) |
---|
| 1231 | + cable->ops = &loopback_snd_timer_ops; |
---|
| 1232 | + else |
---|
| 1233 | + cable->ops = &loopback_jiffies_timer_ops; |
---|
731 | 1234 | loopback->cables[substream->number][dev] = cable; |
---|
732 | 1235 | } |
---|
733 | 1236 | dpcm->cable = cable; |
---|
| 1237 | + runtime->private_data = dpcm; |
---|
| 1238 | + |
---|
| 1239 | + if (cable->ops->open) { |
---|
| 1240 | + err = cable->ops->open(dpcm); |
---|
| 1241 | + if (err < 0) |
---|
| 1242 | + goto unlock; |
---|
| 1243 | + } |
---|
734 | 1244 | |
---|
735 | 1245 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); |
---|
736 | 1246 | |
---|
.. | .. |
---|
756 | 1266 | if (err < 0) |
---|
757 | 1267 | goto unlock; |
---|
758 | 1268 | |
---|
759 | | - runtime->private_data = dpcm; |
---|
| 1269 | + /* In case of sound timer the period time of both devices of the same |
---|
| 1270 | + * loop has to be the same. |
---|
| 1271 | + * This rule only takes effect if a sound timer was chosen |
---|
| 1272 | + */ |
---|
| 1273 | + if (cable->snd_timer.instance) { |
---|
| 1274 | + err = snd_pcm_hw_rule_add(runtime, 0, |
---|
| 1275 | + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, |
---|
| 1276 | + rule_period_bytes, dpcm, |
---|
| 1277 | + SNDRV_PCM_HW_PARAM_PERIOD_BYTES, -1); |
---|
| 1278 | + if (err < 0) |
---|
| 1279 | + goto unlock; |
---|
| 1280 | + } |
---|
| 1281 | + |
---|
| 1282 | + /* loopback_runtime_free() has not to be called if kfree(dpcm) was |
---|
| 1283 | + * already called here. Otherwise it will end up with a double free. |
---|
| 1284 | + */ |
---|
760 | 1285 | runtime->private_free = loopback_runtime_free; |
---|
761 | 1286 | if (get_notify(dpcm)) |
---|
762 | 1287 | runtime->hw = loopback_pcm_hardware; |
---|
.. | .. |
---|
780 | 1305 | { |
---|
781 | 1306 | struct loopback *loopback = substream->private_data; |
---|
782 | 1307 | struct loopback_pcm *dpcm = substream->runtime->private_data; |
---|
| 1308 | + int err = 0; |
---|
783 | 1309 | |
---|
784 | | - loopback_timer_stop_sync(dpcm); |
---|
| 1310 | + if (dpcm->cable->ops->close_substream) |
---|
| 1311 | + err = dpcm->cable->ops->close_substream(dpcm); |
---|
785 | 1312 | mutex_lock(&loopback->cable_lock); |
---|
786 | 1313 | free_cable(substream); |
---|
787 | 1314 | mutex_unlock(&loopback->cable_lock); |
---|
788 | | - return 0; |
---|
| 1315 | + return err; |
---|
789 | 1316 | } |
---|
790 | 1317 | |
---|
791 | 1318 | static const struct snd_pcm_ops loopback_pcm_ops = { |
---|
792 | 1319 | .open = loopback_open, |
---|
793 | 1320 | .close = loopback_close, |
---|
794 | | - .ioctl = snd_pcm_lib_ioctl, |
---|
795 | | - .hw_params = loopback_hw_params, |
---|
796 | 1321 | .hw_free = loopback_hw_free, |
---|
797 | 1322 | .prepare = loopback_prepare, |
---|
798 | 1323 | .trigger = loopback_trigger, |
---|
799 | 1324 | .pointer = loopback_pointer, |
---|
800 | | - .page = snd_pcm_lib_get_vmalloc_page, |
---|
801 | 1325 | }; |
---|
802 | 1326 | |
---|
803 | 1327 | static int loopback_pcm_new(struct loopback *loopback, |
---|
.. | .. |
---|
812 | 1336 | return err; |
---|
813 | 1337 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops); |
---|
814 | 1338 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops); |
---|
| 1339 | + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); |
---|
815 | 1340 | |
---|
816 | 1341 | pcm->private_data = loopback; |
---|
817 | 1342 | pcm->info_flags = 0; |
---|
.. | .. |
---|
926 | 1451 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
---|
927 | 1452 | uinfo->count = 1; |
---|
928 | 1453 | uinfo->value.integer.min = 0; |
---|
929 | | - uinfo->value.integer.max = SNDRV_PCM_FORMAT_LAST; |
---|
| 1454 | + uinfo->value.integer.max = (__force int)SNDRV_PCM_FORMAT_LAST; |
---|
930 | 1455 | uinfo->value.integer.step = 1; |
---|
931 | 1456 | return 0; |
---|
932 | 1457 | } |
---|
.. | .. |
---|
937 | 1462 | struct loopback *loopback = snd_kcontrol_chip(kcontrol); |
---|
938 | 1463 | |
---|
939 | 1464 | ucontrol->value.integer.value[0] = |
---|
940 | | - loopback->setup[kcontrol->id.subdevice] |
---|
| 1465 | + (__force int)loopback->setup[kcontrol->id.subdevice] |
---|
941 | 1466 | [kcontrol->id.device].format; |
---|
942 | 1467 | return 0; |
---|
943 | 1468 | } |
---|
.. | .. |
---|
990 | 1515 | return 0; |
---|
991 | 1516 | } |
---|
992 | 1517 | |
---|
993 | | -static struct snd_kcontrol_new loopback_controls[] = { |
---|
| 1518 | +static const struct snd_kcontrol_new loopback_controls[] = { |
---|
994 | 1519 | { |
---|
995 | 1520 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, |
---|
996 | 1521 | .name = "PCM Rate Shift 100000", |
---|
.. | .. |
---|
1113 | 1638 | snd_iprintf(buffer, " bytes_per_sec:\t%u\n", dpcm->pcm_bps); |
---|
1114 | 1639 | snd_iprintf(buffer, " sample_align:\t%u\n", dpcm->pcm_salign); |
---|
1115 | 1640 | snd_iprintf(buffer, " rate_shift:\t\t%u\n", dpcm->pcm_rate_shift); |
---|
1116 | | - snd_iprintf(buffer, " update_pending:\t%u\n", |
---|
1117 | | - dpcm->period_update_pending); |
---|
1118 | | - snd_iprintf(buffer, " irq_pos:\t\t%u\n", dpcm->irq_pos); |
---|
1119 | | - snd_iprintf(buffer, " period_frac:\t%u\n", dpcm->period_size_frac); |
---|
1120 | | - snd_iprintf(buffer, " last_jiffies:\t%lu (%lu)\n", |
---|
1121 | | - dpcm->last_jiffies, cycles_to_jiffies()); |
---|
1122 | | - snd_iprintf(buffer, " timer_expires:\t%lu\n", dpcm->timer.expires); |
---|
| 1641 | + if (dpcm->cable->ops->dpcm_info) |
---|
| 1642 | + dpcm->cable->ops->dpcm_info(dpcm, buffer); |
---|
1123 | 1643 | } |
---|
1124 | 1644 | |
---|
1125 | 1645 | static void print_substream_info(struct snd_info_buffer *buffer, |
---|
.. | .. |
---|
1155 | 1675 | mutex_unlock(&loopback->cable_lock); |
---|
1156 | 1676 | } |
---|
1157 | 1677 | |
---|
1158 | | -static int loopback_proc_new(struct loopback *loopback, int cidx) |
---|
| 1678 | +static int loopback_cable_proc_new(struct loopback *loopback, int cidx) |
---|
1159 | 1679 | { |
---|
1160 | 1680 | char name[32]; |
---|
1161 | | - struct snd_info_entry *entry; |
---|
1162 | | - int err; |
---|
1163 | 1681 | |
---|
1164 | 1682 | snprintf(name, sizeof(name), "cable#%d", cidx); |
---|
1165 | | - err = snd_card_proc_new(loopback->card, name, &entry); |
---|
1166 | | - if (err < 0) |
---|
1167 | | - return err; |
---|
| 1683 | + return snd_card_ro_proc_new(loopback->card, name, loopback, |
---|
| 1684 | + print_cable_info); |
---|
| 1685 | +} |
---|
1168 | 1686 | |
---|
1169 | | - snd_info_set_text_ops(entry, loopback, print_cable_info); |
---|
1170 | | - return 0; |
---|
| 1687 | +static void loopback_set_timer_source(struct loopback *loopback, |
---|
| 1688 | + const char *value) |
---|
| 1689 | +{ |
---|
| 1690 | + if (loopback->timer_source) { |
---|
| 1691 | + devm_kfree(loopback->card->dev, loopback->timer_source); |
---|
| 1692 | + loopback->timer_source = NULL; |
---|
| 1693 | + } |
---|
| 1694 | + if (value && *value) |
---|
| 1695 | + loopback->timer_source = devm_kstrdup(loopback->card->dev, |
---|
| 1696 | + value, GFP_KERNEL); |
---|
| 1697 | +} |
---|
| 1698 | + |
---|
| 1699 | +static void print_timer_source_info(struct snd_info_entry *entry, |
---|
| 1700 | + struct snd_info_buffer *buffer) |
---|
| 1701 | +{ |
---|
| 1702 | + struct loopback *loopback = entry->private_data; |
---|
| 1703 | + |
---|
| 1704 | + mutex_lock(&loopback->cable_lock); |
---|
| 1705 | + snd_iprintf(buffer, "%s\n", |
---|
| 1706 | + loopback->timer_source ? loopback->timer_source : ""); |
---|
| 1707 | + mutex_unlock(&loopback->cable_lock); |
---|
| 1708 | +} |
---|
| 1709 | + |
---|
| 1710 | +static void change_timer_source_info(struct snd_info_entry *entry, |
---|
| 1711 | + struct snd_info_buffer *buffer) |
---|
| 1712 | +{ |
---|
| 1713 | + struct loopback *loopback = entry->private_data; |
---|
| 1714 | + char line[64]; |
---|
| 1715 | + |
---|
| 1716 | + mutex_lock(&loopback->cable_lock); |
---|
| 1717 | + if (!snd_info_get_line(buffer, line, sizeof(line))) |
---|
| 1718 | + loopback_set_timer_source(loopback, strim(line)); |
---|
| 1719 | + mutex_unlock(&loopback->cable_lock); |
---|
| 1720 | +} |
---|
| 1721 | + |
---|
| 1722 | +static int loopback_timer_source_proc_new(struct loopback *loopback) |
---|
| 1723 | +{ |
---|
| 1724 | + return snd_card_rw_proc_new(loopback->card, "timer_source", loopback, |
---|
| 1725 | + print_timer_source_info, |
---|
| 1726 | + change_timer_source_info); |
---|
1171 | 1727 | } |
---|
1172 | 1728 | |
---|
1173 | 1729 | static int loopback_probe(struct platform_device *devptr) |
---|
.. | .. |
---|
1189 | 1745 | pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; |
---|
1190 | 1746 | |
---|
1191 | 1747 | loopback->card = card; |
---|
| 1748 | + loopback_set_timer_source(loopback, timer_source[dev]); |
---|
| 1749 | + |
---|
1192 | 1750 | mutex_init(&loopback->cable_lock); |
---|
1193 | 1751 | |
---|
1194 | 1752 | err = loopback_pcm_new(loopback, 0, pcm_substreams[dev]); |
---|
.. | .. |
---|
1200 | 1758 | err = loopback_mixer_new(loopback, pcm_notify[dev] ? 1 : 0); |
---|
1201 | 1759 | if (err < 0) |
---|
1202 | 1760 | goto __nodev; |
---|
1203 | | - loopback_proc_new(loopback, 0); |
---|
1204 | | - loopback_proc_new(loopback, 1); |
---|
| 1761 | + loopback_cable_proc_new(loopback, 0); |
---|
| 1762 | + loopback_cable_proc_new(loopback, 1); |
---|
| 1763 | + loopback_timer_source_proc_new(loopback); |
---|
1205 | 1764 | strcpy(card->driver, "Loopback"); |
---|
1206 | 1765 | strcpy(card->shortname, "Loopback"); |
---|
1207 | 1766 | sprintf(card->longname, "Loopback %i", dev + 1); |
---|
.. | .. |
---|
1225 | 1784 | static int loopback_suspend(struct device *pdev) |
---|
1226 | 1785 | { |
---|
1227 | 1786 | struct snd_card *card = dev_get_drvdata(pdev); |
---|
1228 | | - struct loopback *loopback = card->private_data; |
---|
1229 | 1787 | |
---|
1230 | 1788 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
---|
1231 | | - |
---|
1232 | | - snd_pcm_suspend_all(loopback->pcm[0]); |
---|
1233 | | - snd_pcm_suspend_all(loopback->pcm[1]); |
---|
1234 | 1789 | return 0; |
---|
1235 | 1790 | } |
---|
1236 | 1791 | |
---|