.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Digital Audio (PCM) abstract layer |
---|
3 | 4 | * Copyright (c) by Jaroslav Kysela <perex@perex.cz> |
---|
4 | | - * |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify |
---|
7 | | - * it under the terms of the GNU General Public License as published by |
---|
8 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
9 | | - * (at your option) any later version. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
14 | | - * GNU General Public License for more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public License |
---|
17 | | - * along with this program; if not, write to the Free Software |
---|
18 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
19 | | - * |
---|
20 | 5 | */ |
---|
21 | 6 | |
---|
| 7 | +#include <linux/compat.h> |
---|
22 | 8 | #include <linux/mm.h> |
---|
23 | 9 | #include <linux/module.h> |
---|
24 | 10 | #include <linux/file.h> |
---|
.. | .. |
---|
28 | 14 | #include <linux/pm_qos.h> |
---|
29 | 15 | #include <linux/io.h> |
---|
30 | 16 | #include <linux/dma-mapping.h> |
---|
| 17 | +#include <linux/vmalloc.h> |
---|
31 | 18 | #include <sound/core.h> |
---|
32 | 19 | #include <sound/control.h> |
---|
33 | 20 | #include <sound/info.h> |
---|
.. | .. |
---|
85 | 72 | * |
---|
86 | 73 | */ |
---|
87 | 74 | |
---|
88 | | -static DEFINE_RWLOCK(snd_pcm_link_rwlock); |
---|
89 | 75 | static DECLARE_RWSEM(snd_pcm_link_rwsem); |
---|
90 | 76 | |
---|
91 | | -/* Writer in rwsem may block readers even during its waiting in queue, |
---|
92 | | - * and this may lead to a deadlock when the code path takes read sem |
---|
93 | | - * twice (e.g. one in snd_pcm_action_nonatomic() and another in |
---|
94 | | - * snd_pcm_stream_lock()). As a (suboptimal) workaround, let writer to |
---|
95 | | - * sleep until all the readers are completed without blocking by writer. |
---|
96 | | - */ |
---|
97 | | -static inline void down_write_nonfifo(struct rw_semaphore *lock) |
---|
| 77 | +void snd_pcm_group_init(struct snd_pcm_group *group) |
---|
98 | 78 | { |
---|
99 | | - while (!down_write_trylock(lock)) |
---|
100 | | - msleep(1); |
---|
| 79 | + spin_lock_init(&group->lock); |
---|
| 80 | + mutex_init(&group->mutex); |
---|
| 81 | + INIT_LIST_HEAD(&group->substreams); |
---|
| 82 | + refcount_set(&group->refs, 1); |
---|
101 | 83 | } |
---|
102 | 84 | |
---|
103 | | -#define PCM_LOCK_DEFAULT 0 |
---|
104 | | -#define PCM_LOCK_IRQ 1 |
---|
105 | | -#define PCM_LOCK_IRQSAVE 2 |
---|
106 | | - |
---|
107 | | -static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substream, |
---|
108 | | - unsigned int mode) |
---|
109 | | -{ |
---|
110 | | - unsigned long flags = 0; |
---|
111 | | - if (substream->pcm->nonatomic) { |
---|
112 | | - down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING); |
---|
113 | | - mutex_lock(&substream->self_group.mutex); |
---|
114 | | - } else { |
---|
115 | | - switch (mode) { |
---|
116 | | - case PCM_LOCK_DEFAULT: |
---|
117 | | - read_lock(&snd_pcm_link_rwlock); |
---|
118 | | - break; |
---|
119 | | - case PCM_LOCK_IRQ: |
---|
120 | | - read_lock_irq(&snd_pcm_link_rwlock); |
---|
121 | | - break; |
---|
122 | | - case PCM_LOCK_IRQSAVE: |
---|
123 | | - read_lock_irqsave(&snd_pcm_link_rwlock, flags); |
---|
124 | | - break; |
---|
125 | | - } |
---|
126 | | - spin_lock(&substream->self_group.lock); |
---|
127 | | - } |
---|
128 | | - return flags; |
---|
| 85 | +/* define group lock helpers */ |
---|
| 86 | +#define DEFINE_PCM_GROUP_LOCK(action, mutex_action) \ |
---|
| 87 | +static void snd_pcm_group_ ## action(struct snd_pcm_group *group, bool nonatomic) \ |
---|
| 88 | +{ \ |
---|
| 89 | + if (nonatomic) \ |
---|
| 90 | + mutex_ ## mutex_action(&group->mutex); \ |
---|
| 91 | + else \ |
---|
| 92 | + spin_ ## action(&group->lock); \ |
---|
129 | 93 | } |
---|
130 | 94 | |
---|
131 | | -static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, |
---|
132 | | - unsigned int mode, unsigned long flags) |
---|
133 | | -{ |
---|
134 | | - if (substream->pcm->nonatomic) { |
---|
135 | | - mutex_unlock(&substream->self_group.mutex); |
---|
136 | | - up_read(&snd_pcm_link_rwsem); |
---|
137 | | - } else { |
---|
138 | | - spin_unlock(&substream->self_group.lock); |
---|
139 | | - |
---|
140 | | - switch (mode) { |
---|
141 | | - case PCM_LOCK_DEFAULT: |
---|
142 | | - read_unlock(&snd_pcm_link_rwlock); |
---|
143 | | - break; |
---|
144 | | - case PCM_LOCK_IRQ: |
---|
145 | | - read_unlock_irq(&snd_pcm_link_rwlock); |
---|
146 | | - break; |
---|
147 | | - case PCM_LOCK_IRQSAVE: |
---|
148 | | - read_unlock_irqrestore(&snd_pcm_link_rwlock, flags); |
---|
149 | | - break; |
---|
150 | | - } |
---|
151 | | - } |
---|
152 | | -} |
---|
| 95 | +DEFINE_PCM_GROUP_LOCK(lock, lock); |
---|
| 96 | +DEFINE_PCM_GROUP_LOCK(unlock, unlock); |
---|
| 97 | +DEFINE_PCM_GROUP_LOCK(lock_irq, lock); |
---|
| 98 | +DEFINE_PCM_GROUP_LOCK(unlock_irq, unlock); |
---|
153 | 99 | |
---|
154 | 100 | /** |
---|
155 | 101 | * snd_pcm_stream_lock - Lock the PCM stream |
---|
.. | .. |
---|
161 | 107 | */ |
---|
162 | 108 | void snd_pcm_stream_lock(struct snd_pcm_substream *substream) |
---|
163 | 109 | { |
---|
164 | | - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_DEFAULT); |
---|
| 110 | + snd_pcm_group_lock(&substream->self_group, substream->pcm->nonatomic); |
---|
165 | 111 | } |
---|
166 | 112 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); |
---|
167 | 113 | |
---|
168 | 114 | /** |
---|
169 | | - * snd_pcm_stream_lock - Unlock the PCM stream |
---|
| 115 | + * snd_pcm_stream_unlock - Unlock the PCM stream |
---|
170 | 116 | * @substream: PCM substream |
---|
171 | 117 | * |
---|
172 | 118 | * This unlocks the PCM stream that has been locked via snd_pcm_stream_lock(). |
---|
173 | 119 | */ |
---|
174 | 120 | void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) |
---|
175 | 121 | { |
---|
176 | | - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_DEFAULT, 0); |
---|
| 122 | + snd_pcm_group_unlock(&substream->self_group, substream->pcm->nonatomic); |
---|
177 | 123 | } |
---|
178 | 124 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); |
---|
179 | 125 | |
---|
.. | .. |
---|
187 | 133 | */ |
---|
188 | 134 | void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) |
---|
189 | 135 | { |
---|
190 | | - __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQ); |
---|
| 136 | + snd_pcm_group_lock_irq(&substream->self_group, |
---|
| 137 | + substream->pcm->nonatomic); |
---|
191 | 138 | } |
---|
192 | 139 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); |
---|
| 140 | + |
---|
| 141 | +static void snd_pcm_stream_lock_nested(struct snd_pcm_substream *substream) |
---|
| 142 | +{ |
---|
| 143 | + struct snd_pcm_group *group = &substream->self_group; |
---|
| 144 | + |
---|
| 145 | + if (substream->pcm->nonatomic) |
---|
| 146 | + mutex_lock_nested(&group->mutex, SINGLE_DEPTH_NESTING); |
---|
| 147 | + else |
---|
| 148 | + spin_lock_nested(&group->lock, SINGLE_DEPTH_NESTING); |
---|
| 149 | +} |
---|
193 | 150 | |
---|
194 | 151 | /** |
---|
195 | 152 | * snd_pcm_stream_unlock_irq - Unlock the PCM stream |
---|
.. | .. |
---|
199 | 156 | */ |
---|
200 | 157 | void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) |
---|
201 | 158 | { |
---|
202 | | - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQ, 0); |
---|
| 159 | + snd_pcm_group_unlock_irq(&substream->self_group, |
---|
| 160 | + substream->pcm->nonatomic); |
---|
203 | 161 | } |
---|
204 | 162 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); |
---|
205 | 163 | |
---|
206 | 164 | unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) |
---|
207 | 165 | { |
---|
208 | | - return __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQSAVE); |
---|
| 166 | + unsigned long flags = 0; |
---|
| 167 | + if (substream->pcm->nonatomic) |
---|
| 168 | + mutex_lock(&substream->self_group.mutex); |
---|
| 169 | + else |
---|
| 170 | + spin_lock_irqsave(&substream->self_group.lock, flags); |
---|
| 171 | + return flags; |
---|
209 | 172 | } |
---|
210 | 173 | EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); |
---|
211 | 174 | |
---|
.. | .. |
---|
219 | 182 | void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, |
---|
220 | 183 | unsigned long flags) |
---|
221 | 184 | { |
---|
222 | | - __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQSAVE, flags); |
---|
| 185 | + if (substream->pcm->nonatomic) |
---|
| 186 | + mutex_unlock(&substream->self_group.mutex); |
---|
| 187 | + else |
---|
| 188 | + spin_unlock_irqrestore(&substream->self_group.lock, flags); |
---|
223 | 189 | } |
---|
224 | 190 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); |
---|
| 191 | + |
---|
| 192 | +/* Run PCM ioctl ops */ |
---|
| 193 | +static int snd_pcm_ops_ioctl(struct snd_pcm_substream *substream, |
---|
| 194 | + unsigned cmd, void *arg) |
---|
| 195 | +{ |
---|
| 196 | + if (substream->ops->ioctl) |
---|
| 197 | + return substream->ops->ioctl(substream, cmd, arg); |
---|
| 198 | + else |
---|
| 199 | + return snd_pcm_lib_ioctl(substream, cmd, arg); |
---|
| 200 | +} |
---|
225 | 201 | |
---|
226 | 202 | int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) |
---|
227 | 203 | { |
---|
.. | .. |
---|
262 | 238 | return err; |
---|
263 | 239 | } |
---|
264 | 240 | |
---|
| 241 | +/* macro for simplified cast */ |
---|
| 242 | +#define PARAM_MASK_BIT(b) (1U << (__force int)(b)) |
---|
| 243 | + |
---|
265 | 244 | static bool hw_support_mmap(struct snd_pcm_substream *substream) |
---|
266 | 245 | { |
---|
267 | 246 | if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP)) |
---|
268 | 247 | return false; |
---|
269 | | - /* architecture supports dma_mmap_coherent()? */ |
---|
270 | | -#if defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP) || !defined(CONFIG_HAS_DMA) |
---|
271 | | - if (!substream->ops->mmap && |
---|
272 | | - substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) |
---|
273 | | - return false; |
---|
274 | | -#endif |
---|
275 | | - return true; |
---|
| 248 | + |
---|
| 249 | + if (substream->ops->mmap || substream->ops->page) |
---|
| 250 | + return true; |
---|
| 251 | + |
---|
| 252 | + switch (substream->dma_buffer.dev.type) { |
---|
| 253 | + case SNDRV_DMA_TYPE_UNKNOWN: |
---|
| 254 | + /* we can't know the device, so just assume that the driver does |
---|
| 255 | + * everything right |
---|
| 256 | + */ |
---|
| 257 | + return true; |
---|
| 258 | + case SNDRV_DMA_TYPE_CONTINUOUS: |
---|
| 259 | + case SNDRV_DMA_TYPE_VMALLOC: |
---|
| 260 | + return true; |
---|
| 261 | + default: |
---|
| 262 | + return dma_can_mmap(substream->dma_buffer.dev.dev); |
---|
| 263 | + } |
---|
276 | 264 | } |
---|
277 | 265 | |
---|
278 | 266 | static int constrain_mask_params(struct snd_pcm_substream *substream, |
---|
.. | .. |
---|
291 | 279 | return -EINVAL; |
---|
292 | 280 | |
---|
293 | 281 | /* This parameter is not requested to change by a caller. */ |
---|
294 | | - if (!(params->rmask & (1 << k))) |
---|
| 282 | + if (!(params->rmask & PARAM_MASK_BIT(k))) |
---|
295 | 283 | continue; |
---|
296 | 284 | |
---|
297 | 285 | if (trace_hw_mask_param_enabled()) |
---|
.. | .. |
---|
305 | 293 | |
---|
306 | 294 | /* Set corresponding flag so that the caller gets it. */ |
---|
307 | 295 | trace_hw_mask_param(substream, k, 0, &old_mask, m); |
---|
308 | | - params->cmask |= 1 << k; |
---|
| 296 | + params->cmask |= PARAM_MASK_BIT(k); |
---|
309 | 297 | } |
---|
310 | 298 | |
---|
311 | 299 | return 0; |
---|
.. | .. |
---|
327 | 315 | return -EINVAL; |
---|
328 | 316 | |
---|
329 | 317 | /* This parameter is not requested to change by a caller. */ |
---|
330 | | - if (!(params->rmask & (1 << k))) |
---|
| 318 | + if (!(params->rmask & PARAM_MASK_BIT(k))) |
---|
331 | 319 | continue; |
---|
332 | 320 | |
---|
333 | 321 | if (trace_hw_interval_param_enabled()) |
---|
.. | .. |
---|
341 | 329 | |
---|
342 | 330 | /* Set corresponding flag so that the caller gets it. */ |
---|
343 | 331 | trace_hw_interval_param(substream, k, 0, &old_interval, i); |
---|
344 | | - params->cmask |= 1 << k; |
---|
| 332 | + params->cmask |= PARAM_MASK_BIT(k); |
---|
345 | 333 | } |
---|
346 | 334 | |
---|
347 | 335 | return 0; |
---|
.. | .. |
---|
383 | 371 | * have 0 so that the parameters are never changed anymore. |
---|
384 | 372 | */ |
---|
385 | 373 | for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) |
---|
386 | | - vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; |
---|
| 374 | + vstamps[k] = (params->rmask & PARAM_MASK_BIT(k)) ? 1 : 0; |
---|
387 | 375 | |
---|
388 | 376 | /* Due to the above design, actual sequence number starts at 2. */ |
---|
389 | 377 | stamp = 2; |
---|
.. | .. |
---|
451 | 439 | hw_param_interval(params, r->var)); |
---|
452 | 440 | } |
---|
453 | 441 | |
---|
454 | | - params->cmask |= (1 << r->var); |
---|
| 442 | + params->cmask |= PARAM_MASK_BIT(r->var); |
---|
455 | 443 | vstamps[r->var] = stamp; |
---|
456 | 444 | again = true; |
---|
457 | 445 | } |
---|
.. | .. |
---|
493 | 481 | m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT); |
---|
494 | 482 | i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); |
---|
495 | 483 | if (snd_mask_single(m) && snd_interval_single(i)) { |
---|
496 | | - err = substream->ops->ioctl(substream, |
---|
497 | | - SNDRV_PCM_IOCTL1_FIFO_SIZE, params); |
---|
| 484 | + err = snd_pcm_ops_ioctl(substream, |
---|
| 485 | + SNDRV_PCM_IOCTL1_FIFO_SIZE, |
---|
| 486 | + params); |
---|
498 | 487 | if (err < 0) |
---|
499 | 488 | return err; |
---|
500 | 489 | } |
---|
.. | .. |
---|
519 | 508 | |
---|
520 | 509 | params->info = 0; |
---|
521 | 510 | params->fifo_size = 0; |
---|
522 | | - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) |
---|
| 511 | + if (params->rmask & PARAM_MASK_BIT(SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) |
---|
523 | 512 | params->msbits = 0; |
---|
524 | | - if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { |
---|
| 513 | + if (params->rmask & PARAM_MASK_BIT(SNDRV_PCM_HW_PARAM_RATE)) { |
---|
525 | 514 | params->rate_num = 0; |
---|
526 | 515 | params->rate_den = 0; |
---|
527 | 516 | } |
---|
.. | .. |
---|
584 | 573 | return usecs; |
---|
585 | 574 | } |
---|
586 | 575 | |
---|
587 | | -static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state) |
---|
| 576 | +static void snd_pcm_set_state(struct snd_pcm_substream *substream, |
---|
| 577 | + snd_pcm_state_t state) |
---|
588 | 578 | { |
---|
589 | 579 | snd_pcm_stream_lock_irq(substream); |
---|
590 | 580 | if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED) |
---|
.. | .. |
---|
602 | 592 | #endif |
---|
603 | 593 | } |
---|
604 | 594 | |
---|
| 595 | +void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq) |
---|
| 596 | +{ |
---|
| 597 | + if (substream->runtime && substream->runtime->stop_operating) { |
---|
| 598 | + substream->runtime->stop_operating = false; |
---|
| 599 | + if (substream->ops && substream->ops->sync_stop) |
---|
| 600 | + substream->ops->sync_stop(substream); |
---|
| 601 | + else if (sync_irq && substream->pcm->card->sync_irq > 0) |
---|
| 602 | + synchronize_irq(substream->pcm->card->sync_irq); |
---|
| 603 | + } |
---|
| 604 | +} |
---|
| 605 | + |
---|
605 | 606 | /** |
---|
606 | | - * snd_pcm_hw_param_choose - choose a configuration defined by @params |
---|
| 607 | + * snd_pcm_hw_params_choose - choose a configuration defined by @params |
---|
607 | 608 | * @pcm: PCM instance |
---|
608 | 609 | * @params: the hw_params instance |
---|
609 | 610 | * |
---|
.. | .. |
---|
666 | 667 | return 0; |
---|
667 | 668 | } |
---|
668 | 669 | |
---|
| 670 | +/* acquire buffer_mutex; if it's in r/w operation, return -EBUSY, otherwise |
---|
| 671 | + * block the further r/w operations |
---|
| 672 | + */ |
---|
| 673 | +static int snd_pcm_buffer_access_lock(struct snd_pcm_runtime *runtime) |
---|
| 674 | +{ |
---|
| 675 | + if (!atomic_dec_unless_positive(&runtime->buffer_accessing)) |
---|
| 676 | + return -EBUSY; |
---|
| 677 | + mutex_lock(&runtime->buffer_mutex); |
---|
| 678 | + return 0; /* keep buffer_mutex, unlocked by below */ |
---|
| 679 | +} |
---|
| 680 | + |
---|
| 681 | +/* release buffer_mutex and clear r/w access flag */ |
---|
| 682 | +static void snd_pcm_buffer_access_unlock(struct snd_pcm_runtime *runtime) |
---|
| 683 | +{ |
---|
| 684 | + mutex_unlock(&runtime->buffer_mutex); |
---|
| 685 | + atomic_inc(&runtime->buffer_accessing); |
---|
| 686 | +} |
---|
| 687 | + |
---|
| 688 | +#if IS_ENABLED(CONFIG_SND_PCM_OSS) |
---|
| 689 | +#define is_oss_stream(substream) ((substream)->oss.oss) |
---|
| 690 | +#else |
---|
| 691 | +#define is_oss_stream(substream) false |
---|
| 692 | +#endif |
---|
| 693 | + |
---|
669 | 694 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, |
---|
670 | 695 | struct snd_pcm_hw_params *params) |
---|
671 | 696 | { |
---|
.. | .. |
---|
677 | 702 | if (PCM_RUNTIME_CHECK(substream)) |
---|
678 | 703 | return -ENXIO; |
---|
679 | 704 | runtime = substream->runtime; |
---|
| 705 | + err = snd_pcm_buffer_access_lock(runtime); |
---|
| 706 | + if (err < 0) |
---|
| 707 | + return err; |
---|
680 | 708 | snd_pcm_stream_lock_irq(substream); |
---|
681 | 709 | switch (runtime->status->state) { |
---|
682 | 710 | case SNDRV_PCM_STATE_OPEN: |
---|
683 | 711 | case SNDRV_PCM_STATE_SETUP: |
---|
684 | 712 | case SNDRV_PCM_STATE_PREPARED: |
---|
| 713 | + if (!is_oss_stream(substream) && |
---|
| 714 | + atomic_read(&substream->mmap_count)) |
---|
| 715 | + err = -EBADFD; |
---|
685 | 716 | break; |
---|
686 | 717 | default: |
---|
687 | | - snd_pcm_stream_unlock_irq(substream); |
---|
688 | | - return -EBADFD; |
---|
| 718 | + err = -EBADFD; |
---|
| 719 | + break; |
---|
689 | 720 | } |
---|
690 | 721 | snd_pcm_stream_unlock_irq(substream); |
---|
691 | | -#if IS_ENABLED(CONFIG_SND_PCM_OSS) |
---|
692 | | - if (!substream->oss.oss) |
---|
693 | | -#endif |
---|
694 | | - if (atomic_read(&substream->mmap_count)) |
---|
695 | | - return -EBADFD; |
---|
| 722 | + if (err) |
---|
| 723 | + goto unlock; |
---|
| 724 | + |
---|
| 725 | + snd_pcm_sync_stop(substream, true); |
---|
696 | 726 | |
---|
697 | 727 | params->rmask = ~0U; |
---|
698 | 728 | err = snd_pcm_hw_refine(substream, params); |
---|
.. | .. |
---|
706 | 736 | err = fixup_unreferenced_params(substream, params); |
---|
707 | 737 | if (err < 0) |
---|
708 | 738 | goto _error; |
---|
| 739 | + |
---|
| 740 | + if (substream->managed_buffer_alloc) { |
---|
| 741 | + err = snd_pcm_lib_malloc_pages(substream, |
---|
| 742 | + params_buffer_bytes(params)); |
---|
| 743 | + if (err < 0) |
---|
| 744 | + goto _error; |
---|
| 745 | + runtime->buffer_changed = err > 0; |
---|
| 746 | + } |
---|
709 | 747 | |
---|
710 | 748 | if (substream->ops->hw_params != NULL) { |
---|
711 | 749 | err = substream->ops->hw_params(substream, params); |
---|
.. | .. |
---|
764 | 802 | snd_pcm_timer_resolution_change(substream); |
---|
765 | 803 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP); |
---|
766 | 804 | |
---|
767 | | - if (pm_qos_request_active(&substream->latency_pm_qos_req)) |
---|
768 | | - pm_qos_remove_request(&substream->latency_pm_qos_req); |
---|
| 805 | + if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req)) |
---|
| 806 | + cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); |
---|
769 | 807 | if ((usecs = period_to_usecs(runtime)) >= 0) |
---|
770 | | - pm_qos_add_request(&substream->latency_pm_qos_req, |
---|
771 | | - PM_QOS_CPU_DMA_LATENCY, usecs); |
---|
772 | | - return 0; |
---|
| 808 | + cpu_latency_qos_add_request(&substream->latency_pm_qos_req, |
---|
| 809 | + usecs); |
---|
| 810 | + err = 0; |
---|
773 | 811 | _error: |
---|
774 | | - /* hardware might be unusable from this time, |
---|
775 | | - so we force application to retry to set |
---|
776 | | - the correct hardware parameter settings */ |
---|
777 | | - snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); |
---|
778 | | - if (substream->ops->hw_free != NULL) |
---|
779 | | - substream->ops->hw_free(substream); |
---|
| 812 | + if (err) { |
---|
| 813 | + /* hardware might be unusable from this time, |
---|
| 814 | + * so we force application to retry to set |
---|
| 815 | + * the correct hardware parameter settings |
---|
| 816 | + */ |
---|
| 817 | + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); |
---|
| 818 | + if (substream->ops->hw_free != NULL) |
---|
| 819 | + substream->ops->hw_free(substream); |
---|
| 820 | + if (substream->managed_buffer_alloc) |
---|
| 821 | + snd_pcm_lib_free_pages(substream); |
---|
| 822 | + } |
---|
| 823 | + unlock: |
---|
| 824 | + snd_pcm_buffer_access_unlock(runtime); |
---|
780 | 825 | return err; |
---|
781 | 826 | } |
---|
782 | 827 | |
---|
.. | .. |
---|
801 | 846 | return err; |
---|
802 | 847 | } |
---|
803 | 848 | |
---|
| 849 | +static int do_hw_free(struct snd_pcm_substream *substream) |
---|
| 850 | +{ |
---|
| 851 | + int result = 0; |
---|
| 852 | + |
---|
| 853 | + snd_pcm_sync_stop(substream, true); |
---|
| 854 | + if (substream->ops->hw_free) |
---|
| 855 | + result = substream->ops->hw_free(substream); |
---|
| 856 | + if (substream->managed_buffer_alloc) |
---|
| 857 | + snd_pcm_lib_free_pages(substream); |
---|
| 858 | + return result; |
---|
| 859 | +} |
---|
| 860 | + |
---|
804 | 861 | static int snd_pcm_hw_free(struct snd_pcm_substream *substream) |
---|
805 | 862 | { |
---|
806 | 863 | struct snd_pcm_runtime *runtime; |
---|
.. | .. |
---|
809 | 866 | if (PCM_RUNTIME_CHECK(substream)) |
---|
810 | 867 | return -ENXIO; |
---|
811 | 868 | runtime = substream->runtime; |
---|
| 869 | + result = snd_pcm_buffer_access_lock(runtime); |
---|
| 870 | + if (result < 0) |
---|
| 871 | + return result; |
---|
812 | 872 | snd_pcm_stream_lock_irq(substream); |
---|
813 | 873 | switch (runtime->status->state) { |
---|
814 | 874 | case SNDRV_PCM_STATE_SETUP: |
---|
815 | 875 | case SNDRV_PCM_STATE_PREPARED: |
---|
| 876 | + if (atomic_read(&substream->mmap_count)) |
---|
| 877 | + result = -EBADFD; |
---|
816 | 878 | break; |
---|
817 | 879 | default: |
---|
818 | | - snd_pcm_stream_unlock_irq(substream); |
---|
819 | | - return -EBADFD; |
---|
| 880 | + result = -EBADFD; |
---|
| 881 | + break; |
---|
820 | 882 | } |
---|
821 | 883 | snd_pcm_stream_unlock_irq(substream); |
---|
822 | | - if (atomic_read(&substream->mmap_count)) |
---|
823 | | - return -EBADFD; |
---|
824 | | - if (substream->ops->hw_free) |
---|
825 | | - result = substream->ops->hw_free(substream); |
---|
| 884 | + if (result) |
---|
| 885 | + goto unlock; |
---|
| 886 | + result = do_hw_free(substream); |
---|
826 | 887 | snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); |
---|
827 | | - pm_qos_remove_request(&substream->latency_pm_qos_req); |
---|
| 888 | + cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); |
---|
| 889 | + unlock: |
---|
| 890 | + snd_pcm_buffer_access_unlock(runtime); |
---|
828 | 891 | return result; |
---|
829 | 892 | } |
---|
830 | 893 | |
---|
.. | .. |
---|
908 | 971 | return delay + substream->runtime->delay; |
---|
909 | 972 | } |
---|
910 | 973 | |
---|
911 | | -int snd_pcm_status(struct snd_pcm_substream *substream, |
---|
912 | | - struct snd_pcm_status *status) |
---|
| 974 | +int snd_pcm_status64(struct snd_pcm_substream *substream, |
---|
| 975 | + struct snd_pcm_status64 *status) |
---|
913 | 976 | { |
---|
914 | 977 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
915 | 978 | |
---|
.. | .. |
---|
935 | 998 | status->suspended_state = runtime->status->suspended_state; |
---|
936 | 999 | if (status->state == SNDRV_PCM_STATE_OPEN) |
---|
937 | 1000 | goto _end; |
---|
938 | | - status->trigger_tstamp = runtime->trigger_tstamp; |
---|
| 1001 | + status->trigger_tstamp_sec = runtime->trigger_tstamp.tv_sec; |
---|
| 1002 | + status->trigger_tstamp_nsec = runtime->trigger_tstamp.tv_nsec; |
---|
939 | 1003 | if (snd_pcm_running(substream)) { |
---|
940 | 1004 | snd_pcm_update_hw_ptr(substream); |
---|
941 | 1005 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { |
---|
942 | | - status->tstamp = runtime->status->tstamp; |
---|
943 | | - status->driver_tstamp = runtime->driver_tstamp; |
---|
944 | | - status->audio_tstamp = |
---|
945 | | - runtime->status->audio_tstamp; |
---|
| 1006 | + status->tstamp_sec = runtime->status->tstamp.tv_sec; |
---|
| 1007 | + status->tstamp_nsec = |
---|
| 1008 | + runtime->status->tstamp.tv_nsec; |
---|
| 1009 | + status->driver_tstamp_sec = |
---|
| 1010 | + runtime->driver_tstamp.tv_sec; |
---|
| 1011 | + status->driver_tstamp_nsec = |
---|
| 1012 | + runtime->driver_tstamp.tv_nsec; |
---|
| 1013 | + status->audio_tstamp_sec = |
---|
| 1014 | + runtime->status->audio_tstamp.tv_sec; |
---|
| 1015 | + status->audio_tstamp_nsec = |
---|
| 1016 | + runtime->status->audio_tstamp.tv_nsec; |
---|
946 | 1017 | if (runtime->audio_tstamp_report.valid == 1) |
---|
947 | 1018 | /* backwards compatibility, no report provided in COMPAT mode */ |
---|
948 | 1019 | snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data, |
---|
.. | .. |
---|
953 | 1024 | } |
---|
954 | 1025 | } else { |
---|
955 | 1026 | /* get tstamp only in fallback mode and only if enabled */ |
---|
956 | | - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
---|
957 | | - snd_pcm_gettime(runtime, &status->tstamp); |
---|
| 1027 | + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { |
---|
| 1028 | + struct timespec64 tstamp; |
---|
| 1029 | + |
---|
| 1030 | + snd_pcm_gettime(runtime, &tstamp); |
---|
| 1031 | + status->tstamp_sec = tstamp.tv_sec; |
---|
| 1032 | + status->tstamp_nsec = tstamp.tv_nsec; |
---|
| 1033 | + } |
---|
958 | 1034 | } |
---|
959 | 1035 | _tstamp_end: |
---|
960 | 1036 | status->appl_ptr = runtime->control->appl_ptr; |
---|
.. | .. |
---|
971 | 1047 | return 0; |
---|
972 | 1048 | } |
---|
973 | 1049 | |
---|
974 | | -static int snd_pcm_status_user(struct snd_pcm_substream *substream, |
---|
975 | | - struct snd_pcm_status __user * _status, |
---|
976 | | - bool ext) |
---|
| 1050 | +static int snd_pcm_status_user64(struct snd_pcm_substream *substream, |
---|
| 1051 | + struct snd_pcm_status64 __user * _status, |
---|
| 1052 | + bool ext) |
---|
977 | 1053 | { |
---|
978 | | - struct snd_pcm_status status; |
---|
| 1054 | + struct snd_pcm_status64 status; |
---|
979 | 1055 | int res; |
---|
980 | 1056 | |
---|
981 | 1057 | memset(&status, 0, sizeof(status)); |
---|
.. | .. |
---|
987 | 1063 | if (ext && get_user(status.audio_tstamp_data, |
---|
988 | 1064 | (u32 __user *)(&_status->audio_tstamp_data))) |
---|
989 | 1065 | return -EFAULT; |
---|
990 | | - res = snd_pcm_status(substream, &status); |
---|
| 1066 | + res = snd_pcm_status64(substream, &status); |
---|
991 | 1067 | if (res < 0) |
---|
992 | 1068 | return res; |
---|
993 | 1069 | if (copy_to_user(_status, &status, sizeof(status))) |
---|
994 | 1070 | return -EFAULT; |
---|
| 1071 | + return 0; |
---|
| 1072 | +} |
---|
| 1073 | + |
---|
| 1074 | +static int snd_pcm_status_user32(struct snd_pcm_substream *substream, |
---|
| 1075 | + struct snd_pcm_status32 __user * _status, |
---|
| 1076 | + bool ext) |
---|
| 1077 | +{ |
---|
| 1078 | + struct snd_pcm_status64 status64; |
---|
| 1079 | + struct snd_pcm_status32 status32; |
---|
| 1080 | + int res; |
---|
| 1081 | + |
---|
| 1082 | + memset(&status64, 0, sizeof(status64)); |
---|
| 1083 | + memset(&status32, 0, sizeof(status32)); |
---|
| 1084 | + /* |
---|
| 1085 | + * with extension, parameters are read/write, |
---|
| 1086 | + * get audio_tstamp_data from user, |
---|
| 1087 | + * ignore rest of status structure |
---|
| 1088 | + */ |
---|
| 1089 | + if (ext && get_user(status64.audio_tstamp_data, |
---|
| 1090 | + (u32 __user *)(&_status->audio_tstamp_data))) |
---|
| 1091 | + return -EFAULT; |
---|
| 1092 | + res = snd_pcm_status64(substream, &status64); |
---|
| 1093 | + if (res < 0) |
---|
| 1094 | + return res; |
---|
| 1095 | + |
---|
| 1096 | + status32 = (struct snd_pcm_status32) { |
---|
| 1097 | + .state = status64.state, |
---|
| 1098 | + .trigger_tstamp_sec = status64.trigger_tstamp_sec, |
---|
| 1099 | + .trigger_tstamp_nsec = status64.trigger_tstamp_nsec, |
---|
| 1100 | + .tstamp_sec = status64.tstamp_sec, |
---|
| 1101 | + .tstamp_nsec = status64.tstamp_nsec, |
---|
| 1102 | + .appl_ptr = status64.appl_ptr, |
---|
| 1103 | + .hw_ptr = status64.hw_ptr, |
---|
| 1104 | + .delay = status64.delay, |
---|
| 1105 | + .avail = status64.avail, |
---|
| 1106 | + .avail_max = status64.avail_max, |
---|
| 1107 | + .overrange = status64.overrange, |
---|
| 1108 | + .suspended_state = status64.suspended_state, |
---|
| 1109 | + .audio_tstamp_data = status64.audio_tstamp_data, |
---|
| 1110 | + .audio_tstamp_sec = status64.audio_tstamp_sec, |
---|
| 1111 | + .audio_tstamp_nsec = status64.audio_tstamp_nsec, |
---|
| 1112 | + .driver_tstamp_sec = status64.audio_tstamp_sec, |
---|
| 1113 | + .driver_tstamp_nsec = status64.audio_tstamp_nsec, |
---|
| 1114 | + .audio_tstamp_accuracy = status64.audio_tstamp_accuracy, |
---|
| 1115 | + }; |
---|
| 1116 | + |
---|
| 1117 | + if (copy_to_user(_status, &status32, sizeof(status32))) |
---|
| 1118 | + return -EFAULT; |
---|
| 1119 | + |
---|
995 | 1120 | return 0; |
---|
996 | 1121 | } |
---|
997 | 1122 | |
---|
.. | .. |
---|
1013 | 1138 | return -EINVAL; |
---|
1014 | 1139 | memset(info, 0, sizeof(*info)); |
---|
1015 | 1140 | info->channel = channel; |
---|
1016 | | - return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); |
---|
| 1141 | + return snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); |
---|
1017 | 1142 | } |
---|
1018 | 1143 | |
---|
1019 | 1144 | static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream, |
---|
.. | .. |
---|
1047 | 1172 | runtime->trigger_master = NULL; |
---|
1048 | 1173 | } |
---|
1049 | 1174 | |
---|
| 1175 | +#define ACTION_ARG_IGNORE (__force snd_pcm_state_t)0 |
---|
| 1176 | + |
---|
1050 | 1177 | struct action_ops { |
---|
1051 | | - int (*pre_action)(struct snd_pcm_substream *substream, int state); |
---|
1052 | | - int (*do_action)(struct snd_pcm_substream *substream, int state); |
---|
1053 | | - void (*undo_action)(struct snd_pcm_substream *substream, int state); |
---|
1054 | | - void (*post_action)(struct snd_pcm_substream *substream, int state); |
---|
| 1178 | + int (*pre_action)(struct snd_pcm_substream *substream, |
---|
| 1179 | + snd_pcm_state_t state); |
---|
| 1180 | + int (*do_action)(struct snd_pcm_substream *substream, |
---|
| 1181 | + snd_pcm_state_t state); |
---|
| 1182 | + void (*undo_action)(struct snd_pcm_substream *substream, |
---|
| 1183 | + snd_pcm_state_t state); |
---|
| 1184 | + void (*post_action)(struct snd_pcm_substream *substream, |
---|
| 1185 | + snd_pcm_state_t state); |
---|
1055 | 1186 | }; |
---|
1056 | 1187 | |
---|
1057 | 1188 | /* |
---|
.. | .. |
---|
1061 | 1192 | */ |
---|
1062 | 1193 | static int snd_pcm_action_group(const struct action_ops *ops, |
---|
1063 | 1194 | struct snd_pcm_substream *substream, |
---|
1064 | | - int state, int do_lock) |
---|
| 1195 | + snd_pcm_state_t state, |
---|
| 1196 | + bool stream_lock) |
---|
1065 | 1197 | { |
---|
1066 | 1198 | struct snd_pcm_substream *s = NULL; |
---|
1067 | 1199 | struct snd_pcm_substream *s1; |
---|
1068 | 1200 | int res = 0, depth = 1; |
---|
1069 | 1201 | |
---|
1070 | 1202 | snd_pcm_group_for_each_entry(s, substream) { |
---|
1071 | | - if (do_lock && s != substream) { |
---|
1072 | | - if (s->pcm->nonatomic) |
---|
| 1203 | + if (s != substream) { |
---|
| 1204 | + if (!stream_lock) |
---|
| 1205 | + mutex_lock_nested(&s->runtime->buffer_mutex, depth); |
---|
| 1206 | + else if (s->pcm->nonatomic) |
---|
1073 | 1207 | mutex_lock_nested(&s->self_group.mutex, depth); |
---|
1074 | 1208 | else |
---|
1075 | 1209 | spin_lock_nested(&s->self_group.lock, depth); |
---|
.. | .. |
---|
1097 | 1231 | ops->post_action(s, state); |
---|
1098 | 1232 | } |
---|
1099 | 1233 | _unlock: |
---|
1100 | | - if (do_lock) { |
---|
1101 | | - /* unlock streams */ |
---|
1102 | | - snd_pcm_group_for_each_entry(s1, substream) { |
---|
1103 | | - if (s1 != substream) { |
---|
1104 | | - if (s1->pcm->nonatomic) |
---|
1105 | | - mutex_unlock(&s1->self_group.mutex); |
---|
1106 | | - else |
---|
1107 | | - spin_unlock(&s1->self_group.lock); |
---|
1108 | | - } |
---|
1109 | | - if (s1 == s) /* end */ |
---|
1110 | | - break; |
---|
| 1234 | + /* unlock streams */ |
---|
| 1235 | + snd_pcm_group_for_each_entry(s1, substream) { |
---|
| 1236 | + if (s1 != substream) { |
---|
| 1237 | + if (!stream_lock) |
---|
| 1238 | + mutex_unlock(&s1->runtime->buffer_mutex); |
---|
| 1239 | + else if (s1->pcm->nonatomic) |
---|
| 1240 | + mutex_unlock(&s1->self_group.mutex); |
---|
| 1241 | + else |
---|
| 1242 | + spin_unlock(&s1->self_group.lock); |
---|
1111 | 1243 | } |
---|
| 1244 | + if (s1 == s) /* end */ |
---|
| 1245 | + break; |
---|
1112 | 1246 | } |
---|
1113 | 1247 | return res; |
---|
1114 | 1248 | } |
---|
.. | .. |
---|
1118 | 1252 | */ |
---|
1119 | 1253 | static int snd_pcm_action_single(const struct action_ops *ops, |
---|
1120 | 1254 | struct snd_pcm_substream *substream, |
---|
1121 | | - int state) |
---|
| 1255 | + snd_pcm_state_t state) |
---|
1122 | 1256 | { |
---|
1123 | 1257 | int res; |
---|
1124 | 1258 | |
---|
.. | .. |
---|
1133 | 1267 | return res; |
---|
1134 | 1268 | } |
---|
1135 | 1269 | |
---|
| 1270 | +static void snd_pcm_group_assign(struct snd_pcm_substream *substream, |
---|
| 1271 | + struct snd_pcm_group *new_group) |
---|
| 1272 | +{ |
---|
| 1273 | + substream->group = new_group; |
---|
| 1274 | + list_move(&substream->link_list, &new_group->substreams); |
---|
| 1275 | +} |
---|
| 1276 | + |
---|
| 1277 | +/* |
---|
| 1278 | + * Unref and unlock the group, but keep the stream lock; |
---|
| 1279 | + * when the group becomes empty and no longer referred, destroy itself |
---|
| 1280 | + */ |
---|
| 1281 | +static void snd_pcm_group_unref(struct snd_pcm_group *group, |
---|
| 1282 | + struct snd_pcm_substream *substream) |
---|
| 1283 | +{ |
---|
| 1284 | + bool do_free; |
---|
| 1285 | + |
---|
| 1286 | + if (!group) |
---|
| 1287 | + return; |
---|
| 1288 | + do_free = refcount_dec_and_test(&group->refs); |
---|
| 1289 | + snd_pcm_group_unlock(group, substream->pcm->nonatomic); |
---|
| 1290 | + if (do_free) |
---|
| 1291 | + kfree(group); |
---|
| 1292 | +} |
---|
| 1293 | + |
---|
| 1294 | +/* |
---|
| 1295 | + * Lock the group inside a stream lock and reference it; |
---|
| 1296 | + * return the locked group object, or NULL if not linked |
---|
| 1297 | + */ |
---|
| 1298 | +static struct snd_pcm_group * |
---|
| 1299 | +snd_pcm_stream_group_ref(struct snd_pcm_substream *substream) |
---|
| 1300 | +{ |
---|
| 1301 | + bool nonatomic = substream->pcm->nonatomic; |
---|
| 1302 | + struct snd_pcm_group *group; |
---|
| 1303 | + bool trylock; |
---|
| 1304 | + |
---|
| 1305 | + for (;;) { |
---|
| 1306 | + if (!snd_pcm_stream_linked(substream)) |
---|
| 1307 | + return NULL; |
---|
| 1308 | + group = substream->group; |
---|
| 1309 | + /* block freeing the group object */ |
---|
| 1310 | + refcount_inc(&group->refs); |
---|
| 1311 | + |
---|
| 1312 | + trylock = nonatomic ? mutex_trylock(&group->mutex) : |
---|
| 1313 | + spin_trylock(&group->lock); |
---|
| 1314 | + if (trylock) |
---|
| 1315 | + break; /* OK */ |
---|
| 1316 | + |
---|
| 1317 | + /* re-lock for avoiding ABBA deadlock */ |
---|
| 1318 | + snd_pcm_stream_unlock(substream); |
---|
| 1319 | + snd_pcm_group_lock(group, nonatomic); |
---|
| 1320 | + snd_pcm_stream_lock(substream); |
---|
| 1321 | + |
---|
| 1322 | + /* check the group again; the above opens a small race window */ |
---|
| 1323 | + if (substream->group == group) |
---|
| 1324 | + break; /* OK */ |
---|
| 1325 | + /* group changed, try again */ |
---|
| 1326 | + snd_pcm_group_unref(group, substream); |
---|
| 1327 | + } |
---|
| 1328 | + return group; |
---|
| 1329 | +} |
---|
| 1330 | + |
---|
1136 | 1331 | /* |
---|
1137 | 1332 | * Note: call with stream lock |
---|
1138 | 1333 | */ |
---|
1139 | 1334 | static int snd_pcm_action(const struct action_ops *ops, |
---|
1140 | 1335 | struct snd_pcm_substream *substream, |
---|
1141 | | - int state) |
---|
| 1336 | + snd_pcm_state_t state) |
---|
1142 | 1337 | { |
---|
| 1338 | + struct snd_pcm_group *group; |
---|
1143 | 1339 | int res; |
---|
1144 | 1340 | |
---|
1145 | | - if (!snd_pcm_stream_linked(substream)) |
---|
1146 | | - return snd_pcm_action_single(ops, substream, state); |
---|
1147 | | - |
---|
1148 | | - if (substream->pcm->nonatomic) { |
---|
1149 | | - if (!mutex_trylock(&substream->group->mutex)) { |
---|
1150 | | - mutex_unlock(&substream->self_group.mutex); |
---|
1151 | | - mutex_lock(&substream->group->mutex); |
---|
1152 | | - mutex_lock(&substream->self_group.mutex); |
---|
1153 | | - } |
---|
1154 | | - res = snd_pcm_action_group(ops, substream, state, 1); |
---|
1155 | | - mutex_unlock(&substream->group->mutex); |
---|
1156 | | - } else { |
---|
1157 | | - if (!spin_trylock(&substream->group->lock)) { |
---|
1158 | | - spin_unlock(&substream->self_group.lock); |
---|
1159 | | - spin_lock(&substream->group->lock); |
---|
1160 | | - spin_lock(&substream->self_group.lock); |
---|
1161 | | - } |
---|
1162 | | - res = snd_pcm_action_group(ops, substream, state, 1); |
---|
1163 | | - spin_unlock(&substream->group->lock); |
---|
1164 | | - } |
---|
| 1341 | + group = snd_pcm_stream_group_ref(substream); |
---|
| 1342 | + if (group) |
---|
| 1343 | + res = snd_pcm_action_group(ops, substream, state, true); |
---|
| 1344 | + else |
---|
| 1345 | + res = snd_pcm_action_single(ops, substream, state); |
---|
| 1346 | + snd_pcm_group_unref(group, substream); |
---|
1165 | 1347 | return res; |
---|
1166 | 1348 | } |
---|
1167 | 1349 | |
---|
.. | .. |
---|
1170 | 1352 | */ |
---|
1171 | 1353 | static int snd_pcm_action_lock_irq(const struct action_ops *ops, |
---|
1172 | 1354 | struct snd_pcm_substream *substream, |
---|
1173 | | - int state) |
---|
| 1355 | + snd_pcm_state_t state) |
---|
1174 | 1356 | { |
---|
1175 | 1357 | int res; |
---|
1176 | 1358 | |
---|
.. | .. |
---|
1184 | 1366 | */ |
---|
1185 | 1367 | static int snd_pcm_action_nonatomic(const struct action_ops *ops, |
---|
1186 | 1368 | struct snd_pcm_substream *substream, |
---|
1187 | | - int state) |
---|
| 1369 | + snd_pcm_state_t state) |
---|
1188 | 1370 | { |
---|
1189 | 1371 | int res; |
---|
1190 | 1372 | |
---|
| 1373 | + /* Guarantee the group members won't change during non-atomic action */ |
---|
1191 | 1374 | down_read(&snd_pcm_link_rwsem); |
---|
| 1375 | + res = snd_pcm_buffer_access_lock(substream->runtime); |
---|
| 1376 | + if (res < 0) |
---|
| 1377 | + goto unlock; |
---|
1192 | 1378 | if (snd_pcm_stream_linked(substream)) |
---|
1193 | | - res = snd_pcm_action_group(ops, substream, state, 0); |
---|
| 1379 | + res = snd_pcm_action_group(ops, substream, state, false); |
---|
1194 | 1380 | else |
---|
1195 | 1381 | res = snd_pcm_action_single(ops, substream, state); |
---|
| 1382 | + snd_pcm_buffer_access_unlock(substream->runtime); |
---|
| 1383 | + unlock: |
---|
1196 | 1384 | up_read(&snd_pcm_link_rwsem); |
---|
1197 | 1385 | return res; |
---|
1198 | 1386 | } |
---|
.. | .. |
---|
1200 | 1388 | /* |
---|
1201 | 1389 | * start callbacks |
---|
1202 | 1390 | */ |
---|
1203 | | -static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state) |
---|
| 1391 | +static int snd_pcm_pre_start(struct snd_pcm_substream *substream, |
---|
| 1392 | + snd_pcm_state_t state) |
---|
1204 | 1393 | { |
---|
1205 | 1394 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1206 | 1395 | if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) |
---|
.. | .. |
---|
1213 | 1402 | return 0; |
---|
1214 | 1403 | } |
---|
1215 | 1404 | |
---|
1216 | | -static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state) |
---|
| 1405 | +static int snd_pcm_do_start(struct snd_pcm_substream *substream, |
---|
| 1406 | + snd_pcm_state_t state) |
---|
1217 | 1407 | { |
---|
1218 | 1408 | if (substream->runtime->trigger_master != substream) |
---|
1219 | 1409 | return 0; |
---|
1220 | 1410 | return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); |
---|
1221 | 1411 | } |
---|
1222 | 1412 | |
---|
1223 | | -static void snd_pcm_undo_start(struct snd_pcm_substream *substream, int state) |
---|
| 1413 | +static void snd_pcm_undo_start(struct snd_pcm_substream *substream, |
---|
| 1414 | + snd_pcm_state_t state) |
---|
1224 | 1415 | { |
---|
1225 | | - if (substream->runtime->trigger_master == substream) |
---|
| 1416 | + if (substream->runtime->trigger_master == substream) { |
---|
1226 | 1417 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); |
---|
| 1418 | + substream->runtime->stop_operating = true; |
---|
| 1419 | + } |
---|
1227 | 1420 | } |
---|
1228 | 1421 | |
---|
1229 | | -static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state) |
---|
| 1422 | +static void snd_pcm_post_start(struct snd_pcm_substream *substream, |
---|
| 1423 | + snd_pcm_state_t state) |
---|
1230 | 1424 | { |
---|
1231 | 1425 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1232 | 1426 | snd_pcm_trigger_tstamp(substream); |
---|
.. | .. |
---|
1270 | 1464 | /* |
---|
1271 | 1465 | * stop callbacks |
---|
1272 | 1466 | */ |
---|
1273 | | -static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state) |
---|
| 1467 | +static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, |
---|
| 1468 | + snd_pcm_state_t state) |
---|
1274 | 1469 | { |
---|
1275 | 1470 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1276 | 1471 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) |
---|
.. | .. |
---|
1279 | 1474 | return 0; |
---|
1280 | 1475 | } |
---|
1281 | 1476 | |
---|
1282 | | -static int snd_pcm_do_stop(struct snd_pcm_substream *substream, int state) |
---|
| 1477 | +static int snd_pcm_do_stop(struct snd_pcm_substream *substream, |
---|
| 1478 | + snd_pcm_state_t state) |
---|
1283 | 1479 | { |
---|
1284 | 1480 | if (substream->runtime->trigger_master == substream && |
---|
1285 | | - snd_pcm_running(substream)) |
---|
| 1481 | + snd_pcm_running(substream)) { |
---|
1286 | 1482 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); |
---|
| 1483 | + substream->runtime->stop_operating = true; |
---|
| 1484 | + } |
---|
1287 | 1485 | return 0; /* unconditonally stop all substreams */ |
---|
1288 | 1486 | } |
---|
1289 | 1487 | |
---|
1290 | | -static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) |
---|
| 1488 | +static void snd_pcm_post_stop(struct snd_pcm_substream *substream, |
---|
| 1489 | + snd_pcm_state_t state) |
---|
1291 | 1490 | { |
---|
1292 | 1491 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1293 | 1492 | if (runtime->status->state != state) { |
---|
.. | .. |
---|
1357 | 1556 | EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun); |
---|
1358 | 1557 | |
---|
1359 | 1558 | /* |
---|
1360 | | - * pause callbacks |
---|
| 1559 | + * pause callbacks: pass boolean (to start pause or resume) as state argument |
---|
1361 | 1560 | */ |
---|
1362 | | -static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push) |
---|
| 1561 | +#define pause_pushed(state) (__force bool)(state) |
---|
| 1562 | + |
---|
| 1563 | +static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, |
---|
| 1564 | + snd_pcm_state_t state) |
---|
1363 | 1565 | { |
---|
1364 | 1566 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1365 | 1567 | if (!(runtime->info & SNDRV_PCM_INFO_PAUSE)) |
---|
1366 | 1568 | return -ENOSYS; |
---|
1367 | | - if (push) { |
---|
| 1569 | + if (pause_pushed(state)) { |
---|
1368 | 1570 | if (runtime->status->state != SNDRV_PCM_STATE_RUNNING) |
---|
1369 | 1571 | return -EBADFD; |
---|
1370 | 1572 | } else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED) |
---|
.. | .. |
---|
1373 | 1575 | return 0; |
---|
1374 | 1576 | } |
---|
1375 | 1577 | |
---|
1376 | | -static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push) |
---|
| 1578 | +static int snd_pcm_do_pause(struct snd_pcm_substream *substream, |
---|
| 1579 | + snd_pcm_state_t state) |
---|
1377 | 1580 | { |
---|
1378 | 1581 | if (substream->runtime->trigger_master != substream) |
---|
1379 | 1582 | return 0; |
---|
1380 | 1583 | /* some drivers might use hw_ptr to recover from the pause - |
---|
1381 | 1584 | update the hw_ptr now */ |
---|
1382 | | - if (push) |
---|
| 1585 | + if (pause_pushed(state)) |
---|
1383 | 1586 | snd_pcm_update_hw_ptr(substream); |
---|
1384 | 1587 | /* The jiffies check in snd_pcm_update_hw_ptr*() is done by |
---|
1385 | 1588 | * a delta between the current jiffies, this gives a large enough |
---|
.. | .. |
---|
1387 | 1590 | */ |
---|
1388 | 1591 | substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000; |
---|
1389 | 1592 | return substream->ops->trigger(substream, |
---|
1390 | | - push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH : |
---|
1391 | | - SNDRV_PCM_TRIGGER_PAUSE_RELEASE); |
---|
| 1593 | + pause_pushed(state) ? |
---|
| 1594 | + SNDRV_PCM_TRIGGER_PAUSE_PUSH : |
---|
| 1595 | + SNDRV_PCM_TRIGGER_PAUSE_RELEASE); |
---|
1392 | 1596 | } |
---|
1393 | 1597 | |
---|
1394 | | -static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push) |
---|
| 1598 | +static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, |
---|
| 1599 | + snd_pcm_state_t state) |
---|
1395 | 1600 | { |
---|
1396 | 1601 | if (substream->runtime->trigger_master == substream) |
---|
1397 | 1602 | substream->ops->trigger(substream, |
---|
1398 | | - push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE : |
---|
| 1603 | + pause_pushed(state) ? |
---|
| 1604 | + SNDRV_PCM_TRIGGER_PAUSE_RELEASE : |
---|
1399 | 1605 | SNDRV_PCM_TRIGGER_PAUSE_PUSH); |
---|
1400 | 1606 | } |
---|
1401 | 1607 | |
---|
1402 | | -static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) |
---|
| 1608 | +static void snd_pcm_post_pause(struct snd_pcm_substream *substream, |
---|
| 1609 | + snd_pcm_state_t state) |
---|
1403 | 1610 | { |
---|
1404 | 1611 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1405 | 1612 | snd_pcm_trigger_tstamp(substream); |
---|
1406 | | - if (push) { |
---|
| 1613 | + if (pause_pushed(state)) { |
---|
1407 | 1614 | runtime->status->state = SNDRV_PCM_STATE_PAUSED; |
---|
1408 | 1615 | snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MPAUSE); |
---|
1409 | 1616 | wake_up(&runtime->sleep); |
---|
.. | .. |
---|
1424 | 1631 | /* |
---|
1425 | 1632 | * Push/release the pause for all linked streams. |
---|
1426 | 1633 | */ |
---|
1427 | | -static int snd_pcm_pause(struct snd_pcm_substream *substream, int push) |
---|
| 1634 | +static int snd_pcm_pause(struct snd_pcm_substream *substream, bool push) |
---|
1428 | 1635 | { |
---|
1429 | | - return snd_pcm_action(&snd_pcm_action_pause, substream, push); |
---|
| 1636 | + return snd_pcm_action(&snd_pcm_action_pause, substream, |
---|
| 1637 | + (__force snd_pcm_state_t)push); |
---|
| 1638 | +} |
---|
| 1639 | + |
---|
| 1640 | +static int snd_pcm_pause_lock_irq(struct snd_pcm_substream *substream, |
---|
| 1641 | + bool push) |
---|
| 1642 | +{ |
---|
| 1643 | + return snd_pcm_action_lock_irq(&snd_pcm_action_pause, substream, |
---|
| 1644 | + (__force snd_pcm_state_t)push); |
---|
1430 | 1645 | } |
---|
1431 | 1646 | |
---|
1432 | 1647 | #ifdef CONFIG_PM |
---|
1433 | | -/* suspend */ |
---|
| 1648 | +/* suspend callback: state argument ignored */ |
---|
1434 | 1649 | |
---|
1435 | | -static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state) |
---|
| 1650 | +static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, |
---|
| 1651 | + snd_pcm_state_t state) |
---|
1436 | 1652 | { |
---|
1437 | 1653 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1438 | 1654 | switch (runtime->status->state) { |
---|
.. | .. |
---|
1448 | 1664 | return 0; |
---|
1449 | 1665 | } |
---|
1450 | 1666 | |
---|
1451 | | -static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state) |
---|
| 1667 | +static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, |
---|
| 1668 | + snd_pcm_state_t state) |
---|
1452 | 1669 | { |
---|
1453 | 1670 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1454 | 1671 | if (runtime->trigger_master != substream) |
---|
.. | .. |
---|
1456 | 1673 | if (! snd_pcm_running(substream)) |
---|
1457 | 1674 | return 0; |
---|
1458 | 1675 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); |
---|
| 1676 | + runtime->stop_operating = true; |
---|
1459 | 1677 | return 0; /* suspend unconditionally */ |
---|
1460 | 1678 | } |
---|
1461 | 1679 | |
---|
1462 | | -static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) |
---|
| 1680 | +static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, |
---|
| 1681 | + snd_pcm_state_t state) |
---|
1463 | 1682 | { |
---|
1464 | 1683 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1465 | 1684 | snd_pcm_trigger_tstamp(substream); |
---|
.. | .. |
---|
1476 | 1695 | .post_action = snd_pcm_post_suspend |
---|
1477 | 1696 | }; |
---|
1478 | 1697 | |
---|
1479 | | -/** |
---|
| 1698 | +/* |
---|
1480 | 1699 | * snd_pcm_suspend - trigger SUSPEND to all linked streams |
---|
1481 | 1700 | * @substream: the PCM substream |
---|
1482 | 1701 | * |
---|
1483 | 1702 | * After this call, all streams are changed to SUSPENDED state. |
---|
1484 | 1703 | * |
---|
1485 | | - * Return: Zero if successful (or @substream is %NULL), or a negative error |
---|
1486 | | - * code. |
---|
| 1704 | + * Return: Zero if successful, or a negative error code. |
---|
1487 | 1705 | */ |
---|
1488 | | -int snd_pcm_suspend(struct snd_pcm_substream *substream) |
---|
| 1706 | +static int snd_pcm_suspend(struct snd_pcm_substream *substream) |
---|
1489 | 1707 | { |
---|
1490 | 1708 | int err; |
---|
1491 | 1709 | unsigned long flags; |
---|
1492 | 1710 | |
---|
1493 | | - if (! substream) |
---|
1494 | | - return 0; |
---|
1495 | | - |
---|
1496 | 1711 | snd_pcm_stream_lock_irqsave(substream, flags); |
---|
1497 | | - err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0); |
---|
| 1712 | + err = snd_pcm_action(&snd_pcm_action_suspend, substream, |
---|
| 1713 | + ACTION_ARG_IGNORE); |
---|
1498 | 1714 | snd_pcm_stream_unlock_irqrestore(substream, flags); |
---|
1499 | 1715 | return err; |
---|
1500 | 1716 | } |
---|
1501 | | -EXPORT_SYMBOL(snd_pcm_suspend); |
---|
1502 | 1717 | |
---|
1503 | 1718 | /** |
---|
1504 | 1719 | * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm |
---|
.. | .. |
---|
1535 | 1750 | return err; |
---|
1536 | 1751 | } |
---|
1537 | 1752 | } |
---|
| 1753 | + |
---|
| 1754 | + for (stream = 0; stream < 2; stream++) |
---|
| 1755 | + for (substream = pcm->streams[stream].substream; |
---|
| 1756 | + substream; substream = substream->next) |
---|
| 1757 | + snd_pcm_sync_stop(substream, false); |
---|
| 1758 | + |
---|
1538 | 1759 | return 0; |
---|
1539 | 1760 | } |
---|
1540 | 1761 | EXPORT_SYMBOL(snd_pcm_suspend_all); |
---|
1541 | 1762 | |
---|
1542 | | -/* resume */ |
---|
| 1763 | +/* resume callbacks: state argument ignored */ |
---|
1543 | 1764 | |
---|
1544 | | -static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state) |
---|
| 1765 | +static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, |
---|
| 1766 | + snd_pcm_state_t state) |
---|
1545 | 1767 | { |
---|
1546 | 1768 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1547 | 1769 | if (!(runtime->info & SNDRV_PCM_INFO_RESUME)) |
---|
.. | .. |
---|
1550 | 1772 | return 0; |
---|
1551 | 1773 | } |
---|
1552 | 1774 | |
---|
1553 | | -static int snd_pcm_do_resume(struct snd_pcm_substream *substream, int state) |
---|
| 1775 | +static int snd_pcm_do_resume(struct snd_pcm_substream *substream, |
---|
| 1776 | + snd_pcm_state_t state) |
---|
1554 | 1777 | { |
---|
1555 | 1778 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1556 | 1779 | if (runtime->trigger_master != substream) |
---|
.. | .. |
---|
1563 | 1786 | return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); |
---|
1564 | 1787 | } |
---|
1565 | 1788 | |
---|
1566 | | -static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, int state) |
---|
| 1789 | +static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, |
---|
| 1790 | + snd_pcm_state_t state) |
---|
1567 | 1791 | { |
---|
1568 | 1792 | if (substream->runtime->trigger_master == substream && |
---|
1569 | 1793 | snd_pcm_running(substream)) |
---|
1570 | 1794 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); |
---|
1571 | 1795 | } |
---|
1572 | 1796 | |
---|
1573 | | -static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state) |
---|
| 1797 | +static void snd_pcm_post_resume(struct snd_pcm_substream *substream, |
---|
| 1798 | + snd_pcm_state_t state) |
---|
1574 | 1799 | { |
---|
1575 | 1800 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1576 | 1801 | snd_pcm_trigger_tstamp(substream); |
---|
.. | .. |
---|
1587 | 1812 | |
---|
1588 | 1813 | static int snd_pcm_resume(struct snd_pcm_substream *substream) |
---|
1589 | 1814 | { |
---|
1590 | | - return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); |
---|
| 1815 | + return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, |
---|
| 1816 | + ACTION_ARG_IGNORE); |
---|
1591 | 1817 | } |
---|
1592 | 1818 | |
---|
1593 | 1819 | #else |
---|
.. | .. |
---|
1628 | 1854 | /* |
---|
1629 | 1855 | * reset ioctl |
---|
1630 | 1856 | */ |
---|
1631 | | -static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state) |
---|
| 1857 | +/* reset callbacks: state argument ignored */ |
---|
| 1858 | +static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, |
---|
| 1859 | + snd_pcm_state_t state) |
---|
1632 | 1860 | { |
---|
1633 | 1861 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1634 | 1862 | switch (runtime->status->state) { |
---|
.. | .. |
---|
1642 | 1870 | } |
---|
1643 | 1871 | } |
---|
1644 | 1872 | |
---|
1645 | | -static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state) |
---|
| 1873 | +static int snd_pcm_do_reset(struct snd_pcm_substream *substream, |
---|
| 1874 | + snd_pcm_state_t state) |
---|
1646 | 1875 | { |
---|
1647 | 1876 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1648 | | - int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); |
---|
| 1877 | + int err = snd_pcm_ops_ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); |
---|
1649 | 1878 | if (err < 0) |
---|
1650 | 1879 | return err; |
---|
| 1880 | + snd_pcm_stream_lock_irq(substream); |
---|
1651 | 1881 | runtime->hw_ptr_base = 0; |
---|
1652 | 1882 | runtime->hw_ptr_interrupt = runtime->status->hw_ptr - |
---|
1653 | 1883 | runtime->status->hw_ptr % runtime->period_size; |
---|
1654 | 1884 | runtime->silence_start = runtime->status->hw_ptr; |
---|
1655 | 1885 | runtime->silence_filled = 0; |
---|
| 1886 | + snd_pcm_stream_unlock_irq(substream); |
---|
1656 | 1887 | return 0; |
---|
1657 | 1888 | } |
---|
1658 | 1889 | |
---|
1659 | | -static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state) |
---|
| 1890 | +static void snd_pcm_post_reset(struct snd_pcm_substream *substream, |
---|
| 1891 | + snd_pcm_state_t state) |
---|
1660 | 1892 | { |
---|
1661 | 1893 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
| 1894 | + snd_pcm_stream_lock_irq(substream); |
---|
1662 | 1895 | runtime->control->appl_ptr = runtime->status->hw_ptr; |
---|
1663 | 1896 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
---|
1664 | 1897 | runtime->silence_size > 0) |
---|
1665 | 1898 | snd_pcm_playback_silence(substream, ULONG_MAX); |
---|
| 1899 | + snd_pcm_stream_unlock_irq(substream); |
---|
1666 | 1900 | } |
---|
1667 | 1901 | |
---|
1668 | 1902 | static const struct action_ops snd_pcm_action_reset = { |
---|
.. | .. |
---|
1673 | 1907 | |
---|
1674 | 1908 | static int snd_pcm_reset(struct snd_pcm_substream *substream) |
---|
1675 | 1909 | { |
---|
1676 | | - return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0); |
---|
| 1910 | + return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, |
---|
| 1911 | + ACTION_ARG_IGNORE); |
---|
1677 | 1912 | } |
---|
1678 | 1913 | |
---|
1679 | 1914 | /* |
---|
1680 | 1915 | * prepare ioctl |
---|
1681 | 1916 | */ |
---|
1682 | | -/* we use the second argument for updating f_flags */ |
---|
| 1917 | +/* pass f_flags as state argument */ |
---|
1683 | 1918 | static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream, |
---|
1684 | | - int f_flags) |
---|
| 1919 | + snd_pcm_state_t state) |
---|
1685 | 1920 | { |
---|
1686 | 1921 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
| 1922 | + int f_flags = (__force int)state; |
---|
| 1923 | + |
---|
1687 | 1924 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN || |
---|
1688 | 1925 | runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED) |
---|
1689 | 1926 | return -EBADFD; |
---|
.. | .. |
---|
1693 | 1930 | return 0; |
---|
1694 | 1931 | } |
---|
1695 | 1932 | |
---|
1696 | | -static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state) |
---|
| 1933 | +static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, |
---|
| 1934 | + snd_pcm_state_t state) |
---|
1697 | 1935 | { |
---|
1698 | 1936 | int err; |
---|
| 1937 | + snd_pcm_sync_stop(substream, true); |
---|
1699 | 1938 | err = substream->ops->prepare(substream); |
---|
1700 | 1939 | if (err < 0) |
---|
1701 | 1940 | return err; |
---|
1702 | | - return snd_pcm_do_reset(substream, 0); |
---|
| 1941 | + return snd_pcm_do_reset(substream, state); |
---|
1703 | 1942 | } |
---|
1704 | 1943 | |
---|
1705 | | -static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state) |
---|
| 1944 | +static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, |
---|
| 1945 | + snd_pcm_state_t state) |
---|
1706 | 1946 | { |
---|
1707 | 1947 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1708 | 1948 | runtime->control->appl_ptr = runtime->status->hw_ptr; |
---|
.. | .. |
---|
1735 | 1975 | snd_pcm_stream_lock_irq(substream); |
---|
1736 | 1976 | switch (substream->runtime->status->state) { |
---|
1737 | 1977 | case SNDRV_PCM_STATE_PAUSED: |
---|
1738 | | - snd_pcm_pause(substream, 0); |
---|
1739 | | - /* fallthru */ |
---|
| 1978 | + snd_pcm_pause(substream, false); |
---|
| 1979 | + fallthrough; |
---|
1740 | 1980 | case SNDRV_PCM_STATE_SUSPENDED: |
---|
1741 | 1981 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); |
---|
1742 | 1982 | break; |
---|
.. | .. |
---|
1744 | 1984 | snd_pcm_stream_unlock_irq(substream); |
---|
1745 | 1985 | |
---|
1746 | 1986 | return snd_pcm_action_nonatomic(&snd_pcm_action_prepare, |
---|
1747 | | - substream, f_flags); |
---|
| 1987 | + substream, |
---|
| 1988 | + (__force snd_pcm_state_t)f_flags); |
---|
1748 | 1989 | } |
---|
1749 | 1990 | |
---|
1750 | 1991 | /* |
---|
1751 | 1992 | * drain ioctl |
---|
1752 | 1993 | */ |
---|
1753 | 1994 | |
---|
1754 | | -static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) |
---|
| 1995 | +/* drain init callbacks: state argument ignored */ |
---|
| 1996 | +static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, |
---|
| 1997 | + snd_pcm_state_t state) |
---|
1755 | 1998 | { |
---|
1756 | 1999 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1757 | 2000 | switch (runtime->status->state) { |
---|
.. | .. |
---|
1764 | 2007 | return 0; |
---|
1765 | 2008 | } |
---|
1766 | 2009 | |
---|
1767 | | -static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) |
---|
| 2010 | +static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, |
---|
| 2011 | + snd_pcm_state_t state) |
---|
1768 | 2012 | { |
---|
1769 | 2013 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
1770 | 2014 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
---|
.. | .. |
---|
1790 | 2034 | } else { |
---|
1791 | 2035 | /* stop running stream */ |
---|
1792 | 2036 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { |
---|
1793 | | - int new_state = snd_pcm_capture_avail(runtime) > 0 ? |
---|
| 2037 | + snd_pcm_state_t new_state; |
---|
| 2038 | + |
---|
| 2039 | + new_state = snd_pcm_capture_avail(runtime) > 0 ? |
---|
1794 | 2040 | SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; |
---|
1795 | 2041 | snd_pcm_do_stop(substream, new_state); |
---|
1796 | 2042 | snd_pcm_post_stop(substream, new_state); |
---|
.. | .. |
---|
1806 | 2052 | return 0; |
---|
1807 | 2053 | } |
---|
1808 | 2054 | |
---|
1809 | | -static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int state) |
---|
| 2055 | +static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, |
---|
| 2056 | + snd_pcm_state_t state) |
---|
1810 | 2057 | { |
---|
1811 | 2058 | } |
---|
1812 | 2059 | |
---|
.. | .. |
---|
1815 | 2062 | .do_action = snd_pcm_do_drain_init, |
---|
1816 | 2063 | .post_action = snd_pcm_post_drain_init |
---|
1817 | 2064 | }; |
---|
1818 | | - |
---|
1819 | | -static int snd_pcm_drop(struct snd_pcm_substream *substream); |
---|
1820 | 2065 | |
---|
1821 | 2066 | /* |
---|
1822 | 2067 | * Drain the stream(s). |
---|
.. | .. |
---|
1831 | 2076 | struct snd_card *card; |
---|
1832 | 2077 | struct snd_pcm_runtime *runtime; |
---|
1833 | 2078 | struct snd_pcm_substream *s; |
---|
| 2079 | + struct snd_pcm_group *group; |
---|
1834 | 2080 | wait_queue_entry_t wait; |
---|
1835 | 2081 | int result = 0; |
---|
1836 | 2082 | int nonblock = 0; |
---|
.. | .. |
---|
1847 | 2093 | } else if (substream->f_flags & O_NONBLOCK) |
---|
1848 | 2094 | nonblock = 1; |
---|
1849 | 2095 | |
---|
1850 | | - down_read(&snd_pcm_link_rwsem); |
---|
1851 | 2096 | snd_pcm_stream_lock_irq(substream); |
---|
1852 | 2097 | /* resume pause */ |
---|
1853 | 2098 | if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) |
---|
1854 | | - snd_pcm_pause(substream, 0); |
---|
| 2099 | + snd_pcm_pause(substream, false); |
---|
1855 | 2100 | |
---|
1856 | 2101 | /* pre-start/stop - all running streams are changed to DRAINING state */ |
---|
1857 | | - result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); |
---|
| 2102 | + result = snd_pcm_action(&snd_pcm_action_drain_init, substream, |
---|
| 2103 | + ACTION_ARG_IGNORE); |
---|
1858 | 2104 | if (result < 0) |
---|
1859 | 2105 | goto unlock; |
---|
1860 | 2106 | /* in non-blocking, we don't wait in ioctl but let caller poll */ |
---|
.. | .. |
---|
1872 | 2118 | } |
---|
1873 | 2119 | /* find a substream to drain */ |
---|
1874 | 2120 | to_check = NULL; |
---|
| 2121 | + group = snd_pcm_stream_group_ref(substream); |
---|
1875 | 2122 | snd_pcm_group_for_each_entry(s, substream) { |
---|
1876 | 2123 | if (s->stream != SNDRV_PCM_STREAM_PLAYBACK) |
---|
1877 | 2124 | continue; |
---|
.. | .. |
---|
1881 | 2128 | break; |
---|
1882 | 2129 | } |
---|
1883 | 2130 | } |
---|
| 2131 | + snd_pcm_group_unref(group, substream); |
---|
1884 | 2132 | if (!to_check) |
---|
1885 | 2133 | break; /* all drained */ |
---|
1886 | 2134 | init_waitqueue_entry(&wait, current); |
---|
| 2135 | + set_current_state(TASK_INTERRUPTIBLE); |
---|
1887 | 2136 | add_wait_queue(&to_check->sleep, &wait); |
---|
1888 | 2137 | snd_pcm_stream_unlock_irq(substream); |
---|
1889 | | - up_read(&snd_pcm_link_rwsem); |
---|
1890 | 2138 | if (runtime->no_period_wakeup) |
---|
1891 | 2139 | tout = MAX_SCHEDULE_TIMEOUT; |
---|
1892 | 2140 | else { |
---|
.. | .. |
---|
1897 | 2145 | } |
---|
1898 | 2146 | tout = msecs_to_jiffies(tout * 1000); |
---|
1899 | 2147 | } |
---|
1900 | | - tout = schedule_timeout_interruptible(tout); |
---|
1901 | | - down_read(&snd_pcm_link_rwsem); |
---|
| 2148 | + tout = schedule_timeout(tout); |
---|
| 2149 | + |
---|
1902 | 2150 | snd_pcm_stream_lock_irq(substream); |
---|
1903 | | - remove_wait_queue(&to_check->sleep, &wait); |
---|
| 2151 | + group = snd_pcm_stream_group_ref(substream); |
---|
| 2152 | + snd_pcm_group_for_each_entry(s, substream) { |
---|
| 2153 | + if (s->runtime == to_check) { |
---|
| 2154 | + remove_wait_queue(&to_check->sleep, &wait); |
---|
| 2155 | + break; |
---|
| 2156 | + } |
---|
| 2157 | + } |
---|
| 2158 | + snd_pcm_group_unref(group, substream); |
---|
| 2159 | + |
---|
1904 | 2160 | if (card->shutdown) { |
---|
1905 | 2161 | result = -ENODEV; |
---|
1906 | 2162 | break; |
---|
.. | .. |
---|
1920 | 2176 | |
---|
1921 | 2177 | unlock: |
---|
1922 | 2178 | snd_pcm_stream_unlock_irq(substream); |
---|
1923 | | - up_read(&snd_pcm_link_rwsem); |
---|
1924 | 2179 | |
---|
1925 | 2180 | return result; |
---|
1926 | 2181 | } |
---|
.. | .. |
---|
1946 | 2201 | snd_pcm_stream_lock_irq(substream); |
---|
1947 | 2202 | /* resume pause */ |
---|
1948 | 2203 | if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) |
---|
1949 | | - snd_pcm_pause(substream, 0); |
---|
| 2204 | + snd_pcm_pause(substream, false); |
---|
1950 | 2205 | |
---|
1951 | 2206 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); |
---|
1952 | 2207 | /* runtime->control->appl_ptr = runtime->status->hw_ptr; */ |
---|
.. | .. |
---|
1959 | 2214 | static bool is_pcm_file(struct file *file) |
---|
1960 | 2215 | { |
---|
1961 | 2216 | struct inode *inode = file_inode(file); |
---|
| 2217 | + struct snd_pcm *pcm; |
---|
1962 | 2218 | unsigned int minor; |
---|
1963 | 2219 | |
---|
1964 | 2220 | if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major) |
---|
1965 | 2221 | return false; |
---|
1966 | 2222 | minor = iminor(inode); |
---|
1967 | | - return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) || |
---|
1968 | | - snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE); |
---|
| 2223 | + pcm = snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK); |
---|
| 2224 | + if (!pcm) |
---|
| 2225 | + pcm = snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE); |
---|
| 2226 | + if (!pcm) |
---|
| 2227 | + return false; |
---|
| 2228 | + snd_card_unref(pcm->card); |
---|
| 2229 | + return true; |
---|
1969 | 2230 | } |
---|
1970 | 2231 | |
---|
1971 | 2232 | /* |
---|
.. | .. |
---|
1976 | 2237 | int res = 0; |
---|
1977 | 2238 | struct snd_pcm_file *pcm_file; |
---|
1978 | 2239 | struct snd_pcm_substream *substream1; |
---|
1979 | | - struct snd_pcm_group *group; |
---|
| 2240 | + struct snd_pcm_group *group, *target_group; |
---|
| 2241 | + bool nonatomic = substream->pcm->nonatomic; |
---|
1980 | 2242 | struct fd f = fdget(fd); |
---|
1981 | 2243 | |
---|
1982 | 2244 | if (!f.file) |
---|
.. | .. |
---|
1987 | 2249 | } |
---|
1988 | 2250 | pcm_file = f.file->private_data; |
---|
1989 | 2251 | substream1 = pcm_file->substream; |
---|
| 2252 | + |
---|
1990 | 2253 | if (substream == substream1) { |
---|
1991 | 2254 | res = -EINVAL; |
---|
1992 | 2255 | goto _badf; |
---|
1993 | 2256 | } |
---|
1994 | 2257 | |
---|
1995 | | - group = kmalloc(sizeof(*group), GFP_KERNEL); |
---|
| 2258 | + group = kzalloc(sizeof(*group), GFP_KERNEL); |
---|
1996 | 2259 | if (!group) { |
---|
1997 | 2260 | res = -ENOMEM; |
---|
1998 | 2261 | goto _nolock; |
---|
1999 | 2262 | } |
---|
2000 | | - down_write_nonfifo(&snd_pcm_link_rwsem); |
---|
2001 | | - write_lock_irq(&snd_pcm_link_rwlock); |
---|
| 2263 | + snd_pcm_group_init(group); |
---|
| 2264 | + |
---|
| 2265 | + down_write(&snd_pcm_link_rwsem); |
---|
2002 | 2266 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || |
---|
2003 | 2267 | substream->runtime->status->state != substream1->runtime->status->state || |
---|
2004 | 2268 | substream->pcm->nonatomic != substream1->pcm->nonatomic) { |
---|
.. | .. |
---|
2009 | 2273 | res = -EALREADY; |
---|
2010 | 2274 | goto _end; |
---|
2011 | 2275 | } |
---|
| 2276 | + |
---|
| 2277 | + snd_pcm_stream_lock_irq(substream); |
---|
2012 | 2278 | if (!snd_pcm_stream_linked(substream)) { |
---|
2013 | | - substream->group = group; |
---|
2014 | | - group = NULL; |
---|
2015 | | - spin_lock_init(&substream->group->lock); |
---|
2016 | | - mutex_init(&substream->group->mutex); |
---|
2017 | | - INIT_LIST_HEAD(&substream->group->substreams); |
---|
2018 | | - list_add_tail(&substream->link_list, &substream->group->substreams); |
---|
2019 | | - substream->group->count = 1; |
---|
| 2279 | + snd_pcm_group_assign(substream, group); |
---|
| 2280 | + group = NULL; /* assigned, don't free this one below */ |
---|
2020 | 2281 | } |
---|
2021 | | - list_add_tail(&substream1->link_list, &substream->group->substreams); |
---|
2022 | | - substream->group->count++; |
---|
2023 | | - substream1->group = substream->group; |
---|
| 2282 | + target_group = substream->group; |
---|
| 2283 | + snd_pcm_stream_unlock_irq(substream); |
---|
| 2284 | + |
---|
| 2285 | + snd_pcm_group_lock_irq(target_group, nonatomic); |
---|
| 2286 | + snd_pcm_stream_lock_nested(substream1); |
---|
| 2287 | + snd_pcm_group_assign(substream1, target_group); |
---|
| 2288 | + refcount_inc(&target_group->refs); |
---|
| 2289 | + snd_pcm_stream_unlock(substream1); |
---|
| 2290 | + snd_pcm_group_unlock_irq(target_group, nonatomic); |
---|
2024 | 2291 | _end: |
---|
2025 | | - write_unlock_irq(&snd_pcm_link_rwlock); |
---|
2026 | 2292 | up_write(&snd_pcm_link_rwsem); |
---|
2027 | 2293 | _nolock: |
---|
2028 | | - snd_card_unref(substream1->pcm->card); |
---|
2029 | 2294 | kfree(group); |
---|
2030 | 2295 | _badf: |
---|
2031 | 2296 | fdput(f); |
---|
.. | .. |
---|
2034 | 2299 | |
---|
2035 | 2300 | static void relink_to_local(struct snd_pcm_substream *substream) |
---|
2036 | 2301 | { |
---|
2037 | | - substream->group = &substream->self_group; |
---|
2038 | | - INIT_LIST_HEAD(&substream->self_group.substreams); |
---|
2039 | | - list_add_tail(&substream->link_list, &substream->self_group.substreams); |
---|
| 2302 | + snd_pcm_stream_lock_nested(substream); |
---|
| 2303 | + snd_pcm_group_assign(substream, &substream->self_group); |
---|
| 2304 | + snd_pcm_stream_unlock(substream); |
---|
2040 | 2305 | } |
---|
2041 | 2306 | |
---|
2042 | 2307 | static int snd_pcm_unlink(struct snd_pcm_substream *substream) |
---|
2043 | 2308 | { |
---|
2044 | | - struct snd_pcm_substream *s; |
---|
| 2309 | + struct snd_pcm_group *group; |
---|
| 2310 | + bool nonatomic = substream->pcm->nonatomic; |
---|
| 2311 | + bool do_free = false; |
---|
2045 | 2312 | int res = 0; |
---|
2046 | 2313 | |
---|
2047 | | - down_write_nonfifo(&snd_pcm_link_rwsem); |
---|
2048 | | - write_lock_irq(&snd_pcm_link_rwlock); |
---|
| 2314 | + down_write(&snd_pcm_link_rwsem); |
---|
| 2315 | + |
---|
2049 | 2316 | if (!snd_pcm_stream_linked(substream)) { |
---|
2050 | 2317 | res = -EALREADY; |
---|
2051 | 2318 | goto _end; |
---|
2052 | 2319 | } |
---|
2053 | | - list_del(&substream->link_list); |
---|
2054 | | - substream->group->count--; |
---|
2055 | | - if (substream->group->count == 1) { /* detach the last stream, too */ |
---|
2056 | | - snd_pcm_group_for_each_entry(s, substream) { |
---|
2057 | | - relink_to_local(s); |
---|
2058 | | - break; |
---|
2059 | | - } |
---|
2060 | | - kfree(substream->group); |
---|
2061 | | - } |
---|
| 2320 | + |
---|
| 2321 | + group = substream->group; |
---|
| 2322 | + snd_pcm_group_lock_irq(group, nonatomic); |
---|
| 2323 | + |
---|
2062 | 2324 | relink_to_local(substream); |
---|
| 2325 | + refcount_dec(&group->refs); |
---|
| 2326 | + |
---|
| 2327 | + /* detach the last stream, too */ |
---|
| 2328 | + if (list_is_singular(&group->substreams)) { |
---|
| 2329 | + relink_to_local(list_first_entry(&group->substreams, |
---|
| 2330 | + struct snd_pcm_substream, |
---|
| 2331 | + link_list)); |
---|
| 2332 | + do_free = refcount_dec_and_test(&group->refs); |
---|
| 2333 | + } |
---|
| 2334 | + |
---|
| 2335 | + snd_pcm_group_unlock_irq(group, nonatomic); |
---|
| 2336 | + if (do_free) |
---|
| 2337 | + kfree(group); |
---|
| 2338 | + |
---|
2063 | 2339 | _end: |
---|
2064 | | - write_unlock_irq(&snd_pcm_link_rwlock); |
---|
2065 | 2340 | up_write(&snd_pcm_link_rwsem); |
---|
2066 | 2341 | return res; |
---|
2067 | 2342 | } |
---|
.. | .. |
---|
2110 | 2385 | static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params, |
---|
2111 | 2386 | struct snd_pcm_hw_rule *rule) |
---|
2112 | 2387 | { |
---|
2113 | | - unsigned int k; |
---|
| 2388 | + snd_pcm_format_t k; |
---|
2114 | 2389 | const struct snd_interval *i = |
---|
2115 | 2390 | hw_param_interval_c(params, rule->deps[0]); |
---|
2116 | 2391 | struct snd_mask m; |
---|
2117 | 2392 | struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); |
---|
2118 | 2393 | snd_mask_any(&m); |
---|
2119 | | - for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { |
---|
| 2394 | + pcm_for_each_format(k) { |
---|
2120 | 2395 | int bits; |
---|
2121 | | - if (! snd_mask_test(mask, k)) |
---|
| 2396 | + if (!snd_mask_test_format(mask, k)) |
---|
2122 | 2397 | continue; |
---|
2123 | 2398 | bits = snd_pcm_format_physical_width(k); |
---|
2124 | 2399 | if (bits <= 0) |
---|
2125 | 2400 | continue; /* ignore invalid formats */ |
---|
2126 | 2401 | if ((unsigned)bits < i->min || (unsigned)bits > i->max) |
---|
2127 | | - snd_mask_reset(&m, k); |
---|
| 2402 | + snd_mask_reset(&m, (__force unsigned)k); |
---|
2128 | 2403 | } |
---|
2129 | 2404 | return snd_mask_refine(mask, &m); |
---|
2130 | 2405 | } |
---|
.. | .. |
---|
2133 | 2408 | struct snd_pcm_hw_rule *rule) |
---|
2134 | 2409 | { |
---|
2135 | 2410 | struct snd_interval t; |
---|
2136 | | - unsigned int k; |
---|
| 2411 | + snd_pcm_format_t k; |
---|
| 2412 | + |
---|
2137 | 2413 | t.min = UINT_MAX; |
---|
2138 | 2414 | t.max = 0; |
---|
2139 | 2415 | t.openmin = 0; |
---|
2140 | 2416 | t.openmax = 0; |
---|
2141 | | - for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { |
---|
| 2417 | + pcm_for_each_format(k) { |
---|
2142 | 2418 | int bits; |
---|
2143 | | - if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k)) |
---|
| 2419 | + if (!snd_mask_test_format(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k)) |
---|
2144 | 2420 | continue; |
---|
2145 | 2421 | bits = snd_pcm_format_physical_width(k); |
---|
2146 | 2422 | if (bits <= 0) |
---|
.. | .. |
---|
2190 | 2466 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); |
---|
2191 | 2467 | } |
---|
2192 | 2468 | |
---|
2193 | | -int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) |
---|
| 2469 | +static int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream) |
---|
2194 | 2470 | { |
---|
2195 | 2471 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
2196 | 2472 | struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints; |
---|
.. | .. |
---|
2314 | 2590 | return 0; |
---|
2315 | 2591 | } |
---|
2316 | 2592 | |
---|
2317 | | -int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) |
---|
| 2593 | +static int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream) |
---|
2318 | 2594 | { |
---|
2319 | 2595 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
2320 | 2596 | struct snd_pcm_hardware *hw = &runtime->hw; |
---|
.. | .. |
---|
2322 | 2598 | unsigned int mask = 0; |
---|
2323 | 2599 | |
---|
2324 | 2600 | if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) |
---|
2325 | | - mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED; |
---|
| 2601 | + mask |= PARAM_MASK_BIT(SNDRV_PCM_ACCESS_RW_INTERLEAVED); |
---|
2326 | 2602 | if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) |
---|
2327 | | - mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; |
---|
| 2603 | + mask |= PARAM_MASK_BIT(SNDRV_PCM_ACCESS_RW_NONINTERLEAVED); |
---|
2328 | 2604 | if (hw_support_mmap(substream)) { |
---|
2329 | 2605 | if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) |
---|
2330 | | - mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; |
---|
| 2606 | + mask |= PARAM_MASK_BIT(SNDRV_PCM_ACCESS_MMAP_INTERLEAVED); |
---|
2331 | 2607 | if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) |
---|
2332 | | - mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED; |
---|
| 2608 | + mask |= PARAM_MASK_BIT(SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED); |
---|
2333 | 2609 | if (hw->info & SNDRV_PCM_INFO_COMPLEX) |
---|
2334 | | - mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX; |
---|
| 2610 | + mask |= PARAM_MASK_BIT(SNDRV_PCM_ACCESS_MMAP_COMPLEX); |
---|
2335 | 2611 | } |
---|
2336 | 2612 | err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask); |
---|
2337 | 2613 | if (err < 0) |
---|
.. | .. |
---|
2341 | 2617 | if (err < 0) |
---|
2342 | 2618 | return err; |
---|
2343 | 2619 | |
---|
2344 | | - err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD); |
---|
| 2620 | + err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, |
---|
| 2621 | + PARAM_MASK_BIT(SNDRV_PCM_SUBFORMAT_STD)); |
---|
2345 | 2622 | if (err < 0) |
---|
2346 | 2623 | return err; |
---|
2347 | 2624 | |
---|
.. | .. |
---|
2411 | 2688 | |
---|
2412 | 2689 | snd_pcm_drop(substream); |
---|
2413 | 2690 | if (substream->hw_opened) { |
---|
2414 | | - if (substream->ops->hw_free && |
---|
2415 | | - substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
2416 | | - substream->ops->hw_free(substream); |
---|
| 2691 | + if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN) |
---|
| 2692 | + do_hw_free(substream); |
---|
2417 | 2693 | substream->ops->close(substream); |
---|
2418 | 2694 | substream->hw_opened = 0; |
---|
2419 | 2695 | } |
---|
2420 | | - if (pm_qos_request_active(&substream->latency_pm_qos_req)) |
---|
2421 | | - pm_qos_remove_request(&substream->latency_pm_qos_req); |
---|
| 2696 | + if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req)) |
---|
| 2697 | + cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); |
---|
2422 | 2698 | if (substream->pcm_release) { |
---|
2423 | 2699 | substream->pcm_release(substream); |
---|
2424 | 2700 | substream->pcm_release = NULL; |
---|
.. | .. |
---|
2486 | 2762 | return -ENOMEM; |
---|
2487 | 2763 | } |
---|
2488 | 2764 | pcm_file->substream = substream; |
---|
2489 | | - if (substream->ref_count == 1) { |
---|
2490 | | - substream->file = pcm_file; |
---|
| 2765 | + if (substream->ref_count == 1) |
---|
2491 | 2766 | substream->pcm_release = pcm_release_private; |
---|
2492 | | - } |
---|
2493 | 2767 | file->private_data = pcm_file; |
---|
2494 | 2768 | |
---|
2495 | 2769 | return 0; |
---|
.. | .. |
---|
2610 | 2884 | case SNDRV_PCM_STATE_DRAINING: |
---|
2611 | 2885 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) |
---|
2612 | 2886 | return -EBADFD; |
---|
2613 | | - /* Fall through */ |
---|
| 2887 | + fallthrough; |
---|
2614 | 2888 | case SNDRV_PCM_STATE_RUNNING: |
---|
2615 | 2889 | return snd_pcm_update_hw_ptr(substream); |
---|
2616 | 2890 | case SNDRV_PCM_STATE_PREPARED: |
---|
.. | .. |
---|
2738 | 3012 | volatile struct snd_pcm_mmap_status *status; |
---|
2739 | 3013 | volatile struct snd_pcm_mmap_control *control; |
---|
2740 | 3014 | int err; |
---|
2741 | | - snd_pcm_uframes_t hw_avail; |
---|
2742 | 3015 | |
---|
2743 | 3016 | memset(&sync_ptr, 0, sizeof(sync_ptr)); |
---|
2744 | 3017 | if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) |
---|
.. | .. |
---|
2767 | 3040 | control->avail_min = sync_ptr.c.control.avail_min; |
---|
2768 | 3041 | else |
---|
2769 | 3042 | sync_ptr.c.control.avail_min = control->avail_min; |
---|
2770 | | - |
---|
2771 | | - if (runtime->render_flag & SNDRV_NON_DMA_MODE) { |
---|
2772 | | - hw_avail = snd_pcm_playback_hw_avail(runtime); |
---|
2773 | | - if ((hw_avail >= runtime->start_threshold) |
---|
2774 | | - && (runtime->render_flag & |
---|
2775 | | - SNDRV_RENDER_STOPPED)) { |
---|
2776 | | - if (substream->ops->restart) |
---|
2777 | | - substream->ops->restart(substream); |
---|
2778 | | - } |
---|
2779 | | - } |
---|
2780 | 3043 | sync_ptr.s.status.state = status->state; |
---|
2781 | 3044 | sync_ptr.s.status.hw_ptr = status->hw_ptr; |
---|
2782 | 3045 | sync_ptr.s.status.tstamp = status->tstamp; |
---|
.. | .. |
---|
2787 | 3050 | return -EFAULT; |
---|
2788 | 3051 | return 0; |
---|
2789 | 3052 | } |
---|
| 3053 | + |
---|
| 3054 | +struct snd_pcm_mmap_status32 { |
---|
| 3055 | + snd_pcm_state_t state; |
---|
| 3056 | + s32 pad1; |
---|
| 3057 | + u32 hw_ptr; |
---|
| 3058 | + s32 tstamp_sec; |
---|
| 3059 | + s32 tstamp_nsec; |
---|
| 3060 | + snd_pcm_state_t suspended_state; |
---|
| 3061 | + s32 audio_tstamp_sec; |
---|
| 3062 | + s32 audio_tstamp_nsec; |
---|
| 3063 | +} __attribute__((packed)); |
---|
| 3064 | + |
---|
| 3065 | +struct snd_pcm_mmap_control32 { |
---|
| 3066 | + u32 appl_ptr; |
---|
| 3067 | + u32 avail_min; |
---|
| 3068 | +}; |
---|
| 3069 | + |
---|
| 3070 | +struct snd_pcm_sync_ptr32 { |
---|
| 3071 | + u32 flags; |
---|
| 3072 | + union { |
---|
| 3073 | + struct snd_pcm_mmap_status32 status; |
---|
| 3074 | + unsigned char reserved[64]; |
---|
| 3075 | + } s; |
---|
| 3076 | + union { |
---|
| 3077 | + struct snd_pcm_mmap_control32 control; |
---|
| 3078 | + unsigned char reserved[64]; |
---|
| 3079 | + } c; |
---|
| 3080 | +} __attribute__((packed)); |
---|
| 3081 | + |
---|
| 3082 | +/* recalcuate the boundary within 32bit */ |
---|
| 3083 | +static snd_pcm_uframes_t recalculate_boundary(struct snd_pcm_runtime *runtime) |
---|
| 3084 | +{ |
---|
| 3085 | + snd_pcm_uframes_t boundary; |
---|
| 3086 | + |
---|
| 3087 | + if (! runtime->buffer_size) |
---|
| 3088 | + return 0; |
---|
| 3089 | + boundary = runtime->buffer_size; |
---|
| 3090 | + while (boundary * 2 <= 0x7fffffffUL - runtime->buffer_size) |
---|
| 3091 | + boundary *= 2; |
---|
| 3092 | + return boundary; |
---|
| 3093 | +} |
---|
| 3094 | + |
---|
| 3095 | +static int snd_pcm_ioctl_sync_ptr_compat(struct snd_pcm_substream *substream, |
---|
| 3096 | + struct snd_pcm_sync_ptr32 __user *src) |
---|
| 3097 | +{ |
---|
| 3098 | + struct snd_pcm_runtime *runtime = substream->runtime; |
---|
| 3099 | + volatile struct snd_pcm_mmap_status *status; |
---|
| 3100 | + volatile struct snd_pcm_mmap_control *control; |
---|
| 3101 | + u32 sflags; |
---|
| 3102 | + struct snd_pcm_mmap_control scontrol; |
---|
| 3103 | + struct snd_pcm_mmap_status sstatus; |
---|
| 3104 | + snd_pcm_uframes_t boundary; |
---|
| 3105 | + int err; |
---|
| 3106 | + |
---|
| 3107 | + if (snd_BUG_ON(!runtime)) |
---|
| 3108 | + return -EINVAL; |
---|
| 3109 | + |
---|
| 3110 | + if (get_user(sflags, &src->flags) || |
---|
| 3111 | + get_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || |
---|
| 3112 | + get_user(scontrol.avail_min, &src->c.control.avail_min)) |
---|
| 3113 | + return -EFAULT; |
---|
| 3114 | + if (sflags & SNDRV_PCM_SYNC_PTR_HWSYNC) { |
---|
| 3115 | + err = snd_pcm_hwsync(substream); |
---|
| 3116 | + if (err < 0) |
---|
| 3117 | + return err; |
---|
| 3118 | + } |
---|
| 3119 | + status = runtime->status; |
---|
| 3120 | + control = runtime->control; |
---|
| 3121 | + boundary = recalculate_boundary(runtime); |
---|
| 3122 | + if (! boundary) |
---|
| 3123 | + boundary = 0x7fffffff; |
---|
| 3124 | + snd_pcm_stream_lock_irq(substream); |
---|
| 3125 | + /* FIXME: we should consider the boundary for the sync from app */ |
---|
| 3126 | + if (!(sflags & SNDRV_PCM_SYNC_PTR_APPL)) { |
---|
| 3127 | + err = pcm_lib_apply_appl_ptr(substream, |
---|
| 3128 | + scontrol.appl_ptr); |
---|
| 3129 | + if (err < 0) { |
---|
| 3130 | + snd_pcm_stream_unlock_irq(substream); |
---|
| 3131 | + return err; |
---|
| 3132 | + } |
---|
| 3133 | + } else |
---|
| 3134 | + scontrol.appl_ptr = control->appl_ptr % boundary; |
---|
| 3135 | + if (!(sflags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) |
---|
| 3136 | + control->avail_min = scontrol.avail_min; |
---|
| 3137 | + else |
---|
| 3138 | + scontrol.avail_min = control->avail_min; |
---|
| 3139 | + sstatus.state = status->state; |
---|
| 3140 | + sstatus.hw_ptr = status->hw_ptr % boundary; |
---|
| 3141 | + sstatus.tstamp = status->tstamp; |
---|
| 3142 | + sstatus.suspended_state = status->suspended_state; |
---|
| 3143 | + sstatus.audio_tstamp = status->audio_tstamp; |
---|
| 3144 | + snd_pcm_stream_unlock_irq(substream); |
---|
| 3145 | + if (put_user(sstatus.state, &src->s.status.state) || |
---|
| 3146 | + put_user(sstatus.hw_ptr, &src->s.status.hw_ptr) || |
---|
| 3147 | + put_user(sstatus.tstamp.tv_sec, &src->s.status.tstamp_sec) || |
---|
| 3148 | + put_user(sstatus.tstamp.tv_nsec, &src->s.status.tstamp_nsec) || |
---|
| 3149 | + put_user(sstatus.suspended_state, &src->s.status.suspended_state) || |
---|
| 3150 | + put_user(sstatus.audio_tstamp.tv_sec, &src->s.status.audio_tstamp_sec) || |
---|
| 3151 | + put_user(sstatus.audio_tstamp.tv_nsec, &src->s.status.audio_tstamp_nsec) || |
---|
| 3152 | + put_user(scontrol.appl_ptr, &src->c.control.appl_ptr) || |
---|
| 3153 | + put_user(scontrol.avail_min, &src->c.control.avail_min)) |
---|
| 3154 | + return -EFAULT; |
---|
| 3155 | + |
---|
| 3156 | + return 0; |
---|
| 3157 | +} |
---|
| 3158 | +#define __SNDRV_PCM_IOCTL_SYNC_PTR32 _IOWR('A', 0x23, struct snd_pcm_sync_ptr32) |
---|
2790 | 3159 | |
---|
2791 | 3160 | static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg) |
---|
2792 | 3161 | { |
---|
.. | .. |
---|
2818 | 3187 | result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames); |
---|
2819 | 3188 | else |
---|
2820 | 3189 | result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames); |
---|
2821 | | - __put_user(result, &_xferi->result); |
---|
| 3190 | + if (put_user(result, &_xferi->result)) |
---|
| 3191 | + return -EFAULT; |
---|
2822 | 3192 | return result < 0 ? result : 0; |
---|
2823 | 3193 | } |
---|
2824 | 3194 | |
---|
.. | .. |
---|
2847 | 3217 | else |
---|
2848 | 3218 | result = snd_pcm_lib_readv(substream, bufs, xfern.frames); |
---|
2849 | 3219 | kfree(bufs); |
---|
2850 | | - __put_user(result, &_xfern->result); |
---|
| 3220 | + if (put_user(result, &_xfern->result)) |
---|
| 3221 | + return -EFAULT; |
---|
2851 | 3222 | return result < 0 ? result : 0; |
---|
2852 | 3223 | } |
---|
2853 | 3224 | |
---|
.. | .. |
---|
2862 | 3233 | if (put_user(0, _frames)) |
---|
2863 | 3234 | return -EFAULT; |
---|
2864 | 3235 | result = snd_pcm_rewind(substream, frames); |
---|
2865 | | - __put_user(result, _frames); |
---|
| 3236 | + if (put_user(result, _frames)) |
---|
| 3237 | + return -EFAULT; |
---|
2866 | 3238 | return result < 0 ? result : 0; |
---|
2867 | 3239 | } |
---|
2868 | 3240 | |
---|
.. | .. |
---|
2877 | 3249 | if (put_user(0, _frames)) |
---|
2878 | 3250 | return -EFAULT; |
---|
2879 | 3251 | result = snd_pcm_forward(substream, frames); |
---|
2880 | | - __put_user(result, _frames); |
---|
| 3252 | + if (put_user(result, _frames)) |
---|
| 3253 | + return -EFAULT; |
---|
2881 | 3254 | return result < 0 ? result : 0; |
---|
2882 | 3255 | } |
---|
2883 | 3256 | |
---|
.. | .. |
---|
2917 | 3290 | return snd_pcm_hw_free(substream); |
---|
2918 | 3291 | case SNDRV_PCM_IOCTL_SW_PARAMS: |
---|
2919 | 3292 | return snd_pcm_sw_params_user(substream, arg); |
---|
2920 | | - case SNDRV_PCM_IOCTL_STATUS: |
---|
2921 | | - return snd_pcm_status_user(substream, arg, false); |
---|
2922 | | - case SNDRV_PCM_IOCTL_STATUS_EXT: |
---|
2923 | | - return snd_pcm_status_user(substream, arg, true); |
---|
| 3293 | + case SNDRV_PCM_IOCTL_STATUS32: |
---|
| 3294 | + return snd_pcm_status_user32(substream, arg, false); |
---|
| 3295 | + case SNDRV_PCM_IOCTL_STATUS_EXT32: |
---|
| 3296 | + return snd_pcm_status_user32(substream, arg, true); |
---|
| 3297 | + case SNDRV_PCM_IOCTL_STATUS64: |
---|
| 3298 | + return snd_pcm_status_user64(substream, arg, false); |
---|
| 3299 | + case SNDRV_PCM_IOCTL_STATUS_EXT64: |
---|
| 3300 | + return snd_pcm_status_user64(substream, arg, true); |
---|
2924 | 3301 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: |
---|
2925 | 3302 | return snd_pcm_channel_info_user(substream, arg); |
---|
2926 | 3303 | case SNDRV_PCM_IOCTL_PREPARE: |
---|
.. | .. |
---|
2952 | 3329 | return -EFAULT; |
---|
2953 | 3330 | return 0; |
---|
2954 | 3331 | } |
---|
2955 | | - case SNDRV_PCM_IOCTL_SYNC_PTR: |
---|
| 3332 | + case __SNDRV_PCM_IOCTL_SYNC_PTR32: |
---|
| 3333 | + return snd_pcm_ioctl_sync_ptr_compat(substream, arg); |
---|
| 3334 | + case __SNDRV_PCM_IOCTL_SYNC_PTR64: |
---|
2956 | 3335 | return snd_pcm_sync_ptr(substream, arg); |
---|
2957 | 3336 | #ifdef CONFIG_SND_SUPPORT_OLD_API |
---|
2958 | 3337 | case SNDRV_PCM_IOCTL_HW_REFINE_OLD: |
---|
.. | .. |
---|
2965 | 3344 | case SNDRV_PCM_IOCTL_DROP: |
---|
2966 | 3345 | return snd_pcm_drop(substream); |
---|
2967 | 3346 | case SNDRV_PCM_IOCTL_PAUSE: |
---|
2968 | | - return snd_pcm_action_lock_irq(&snd_pcm_action_pause, |
---|
2969 | | - substream, |
---|
2970 | | - (int)(unsigned long)arg); |
---|
| 3347 | + return snd_pcm_pause_lock_irq(substream, (unsigned long)arg); |
---|
2971 | 3348 | case SNDRV_PCM_IOCTL_WRITEI_FRAMES: |
---|
2972 | 3349 | case SNDRV_PCM_IOCTL_READI_FRAMES: |
---|
2973 | 3350 | return snd_pcm_xferi_frames_ioctl(substream, arg); |
---|
.. | .. |
---|
3290 | 3667 | |
---|
3291 | 3668 | static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file) |
---|
3292 | 3669 | { |
---|
3293 | | - if (pcm_file->no_compat_mmap) |
---|
3294 | | - return false; |
---|
3295 | 3670 | /* See pcm_control_mmap_allowed() below. |
---|
3296 | 3671 | * Since older alsa-lib requires both status and control mmaps to be |
---|
3297 | 3672 | * coupled, we have to disable the status mmap for old alsa-lib, too. |
---|
.. | .. |
---|
3338 | 3713 | snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) |
---|
3339 | 3714 | { |
---|
3340 | 3715 | void *vaddr = substream->runtime->dma_area + ofs; |
---|
3341 | | - return virt_to_page(vaddr); |
---|
| 3716 | + |
---|
| 3717 | + switch (substream->dma_buffer.dev.type) { |
---|
| 3718 | +#ifdef CONFIG_SND_DMA_SGBUF |
---|
| 3719 | + case SNDRV_DMA_TYPE_DEV_SG: |
---|
| 3720 | + case SNDRV_DMA_TYPE_DEV_UC_SG: |
---|
| 3721 | + return snd_pcm_sgbuf_ops_page(substream, ofs); |
---|
| 3722 | +#endif /* CONFIG_SND_DMA_SGBUF */ |
---|
| 3723 | + case SNDRV_DMA_TYPE_VMALLOC: |
---|
| 3724 | + return vmalloc_to_page(vaddr); |
---|
| 3725 | + default: |
---|
| 3726 | + return virt_to_page(vaddr); |
---|
| 3727 | + } |
---|
3342 | 3728 | } |
---|
3343 | 3729 | |
---|
3344 | 3730 | /* |
---|
.. | .. |
---|
3405 | 3791 | area->vm_end - area->vm_start, area->vm_page_prot); |
---|
3406 | 3792 | } |
---|
3407 | 3793 | #endif /* CONFIG_GENERIC_ALLOCATOR */ |
---|
3408 | | -#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */ |
---|
3409 | 3794 | if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page && |
---|
3410 | | - substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) |
---|
| 3795 | + (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV || |
---|
| 3796 | + substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC)) |
---|
3411 | 3797 | return dma_mmap_coherent(substream->dma_buffer.dev.dev, |
---|
3412 | 3798 | area, |
---|
3413 | 3799 | substream->runtime->dma_area, |
---|
3414 | 3800 | substream->runtime->dma_addr, |
---|
3415 | 3801 | substream->runtime->dma_bytes); |
---|
3416 | | -#endif /* CONFIG_X86 */ |
---|
3417 | 3802 | /* mmap with fault handler */ |
---|
3418 | 3803 | area->vm_ops = &snd_pcm_vm_ops_data_fault; |
---|
3419 | 3804 | return 0; |
---|
.. | .. |
---|
3504 | 3889 | |
---|
3505 | 3890 | offset = area->vm_pgoff << PAGE_SHIFT; |
---|
3506 | 3891 | switch (offset) { |
---|
3507 | | - case SNDRV_PCM_MMAP_OFFSET_STATUS: |
---|
| 3892 | + case SNDRV_PCM_MMAP_OFFSET_STATUS_OLD: |
---|
| 3893 | + if (pcm_file->no_compat_mmap || !IS_ENABLED(CONFIG_64BIT)) |
---|
| 3894 | + return -ENXIO; |
---|
| 3895 | + fallthrough; |
---|
| 3896 | + case SNDRV_PCM_MMAP_OFFSET_STATUS_NEW: |
---|
3508 | 3897 | if (!pcm_status_mmap_allowed(pcm_file)) |
---|
3509 | 3898 | return -ENXIO; |
---|
3510 | 3899 | return snd_pcm_mmap_status(substream, file, area); |
---|
3511 | | - case SNDRV_PCM_MMAP_OFFSET_CONTROL: |
---|
| 3900 | + case SNDRV_PCM_MMAP_OFFSET_CONTROL_OLD: |
---|
| 3901 | + if (pcm_file->no_compat_mmap || !IS_ENABLED(CONFIG_64BIT)) |
---|
| 3902 | + return -ENXIO; |
---|
| 3903 | + fallthrough; |
---|
| 3904 | + case SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW: |
---|
3512 | 3905 | if (!pcm_control_mmap_allowed(pcm_file)) |
---|
3513 | 3906 | return -ENXIO; |
---|
3514 | 3907 | return snd_pcm_mmap_control(substream, file, area); |
---|
.. | .. |
---|
3668 | 4061 | unsigned long offset = pgoff << PAGE_SHIFT; |
---|
3669 | 4062 | |
---|
3670 | 4063 | switch (offset) { |
---|
3671 | | - case SNDRV_PCM_MMAP_OFFSET_STATUS: |
---|
| 4064 | + case SNDRV_PCM_MMAP_OFFSET_STATUS_NEW: |
---|
3672 | 4065 | return (unsigned long)runtime->status; |
---|
3673 | | - case SNDRV_PCM_MMAP_OFFSET_CONTROL: |
---|
| 4066 | + case SNDRV_PCM_MMAP_OFFSET_CONTROL_NEW: |
---|
3674 | 4067 | return (unsigned long)runtime->control; |
---|
3675 | 4068 | default: |
---|
3676 | 4069 | return (unsigned long)runtime->dma_area + offset; |
---|