.. | .. |
---|
| 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 | * Abramo Bagnara <abramo@alsa-project.org> |
---|
5 | | - * |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify |
---|
8 | | - * it under the terms of the GNU General Public License as published by |
---|
9 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
10 | | - * (at your option) any later version. |
---|
11 | | - * |
---|
12 | | - * This program is distributed in the hope that it will be useful, |
---|
13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | | - * GNU General Public License for more details. |
---|
16 | | - * |
---|
17 | | - * You should have received a copy of the GNU General Public License |
---|
18 | | - * along with this program; if not, write to the Free Software |
---|
19 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
20 | | - * |
---|
21 | 6 | */ |
---|
22 | 7 | |
---|
23 | 8 | #include <linux/slab.h> |
---|
.. | .. |
---|
43 | 28 | #define trace_xrun(substream) |
---|
44 | 29 | #define trace_hw_ptr_error(substream, reason) |
---|
45 | 30 | #define trace_applptr(substream, prev, curr) |
---|
| 31 | +#define trace_applptr_start(substream, frame) |
---|
46 | 32 | #endif |
---|
47 | | - |
---|
48 | | -#define STRING_LENGTH_OF_INT 12 |
---|
49 | | -#define MAX_USR_CTRL_CNT 128 |
---|
50 | 33 | |
---|
51 | 34 | static int fill_silence_frames(struct snd_pcm_substream *substream, |
---|
52 | 35 | snd_pcm_uframes_t off, snd_pcm_uframes_t frames); |
---|
.. | .. |
---|
162 | 145 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
163 | 146 | |
---|
164 | 147 | trace_xrun(substream); |
---|
165 | | - if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
---|
166 | | - snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); |
---|
| 148 | + if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) { |
---|
| 149 | + struct timespec64 tstamp; |
---|
| 150 | + |
---|
| 151 | + snd_pcm_gettime(runtime, &tstamp); |
---|
| 152 | + runtime->status->tstamp.tv_sec = tstamp.tv_sec; |
---|
| 153 | + runtime->status->tstamp.tv_nsec = tstamp.tv_nsec; |
---|
| 154 | + } |
---|
167 | 155 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); |
---|
168 | 156 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { |
---|
169 | 157 | char name[16]; |
---|
.. | .. |
---|
218 | 206 | } |
---|
219 | 207 | |
---|
220 | 208 | static void update_audio_tstamp(struct snd_pcm_substream *substream, |
---|
221 | | - struct timespec *curr_tstamp, |
---|
222 | | - struct timespec *audio_tstamp) |
---|
| 209 | + struct timespec64 *curr_tstamp, |
---|
| 210 | + struct timespec64 *audio_tstamp) |
---|
223 | 211 | { |
---|
224 | 212 | struct snd_pcm_runtime *runtime = substream->runtime; |
---|
225 | 213 | u64 audio_frames, audio_nsecs; |
---|
226 | | - struct timespec driver_tstamp; |
---|
| 214 | + struct timespec64 driver_tstamp; |
---|
227 | 215 | |
---|
228 | 216 | if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE) |
---|
229 | 217 | return; |
---|
.. | .. |
---|
247 | 235 | } |
---|
248 | 236 | audio_nsecs = div_u64(audio_frames * 1000000000LL, |
---|
249 | 237 | runtime->rate); |
---|
250 | | - *audio_tstamp = ns_to_timespec(audio_nsecs); |
---|
| 238 | + *audio_tstamp = ns_to_timespec64(audio_nsecs); |
---|
251 | 239 | } |
---|
252 | | - if (!timespec_equal(&runtime->status->audio_tstamp, audio_tstamp)) { |
---|
253 | | - runtime->status->audio_tstamp = *audio_tstamp; |
---|
254 | | - runtime->status->tstamp = *curr_tstamp; |
---|
| 240 | + |
---|
| 241 | + if (runtime->status->audio_tstamp.tv_sec != audio_tstamp->tv_sec || |
---|
| 242 | + runtime->status->audio_tstamp.tv_nsec != audio_tstamp->tv_nsec) { |
---|
| 243 | + runtime->status->audio_tstamp.tv_sec = audio_tstamp->tv_sec; |
---|
| 244 | + runtime->status->audio_tstamp.tv_nsec = audio_tstamp->tv_nsec; |
---|
| 245 | + runtime->status->tstamp.tv_sec = curr_tstamp->tv_sec; |
---|
| 246 | + runtime->status->tstamp.tv_nsec = curr_tstamp->tv_nsec; |
---|
255 | 247 | } |
---|
| 248 | + |
---|
256 | 249 | |
---|
257 | 250 | /* |
---|
258 | 251 | * re-take a driver timestamp to let apps detect if the reference tstamp |
---|
259 | 252 | * read by low-level hardware was provided with a delay |
---|
260 | 253 | */ |
---|
261 | | - snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp); |
---|
| 254 | + snd_pcm_gettime(substream->runtime, &driver_tstamp); |
---|
262 | 255 | runtime->driver_tstamp = driver_tstamp; |
---|
263 | 256 | } |
---|
264 | 257 | |
---|
.. | .. |
---|
271 | 264 | snd_pcm_sframes_t hdelta, delta; |
---|
272 | 265 | unsigned long jdelta; |
---|
273 | 266 | unsigned long curr_jiffies; |
---|
274 | | - struct timespec curr_tstamp; |
---|
275 | | - struct timespec audio_tstamp; |
---|
| 267 | + struct timespec64 curr_tstamp; |
---|
| 268 | + struct timespec64 audio_tstamp; |
---|
276 | 269 | int crossed_boundary = 0; |
---|
277 | 270 | |
---|
278 | 271 | old_hw_ptr = runtime->status->hw_ptr; |
---|
.. | .. |
---|
295 | 288 | |
---|
296 | 289 | /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */ |
---|
297 | 290 | if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT) |
---|
298 | | - snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); |
---|
| 291 | + snd_pcm_gettime(runtime, &curr_tstamp); |
---|
299 | 292 | } else |
---|
300 | | - snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp); |
---|
| 293 | + snd_pcm_gettime(runtime, &curr_tstamp); |
---|
301 | 294 | } |
---|
302 | 295 | |
---|
303 | 296 | if (pos == SNDRV_PCM_POS_XRUN) { |
---|
.. | .. |
---|
498 | 491 | EXPORT_SYMBOL(snd_pcm_set_ops); |
---|
499 | 492 | |
---|
500 | 493 | /** |
---|
501 | | - * snd_pcm_sync - set the PCM sync id |
---|
| 494 | + * snd_pcm_set_sync - set the PCM sync id |
---|
502 | 495 | * @substream: the pcm substream |
---|
503 | 496 | * |
---|
504 | 497 | * Sets the PCM sync identifier for the card. |
---|
.. | .. |
---|
1461 | 1454 | |
---|
1462 | 1455 | static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) |
---|
1463 | 1456 | { |
---|
1464 | | - static unsigned int pow2_sizes[] = { |
---|
| 1457 | + static const unsigned int pow2_sizes[] = { |
---|
1465 | 1458 | 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7, |
---|
1466 | 1459 | 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15, |
---|
1467 | 1460 | 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23, |
---|
.. | .. |
---|
2139 | 2132 | if (err < 0) |
---|
2140 | 2133 | return err; |
---|
2141 | 2134 | |
---|
| 2135 | + trace_applptr_start(substream, size); |
---|
| 2136 | + |
---|
2142 | 2137 | is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; |
---|
2143 | 2138 | if (interleaved) { |
---|
2144 | 2139 | if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED && |
---|
.. | .. |
---|
2180 | 2175 | if (err < 0) |
---|
2181 | 2176 | goto _end_unlock; |
---|
2182 | 2177 | |
---|
| 2178 | + runtime->twake = runtime->control->avail_min ? : 1; |
---|
| 2179 | + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
---|
| 2180 | + snd_pcm_update_hw_ptr(substream); |
---|
| 2181 | + |
---|
| 2182 | + /* |
---|
| 2183 | + * If size < start_threshold, wait indefinitely. Another |
---|
| 2184 | + * thread may start capture |
---|
| 2185 | + */ |
---|
2183 | 2186 | if (!is_playback && |
---|
2184 | 2187 | runtime->status->state == SNDRV_PCM_STATE_PREPARED && |
---|
2185 | 2188 | size >= runtime->start_threshold) { |
---|
.. | .. |
---|
2188 | 2191 | goto _end_unlock; |
---|
2189 | 2192 | } |
---|
2190 | 2193 | |
---|
2191 | | - runtime->twake = runtime->control->avail_min ? : 1; |
---|
2192 | | - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
---|
2193 | | - snd_pcm_update_hw_ptr(substream); |
---|
2194 | 2194 | avail = snd_pcm_avail(substream); |
---|
| 2195 | + |
---|
2195 | 2196 | while (size > 0) { |
---|
2196 | 2197 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
---|
2197 | 2198 | snd_pcm_uframes_t cont; |
---|
.. | .. |
---|
2220 | 2221 | if (frames > cont) |
---|
2221 | 2222 | frames = cont; |
---|
2222 | 2223 | if (snd_BUG_ON(!frames)) { |
---|
2223 | | - runtime->twake = 0; |
---|
2224 | | - snd_pcm_stream_unlock_irq(substream); |
---|
2225 | | - return -EINVAL; |
---|
| 2224 | + err = -EINVAL; |
---|
| 2225 | + goto _end_unlock; |
---|
| 2226 | + } |
---|
| 2227 | + if (!atomic_inc_unless_negative(&runtime->buffer_accessing)) { |
---|
| 2228 | + err = -EBUSY; |
---|
| 2229 | + goto _end_unlock; |
---|
2226 | 2230 | } |
---|
2227 | 2231 | snd_pcm_stream_unlock_irq(substream); |
---|
2228 | 2232 | err = writer(substream, appl_ofs, data, offset, frames, |
---|
2229 | 2233 | transfer); |
---|
2230 | 2234 | snd_pcm_stream_lock_irq(substream); |
---|
| 2235 | + atomic_dec(&runtime->buffer_accessing); |
---|
2231 | 2236 | if (err < 0) |
---|
2232 | 2237 | goto _end_unlock; |
---|
2233 | 2238 | err = pcm_accessible_state(runtime); |
---|
.. | .. |
---|
2322 | 2327 | struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); |
---|
2323 | 2328 | |
---|
2324 | 2329 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
---|
2325 | | - uinfo->count = 0; |
---|
2326 | 2330 | uinfo->count = info->max_channels; |
---|
2327 | 2331 | uinfo->value.integer.min = 0; |
---|
2328 | 2332 | uinfo->value.integer.max = SNDRV_CHMAP_LAST; |
---|
.. | .. |
---|
2346 | 2350 | if (!substream) |
---|
2347 | 2351 | return -ENODEV; |
---|
2348 | 2352 | memset(ucontrol->value.integer.value, 0, |
---|
2349 | | - sizeof(ucontrol->value.integer.value)); |
---|
| 2353 | + sizeof(long) * info->max_channels); |
---|
2350 | 2354 | if (!substream->runtime) |
---|
2351 | 2355 | return 0; /* no channels set */ |
---|
2352 | 2356 | for (map = info->chmap; map->channels; map++) { |
---|
.. | .. |
---|
2414 | 2418 | kfree(info); |
---|
2415 | 2419 | } |
---|
2416 | 2420 | |
---|
2417 | | -static int pcm_volume_ctl_info(struct snd_kcontrol *kcontrol, |
---|
2418 | | - struct snd_ctl_elem_info *uinfo) |
---|
2419 | | -{ |
---|
2420 | | - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
---|
2421 | | - uinfo->count = 1; |
---|
2422 | | - uinfo->value.integer.min = 0; |
---|
2423 | | - uinfo->value.integer.max = 0x2000; |
---|
2424 | | - return 0; |
---|
2425 | | -} |
---|
2426 | | - |
---|
2427 | | -static void pcm_volume_ctl_private_free(struct snd_kcontrol *kcontrol) |
---|
2428 | | -{ |
---|
2429 | | - struct snd_pcm_volume *info = snd_kcontrol_chip(kcontrol); |
---|
2430 | | - |
---|
2431 | | - info->pcm->streams[info->stream].vol_kctl = NULL; |
---|
2432 | | - kfree(info); |
---|
2433 | | -} |
---|
2434 | | - |
---|
2435 | 2421 | /** |
---|
2436 | 2422 | * snd_pcm_add_chmap_ctls - create channel-mapping control elements |
---|
2437 | 2423 | * @pcm: the assigned PCM instance |
---|
.. | .. |
---|
2493 | 2479 | return 0; |
---|
2494 | 2480 | } |
---|
2495 | 2481 | EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls); |
---|
2496 | | - |
---|
2497 | | -/** |
---|
2498 | | - * snd_pcm_add_volume_ctls - create volume control elements |
---|
2499 | | - * @pcm: the assigned PCM instance |
---|
2500 | | - * @stream: stream direction |
---|
2501 | | - * @max_length: the max length of the volume parameter of stream |
---|
2502 | | - * @private_value: the value passed to each kcontrol's private_value field |
---|
2503 | | - * @info_ret: store struct snd_pcm_volume instance if non-NULL |
---|
2504 | | - * |
---|
2505 | | - * Create volume control elements assigned to the given PCM stream(s). |
---|
2506 | | - * Returns zero if succeed, or a negative error value. |
---|
2507 | | - */ |
---|
2508 | | -int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream, |
---|
2509 | | - const struct snd_pcm_volume_elem *volume, |
---|
2510 | | - int max_length, |
---|
2511 | | - unsigned long private_value, |
---|
2512 | | - struct snd_pcm_volume **info_ret) |
---|
2513 | | -{ |
---|
2514 | | - struct snd_pcm_volume *info; |
---|
2515 | | - struct snd_kcontrol_new knew = { |
---|
2516 | | - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
---|
2517 | | - .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
---|
2518 | | - SNDRV_CTL_ELEM_ACCESS_READWRITE, |
---|
2519 | | - .info = pcm_volume_ctl_info, |
---|
2520 | | - }; |
---|
2521 | | - int err; |
---|
2522 | | - int size; |
---|
2523 | | - |
---|
2524 | | - info = kzalloc(sizeof(*info), GFP_KERNEL); |
---|
2525 | | - if (!info) |
---|
2526 | | - return -ENOMEM; |
---|
2527 | | - info->pcm = pcm; |
---|
2528 | | - info->stream = stream; |
---|
2529 | | - info->volume = volume; |
---|
2530 | | - info->max_length = max_length; |
---|
2531 | | - size = sizeof("Playback ") + sizeof(" Volume") + |
---|
2532 | | - STRING_LENGTH_OF_INT*sizeof(char) + 1; |
---|
2533 | | - knew.name = kzalloc(size, GFP_KERNEL); |
---|
2534 | | - if (!knew.name) { |
---|
2535 | | - kfree(info); |
---|
2536 | | - return -ENOMEM; |
---|
2537 | | - } |
---|
2538 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
2539 | | - snprintf((char *)knew.name, size, "%s %d %s", |
---|
2540 | | - "Playback", pcm->device, "Volume"); |
---|
2541 | | - else |
---|
2542 | | - snprintf((char *)knew.name, size, "%s %d %s", |
---|
2543 | | - "Capture", pcm->device, "Volume"); |
---|
2544 | | - knew.device = pcm->device; |
---|
2545 | | - knew.count = pcm->streams[stream].substream_count; |
---|
2546 | | - knew.private_value = private_value; |
---|
2547 | | - info->kctl = snd_ctl_new1(&knew, info); |
---|
2548 | | - if (!info->kctl) { |
---|
2549 | | - kfree(info); |
---|
2550 | | - kfree(knew.name); |
---|
2551 | | - return -ENOMEM; |
---|
2552 | | - } |
---|
2553 | | - info->kctl->private_free = pcm_volume_ctl_private_free; |
---|
2554 | | - err = snd_ctl_add(pcm->card, info->kctl); |
---|
2555 | | - if (err < 0) { |
---|
2556 | | - kfree(info); |
---|
2557 | | - kfree(knew.name); |
---|
2558 | | - return -ENOMEM; |
---|
2559 | | - } |
---|
2560 | | - pcm->streams[stream].vol_kctl = info->kctl; |
---|
2561 | | - if (info_ret) |
---|
2562 | | - *info_ret = info; |
---|
2563 | | - kfree(knew.name); |
---|
2564 | | - return 0; |
---|
2565 | | -} |
---|
2566 | | -EXPORT_SYMBOL(snd_pcm_add_volume_ctls); |
---|
2567 | | - |
---|
2568 | | -static int pcm_usr_ctl_info(struct snd_kcontrol *kcontrol, |
---|
2569 | | - struct snd_ctl_elem_info *uinfo) |
---|
2570 | | -{ |
---|
2571 | | - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
---|
2572 | | - uinfo->count = MAX_USR_CTRL_CNT; |
---|
2573 | | - uinfo->value.integer.min = 0; |
---|
2574 | | - uinfo->value.integer.max = INT_MAX; |
---|
2575 | | - return 0; |
---|
2576 | | -} |
---|
2577 | | - |
---|
2578 | | -static void pcm_usr_ctl_private_free(struct snd_kcontrol *kcontrol) |
---|
2579 | | -{ |
---|
2580 | | - struct snd_pcm_usr *info = snd_kcontrol_chip(kcontrol); |
---|
2581 | | - |
---|
2582 | | - info->pcm->streams[info->stream].usr_kctl = NULL; |
---|
2583 | | - kfree(info); |
---|
2584 | | -} |
---|
2585 | | - |
---|
2586 | | -/** |
---|
2587 | | - * snd_pcm_add_usr_ctls - create user control elements |
---|
2588 | | - * @pcm: the assigned PCM instance |
---|
2589 | | - * @stream: stream direction |
---|
2590 | | - * @max_length: the max length of the user parameter of stream |
---|
2591 | | - * @private_value: the value passed to each kcontrol's private_value field |
---|
2592 | | - * @info_ret: store struct snd_pcm_usr instance if non-NULL |
---|
2593 | | - * |
---|
2594 | | - * Create usr control elements assigned to the given PCM stream(s). |
---|
2595 | | - * Returns zero if succeed, or a negative error value. |
---|
2596 | | - */ |
---|
2597 | | -int snd_pcm_add_usr_ctls(struct snd_pcm *pcm, int stream, |
---|
2598 | | - const struct snd_pcm_usr_elem *usr, |
---|
2599 | | - int max_length, int max_kctrl_str_len, |
---|
2600 | | - unsigned long private_value, |
---|
2601 | | - struct snd_pcm_usr **info_ret) |
---|
2602 | | -{ |
---|
2603 | | - struct snd_pcm_usr *info; |
---|
2604 | | - struct snd_kcontrol_new knew = { |
---|
2605 | | - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
---|
2606 | | - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
---|
2607 | | - .info = pcm_usr_ctl_info, |
---|
2608 | | - }; |
---|
2609 | | - int err; |
---|
2610 | | - char *buf; |
---|
2611 | | - |
---|
2612 | | - info = kzalloc(sizeof(*info), GFP_KERNEL); |
---|
2613 | | - if (!info) |
---|
2614 | | - return -ENOMEM; |
---|
2615 | | - |
---|
2616 | | - info->pcm = pcm; |
---|
2617 | | - info->stream = stream; |
---|
2618 | | - info->usr = usr; |
---|
2619 | | - info->max_length = max_length; |
---|
2620 | | - buf = kzalloc(max_kctrl_str_len, GFP_KERNEL); |
---|
2621 | | - if (!buf) { |
---|
2622 | | - pr_err("%s: buffer allocation failed\n", __func__); |
---|
2623 | | - kfree(info); |
---|
2624 | | - return -ENOMEM; |
---|
2625 | | - } |
---|
2626 | | - knew.name = buf; |
---|
2627 | | - if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
---|
2628 | | - snprintf(buf, max_kctrl_str_len, "%s %d %s", |
---|
2629 | | - "Playback", pcm->device, "User kcontrol"); |
---|
2630 | | - else |
---|
2631 | | - snprintf(buf, max_kctrl_str_len, "%s %d %s", |
---|
2632 | | - "Capture", pcm->device, "User kcontrol"); |
---|
2633 | | - knew.device = pcm->device; |
---|
2634 | | - knew.count = pcm->streams[stream].substream_count; |
---|
2635 | | - knew.private_value = private_value; |
---|
2636 | | - info->kctl = snd_ctl_new1(&knew, info); |
---|
2637 | | - if (!info->kctl) { |
---|
2638 | | - kfree(info); |
---|
2639 | | - kfree(knew.name); |
---|
2640 | | - pr_err("%s: snd_ctl_new failed\n", __func__); |
---|
2641 | | - return -ENOMEM; |
---|
2642 | | - } |
---|
2643 | | - info->kctl->private_free = pcm_usr_ctl_private_free; |
---|
2644 | | - err = snd_ctl_add(pcm->card, info->kctl); |
---|
2645 | | - if (err < 0) { |
---|
2646 | | - kfree(info); |
---|
2647 | | - kfree(knew.name); |
---|
2648 | | - pr_err("%s: snd_ctl_add failed:%d\n", __func__, |
---|
2649 | | - err); |
---|
2650 | | - return -ENOMEM; |
---|
2651 | | - } |
---|
2652 | | - pcm->streams[stream].usr_kctl = info->kctl; |
---|
2653 | | - if (info_ret) |
---|
2654 | | - *info_ret = info; |
---|
2655 | | - kfree(knew.name); |
---|
2656 | | - return 0; |
---|
2657 | | -} |
---|
2658 | | -EXPORT_SYMBOL(snd_pcm_add_usr_ctls); |
---|