| 1 | |
| 2 | |
| 3 | * Digital Audio (PCM) abstract layer
|
| 4 | * Copyright (c) by Jaroslav Kysela <[email protected]>
|
| 5 |
|
| 6 |
|
| 7 | #include <linux/init.h>
|
| 8 | #include <linux/slab.h>
|
| 9 | #include <linux/module.h>
|
| 10 | #include <linux/time.h>
|
| 11 | #include <linux/mutex.h>
|
| 12 | #include <linux/device.h>
|
| 13 | #include <linux/nospec.h>
|
| 14 | #include <sound/core.h>
|
| 15 | #include <sound/minors.h>
|
| 16 | #include <sound/pcm.h>
|
| 17 | #include <sound/timer.h>
|
| 18 | #include <sound/control.h>
|
| 19 | #include <sound/info.h>
|
| 20 |
|
| 21 | #include "pcm_local.h"
|
| 22 |
|
| 23 | MODULE_AUTHOR("Jaroslav Kysela <[email protected]>, Abramo Bagnara <[email protected]>");
|
| 24 | MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
|
| 25 | MODULE_LICENSE("GPL");
|
| 26 |
|
| 27 | static LIST_HEAD(snd_pcm_devices);
|
| 28 | static DEFINE_MUTEX(register_mutex);
|
| 29 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 30 | static LIST_HEAD(snd_pcm_notify_list);
|
| 31 | #endif
|
| 32 |
|
| 33 | static int snd_pcm_free(struct snd_pcm *pcm);
|
| 34 | static int snd_pcm_dev_free(struct snd_device *device);
|
| 35 | static int snd_pcm_dev_register(struct snd_device *device);
|
| 36 | static int snd_pcm_dev_disconnect(struct snd_device *device);
|
| 37 |
|
| 38 | static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
|
| 39 | {
|
| 40 | struct snd_pcm *pcm;
|
| 41 |
|
| 42 | list_for_each_entry(pcm, &snd_pcm_devices, list) {
|
| 43 | if (pcm->card == card && pcm->device == device)
|
| 44 | return pcm;
|
| 45 | }
|
| 46 | return NULL;
|
| 47 | }
|
| 48 |
|
| 49 | static int snd_pcm_next(struct snd_card *card, int device)
|
| 50 | {
|
| 51 | struct snd_pcm *pcm;
|
| 52 |
|
| 53 | list_for_each_entry(pcm, &snd_pcm_devices, list) {
|
| 54 | if (pcm->card == card && pcm->device > device)
|
| 55 | return pcm->device;
|
| 56 | else if (pcm->card->number > card->number)
|
| 57 | return -1;
|
| 58 | }
|
| 59 | return -1;
|
| 60 | }
|
| 61 |
|
| 62 | static int snd_pcm_add(struct snd_pcm *newpcm)
|
| 63 | {
|
| 64 | struct snd_pcm *pcm;
|
| 65 |
|
| 66 | if (newpcm->internal)
|
| 67 | return 0;
|
| 68 |
|
| 69 | list_for_each_entry(pcm, &snd_pcm_devices, list) {
|
| 70 | if (pcm->card == newpcm->card && pcm->device == newpcm->device)
|
| 71 | return -EBUSY;
|
| 72 | if (pcm->card->number > newpcm->card->number ||
|
| 73 | (pcm->card == newpcm->card &&
|
| 74 | pcm->device > newpcm->device)) {
|
| 75 | list_add(&newpcm->list, pcm->list.prev);
|
| 76 | return 0;
|
| 77 | }
|
| 78 | }
|
| 79 | list_add_tail(&newpcm->list, &snd_pcm_devices);
|
| 80 | return 0;
|
| 81 | }
|
| 82 |
|
| 83 | static int snd_pcm_control_ioctl(struct snd_card *card,
|
| 84 | struct snd_ctl_file *control,
|
| 85 | unsigned int cmd, unsigned long arg)
|
| 86 | {
|
| 87 | switch (cmd) {
|
| 88 | case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
|
| 89 | {
|
| 90 | int device;
|
| 91 |
|
| 92 | if (get_user(device, (int __user *)arg))
|
| 93 | return -EFAULT;
|
| 94 | scoped_guard(mutex, ®ister_mutex)
|
| 95 | device = snd_pcm_next(card, device);
|
| 96 | if (put_user(device, (int __user *)arg))
|
| 97 | return -EFAULT;
|
| 98 | return 0;
|
| 99 | }
|
| 100 | case SNDRV_CTL_IOCTL_PCM_INFO:
|
| 101 | {
|
| 102 | struct snd_pcm_info __user *info;
|
| 103 | unsigned int device, subdevice;
|
| 104 | int stream;
|
| 105 | struct snd_pcm *pcm;
|
| 106 | struct snd_pcm_str *pstr;
|
| 107 | struct snd_pcm_substream *substream;
|
| 108 |
|
| 109 | info = (struct snd_pcm_info __user *)arg;
|
| 110 | if (get_user(device, &info->device))
|
| 111 | return -EFAULT;
|
| 112 | if (get_user(stream, &info->stream))
|
| 113 | return -EFAULT;
|
| 114 | if (stream < 0 || stream > 1)
|
| 115 | return -EINVAL;
|
| 116 | stream = array_index_nospec(stream, 2);
|
| 117 | if (get_user(subdevice, &info->subdevice))
|
| 118 | return -EFAULT;
|
| 119 | guard(mutex)(®ister_mutex);
|
| 120 | pcm = snd_pcm_get(card, device);
|
| 121 | if (pcm == NULL)
|
| 122 | return -ENXIO;
|
| 123 | pstr = &pcm->streams[stream];
|
| 124 | if (pstr->substream_count == 0)
|
| 125 | return -ENOENT;
|
| 126 | if (subdevice >= pstr->substream_count)
|
| 127 | return -ENXIO;
|
| 128 | for (substream = pstr->substream; substream;
|
| 129 | substream = substream->next)
|
| 130 | if (substream->number == (int)subdevice)
|
| 131 | break;
|
| 132 | if (substream == NULL)
|
| 133 | return -ENXIO;
|
| 134 | guard(mutex)(&pcm->open_mutex);
|
| 135 | return snd_pcm_info_user(substream, info);
|
| 136 | }
|
| 137 | case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
|
| 138 | {
|
| 139 | int val;
|
| 140 |
|
| 141 | if (get_user(val, (int __user *)arg))
|
| 142 | return -EFAULT;
|
| 143 | control->preferred_subdevice[SND_CTL_SUBDEV_PCM] = val;
|
| 144 | return 0;
|
| 145 | }
|
| 146 | }
|
| 147 | return -ENOIOCTLCMD;
|
| 148 | }
|
| 149 |
|
| 150 | #define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
|
| 151 |
|
| 152 | static const char * const snd_pcm_format_names[] = {
|
| 153 | FORMAT(S8),
|
| 154 | FORMAT(U8),
|
| 155 | FORMAT(S16_LE),
|
| 156 | FORMAT(S16_BE),
|
| 157 | FORMAT(U16_LE),
|
| 158 | FORMAT(U16_BE),
|
| 159 | FORMAT(S24_LE),
|
| 160 | FORMAT(S24_BE),
|
| 161 | FORMAT(U24_LE),
|
| 162 | FORMAT(U24_BE),
|
| 163 | FORMAT(S32_LE),
|
| 164 | FORMAT(S32_BE),
|
| 165 | FORMAT(U32_LE),
|
| 166 | FORMAT(U32_BE),
|
| 167 | FORMAT(FLOAT_LE),
|
| 168 | FORMAT(FLOAT_BE),
|
| 169 | FORMAT(FLOAT64_LE),
|
| 170 | FORMAT(FLOAT64_BE),
|
| 171 | FORMAT(IEC958_SUBFRAME_LE),
|
| 172 | FORMAT(IEC958_SUBFRAME_BE),
|
| 173 | FORMAT(MU_LAW),
|
| 174 | FORMAT(A_LAW),
|
| 175 | FORMAT(IMA_ADPCM),
|
| 176 | FORMAT(MPEG),
|
| 177 | FORMAT(GSM),
|
| 178 | FORMAT(SPECIAL),
|
| 179 | FORMAT(S24_3LE),
|
| 180 | FORMAT(S24_3BE),
|
| 181 | FORMAT(U24_3LE),
|
| 182 | FORMAT(U24_3BE),
|
| 183 | FORMAT(S20_3LE),
|
| 184 | FORMAT(S20_3BE),
|
| 185 | FORMAT(U20_3LE),
|
| 186 | FORMAT(U20_3BE),
|
| 187 | FORMAT(S18_3LE),
|
| 188 | FORMAT(S18_3BE),
|
| 189 | FORMAT(U18_3LE),
|
| 190 | FORMAT(U18_3BE),
|
| 191 | FORMAT(G723_24),
|
| 192 | FORMAT(G723_24_1B),
|
| 193 | FORMAT(G723_40),
|
| 194 | FORMAT(G723_40_1B),
|
| 195 | FORMAT(DSD_U8),
|
| 196 | FORMAT(DSD_U16_LE),
|
| 197 | FORMAT(DSD_U32_LE),
|
| 198 | FORMAT(DSD_U16_BE),
|
| 199 | FORMAT(DSD_U32_BE),
|
| 200 | FORMAT(S20_LE),
|
| 201 | FORMAT(S20_BE),
|
| 202 | FORMAT(U20_LE),
|
| 203 | FORMAT(U20_BE),
|
| 204 | };
|
| 205 |
|
| 206 | |
| 207 | * snd_pcm_format_name - Return a name string for the given PCM format
|
| 208 | * @format: PCM format
|
| 209 | *
|
| 210 | * Return: the format name string
|
| 211 |
|
| 212 | const char *snd_pcm_format_name(snd_pcm_format_t format)
|
| 213 | {
|
| 214 | if (format >= ARRAY_SIZE(snd_pcm_format_names) || !snd_pcm_format_names[format])
|
| 215 | return "Unknown";
|
| 216 | return snd_pcm_format_names[format];
|
| 217 | }
|
| 218 | EXPORT_SYMBOL_GPL(snd_pcm_format_name);
|
| 219 |
|
| 220 | #ifdef CONFIG_SND_VERBOSE_PROCFS
|
| 221 |
|
| 222 | #define STATE(v) [SNDRV_PCM_STATE_##v] = #v
|
| 223 | #define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
|
| 224 | #define READY(v) [SNDRV_PCM_READY_##v] = #v
|
| 225 | #define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
|
| 226 | #define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
|
| 227 | #define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
|
| 228 | #define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
|
| 229 | #define START(v) [SNDRV_PCM_START_##v] = #v
|
| 230 | #define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
|
| 231 |
|
| 232 | static const char * const snd_pcm_stream_names[] = {
|
| 233 | STREAM(PLAYBACK),
|
| 234 | STREAM(CAPTURE),
|
| 235 | };
|
| 236 |
|
| 237 | static const char * const snd_pcm_state_names[] = {
|
| 238 | STATE(OPEN),
|
| 239 | STATE(SETUP),
|
| 240 | STATE(PREPARED),
|
| 241 | STATE(RUNNING),
|
| 242 | STATE(XRUN),
|
| 243 | STATE(DRAINING),
|
| 244 | STATE(PAUSED),
|
| 245 | STATE(SUSPENDED),
|
| 246 | STATE(DISCONNECTED),
|
| 247 | };
|
| 248 |
|
| 249 | static const char * const snd_pcm_access_names[] = {
|
| 250 | ACCESS(MMAP_INTERLEAVED),
|
| 251 | ACCESS(MMAP_NONINTERLEAVED),
|
| 252 | ACCESS(MMAP_COMPLEX),
|
| 253 | ACCESS(RW_INTERLEAVED),
|
| 254 | ACCESS(RW_NONINTERLEAVED),
|
| 255 | };
|
| 256 |
|
| 257 | static const char * const snd_pcm_subformat_names[] = {
|
| 258 | SUBFORMAT(STD),
|
| 259 | SUBFORMAT(MSBITS_MAX),
|
| 260 | SUBFORMAT(MSBITS_20),
|
| 261 | SUBFORMAT(MSBITS_24),
|
| 262 | };
|
| 263 |
|
| 264 | static const char * const snd_pcm_tstamp_mode_names[] = {
|
| 265 | TSTAMP(NONE),
|
| 266 | TSTAMP(ENABLE),
|
| 267 | };
|
| 268 |
|
| 269 | static const char *snd_pcm_stream_name(int stream)
|
| 270 | {
|
| 271 | return snd_pcm_stream_names[stream];
|
| 272 | }
|
| 273 |
|
| 274 | static const char *snd_pcm_access_name(snd_pcm_access_t access)
|
| 275 | {
|
| 276 | return snd_pcm_access_names[access];
|
| 277 | }
|
| 278 |
|
| 279 | static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
|
| 280 | {
|
| 281 | return snd_pcm_subformat_names[subformat];
|
| 282 | }
|
| 283 |
|
| 284 | static const char *snd_pcm_tstamp_mode_name(int mode)
|
| 285 | {
|
| 286 | return snd_pcm_tstamp_mode_names[mode];
|
| 287 | }
|
| 288 |
|
| 289 | static const char *snd_pcm_state_name(snd_pcm_state_t state)
|
| 290 | {
|
| 291 | return snd_pcm_state_names[state];
|
| 292 | }
|
| 293 |
|
| 294 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 295 | #include <linux/soundcard.h>
|
| 296 |
|
| 297 | static const char *snd_pcm_oss_format_name(int format)
|
| 298 | {
|
| 299 | switch (format) {
|
| 300 | case AFMT_MU_LAW:
|
| 301 | return "MU_LAW";
|
| 302 | case AFMT_A_LAW:
|
| 303 | return "A_LAW";
|
| 304 | case AFMT_IMA_ADPCM:
|
| 305 | return "IMA_ADPCM";
|
| 306 | case AFMT_U8:
|
| 307 | return "U8";
|
| 308 | case AFMT_S16_LE:
|
| 309 | return "S16_LE";
|
| 310 | case AFMT_S16_BE:
|
| 311 | return "S16_BE";
|
| 312 | case AFMT_S8:
|
| 313 | return "S8";
|
| 314 | case AFMT_U16_LE:
|
| 315 | return "U16_LE";
|
| 316 | case AFMT_U16_BE:
|
| 317 | return "U16_BE";
|
| 318 | case AFMT_MPEG:
|
| 319 | return "MPEG";
|
| 320 | default:
|
| 321 | return "unknown";
|
| 322 | }
|
| 323 | }
|
| 324 | #endif
|
| 325 |
|
| 326 | static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
|
| 327 | struct snd_info_buffer *buffer)
|
| 328 | {
|
| 329 | int err;
|
| 330 |
|
| 331 | if (! substream)
|
| 332 | return;
|
| 333 |
|
| 334 | struct snd_pcm_info *info __free(kfree) =
|
| 335 | kmalloc_obj(*info);
|
| 336 | if (!info)
|
| 337 | return;
|
| 338 |
|
| 339 | err = snd_pcm_info(substream, info);
|
| 340 | if (err < 0) {
|
| 341 | snd_iprintf(buffer, "error %d\n", err);
|
| 342 | return;
|
| 343 | }
|
| 344 | snd_iprintf(buffer, "card: %d\n", info->card);
|
| 345 | snd_iprintf(buffer, "device: %d\n", info->device);
|
| 346 | snd_iprintf(buffer, "subdevice: %d\n", info->subdevice);
|
| 347 | snd_iprintf(buffer, "stream: %s\n", snd_pcm_stream_name(info->stream));
|
| 348 | snd_iprintf(buffer, "id: %s\n", info->id);
|
| 349 | snd_iprintf(buffer, "name: %s\n", info->name);
|
| 350 | snd_iprintf(buffer, "subname: %s\n", info->subname);
|
| 351 | snd_iprintf(buffer, "class: %d\n", info->dev_class);
|
| 352 | snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
|
| 353 | snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
|
| 354 | snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
|
| 355 | }
|
| 356 |
|
| 357 | static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
|
| 358 | struct snd_info_buffer *buffer)
|
| 359 | {
|
| 360 | snd_pcm_proc_info_read(((struct snd_pcm_str *)entry->private_data)->substream,
|
| 361 | buffer);
|
| 362 | }
|
| 363 |
|
| 364 | static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
|
| 365 | struct snd_info_buffer *buffer)
|
| 366 | {
|
| 367 | snd_pcm_proc_info_read(entry->private_data, buffer);
|
| 368 | }
|
| 369 |
|
| 370 | static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
|
| 371 | struct snd_info_buffer *buffer)
|
| 372 | {
|
| 373 | struct snd_pcm_substream *substream = entry->private_data;
|
| 374 | struct snd_pcm_runtime *runtime;
|
| 375 |
|
| 376 | guard(mutex)(&substream->pcm->open_mutex);
|
| 377 | runtime = substream->runtime;
|
| 378 | if (!runtime) {
|
| 379 | snd_iprintf(buffer, "closed\n");
|
| 380 | return;
|
| 381 | }
|
| 382 | if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
| 383 | snd_iprintf(buffer, "no setup\n");
|
| 384 | return;
|
| 385 | }
|
| 386 | snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
|
| 387 | snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
|
| 388 | snd_iprintf(buffer, "subformat: %s\n", snd_pcm_subformat_name(runtime->subformat));
|
| 389 | snd_iprintf(buffer, "channels: %u\n", runtime->channels);
|
| 390 | snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den);
|
| 391 | snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);
|
| 392 | snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);
|
| 393 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 394 | if (substream->oss.oss) {
|
| 395 | snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
|
| 396 | snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);
|
| 397 | snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate);
|
| 398 | snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);
|
| 399 | snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods);
|
| 400 | snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
|
| 401 | }
|
| 402 | #endif
|
| 403 | }
|
| 404 |
|
| 405 | static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
|
| 406 | struct snd_info_buffer *buffer)
|
| 407 | {
|
| 408 | struct snd_pcm_substream *substream = entry->private_data;
|
| 409 | struct snd_pcm_runtime *runtime;
|
| 410 |
|
| 411 | guard(mutex)(&substream->pcm->open_mutex);
|
| 412 | runtime = substream->runtime;
|
| 413 | if (!runtime) {
|
| 414 | snd_iprintf(buffer, "closed\n");
|
| 415 | return;
|
| 416 | }
|
| 417 | if (runtime->state == SNDRV_PCM_STATE_OPEN) {
|
| 418 | snd_iprintf(buffer, "no setup\n");
|
| 419 | return;
|
| 420 | }
|
| 421 | snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
|
| 422 | snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
|
| 423 | snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min);
|
| 424 | snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold);
|
| 425 | snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold);
|
| 426 | snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
|
| 427 | snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
|
| 428 | snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
|
| 429 | }
|
| 430 |
|
| 431 | static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
|
| 432 | struct snd_info_buffer *buffer)
|
| 433 | {
|
| 434 | struct snd_pcm_substream *substream = entry->private_data;
|
| 435 | struct snd_pcm_runtime *runtime;
|
| 436 | struct snd_pcm_status64 status;
|
| 437 | int err;
|
| 438 |
|
| 439 | guard(mutex)(&substream->pcm->open_mutex);
|
| 440 | runtime = substream->runtime;
|
| 441 | if (!runtime) {
|
| 442 | snd_iprintf(buffer, "closed\n");
|
| 443 | return;
|
| 444 | }
|
| 445 | memset(&status, 0, sizeof(status));
|
| 446 | err = snd_pcm_status64(substream, &status);
|
| 447 | if (err < 0) {
|
| 448 | snd_iprintf(buffer, "error %d\n", err);
|
| 449 | return;
|
| 450 | }
|
| 451 | snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
|
| 452 | snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
|
| 453 | snd_iprintf(buffer, "trigger_time: %lld.%09lld\n",
|
| 454 | status.trigger_tstamp_sec, status.trigger_tstamp_nsec);
|
| 455 | snd_iprintf(buffer, "tstamp : %lld.%09lld\n",
|
| 456 | status.tstamp_sec, status.tstamp_nsec);
|
| 457 | snd_iprintf(buffer, "delay : %ld\n", status.delay);
|
| 458 | snd_iprintf(buffer, "avail : %ld\n", status.avail);
|
| 459 | snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max);
|
| 460 | snd_iprintf(buffer, "-----\n");
|
| 461 | snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
|
| 462 | snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
|
| 463 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
| 464 | snd_iprintf(buffer, "xrun_counter: %d\n", substream->xrun_counter);
|
| 465 | #endif
|
| 466 | }
|
| 467 |
|
| 468 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
| 469 | static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry,
|
| 470 | struct snd_info_buffer *buffer)
|
| 471 | {
|
| 472 | struct snd_pcm_substream *substream = entry->private_data;
|
| 473 |
|
| 474 | snd_pcm_stop_xrun(substream);
|
| 475 | }
|
| 476 |
|
| 477 | static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry,
|
| 478 | struct snd_info_buffer *buffer)
|
| 479 | {
|
| 480 | struct snd_pcm_str *pstr = entry->private_data;
|
| 481 | snd_iprintf(buffer, "%d\n", pstr->xrun_debug);
|
| 482 | }
|
| 483 |
|
| 484 | static void snd_pcm_xrun_debug_write(struct snd_info_entry *entry,
|
| 485 | struct snd_info_buffer *buffer)
|
| 486 | {
|
| 487 | struct snd_pcm_str *pstr = entry->private_data;
|
| 488 | char line[64];
|
| 489 | if (!snd_info_get_line(buffer, line, sizeof(line)))
|
| 490 | pstr->xrun_debug = simple_strtoul(line, NULL, 10);
|
| 491 | }
|
| 492 | #endif
|
| 493 |
|
| 494 | static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
|
| 495 | {
|
| 496 | struct snd_pcm *pcm = pstr->pcm;
|
| 497 | struct snd_info_entry *entry;
|
| 498 | char name[16];
|
| 499 |
|
| 500 | sprintf(name, "pcm%i%c", pcm->device,
|
| 501 | pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
|
| 502 | entry = snd_info_create_card_entry(pcm->card, name,
|
| 503 | pcm->card->proc_root);
|
| 504 | if (!entry)
|
| 505 | return -ENOMEM;
|
| 506 | entry->mode = S_IFDIR | 0555;
|
| 507 | pstr->proc_root = entry;
|
| 508 | entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root);
|
| 509 | if (entry)
|
| 510 | snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);
|
| 511 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
| 512 | entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
|
| 513 | pstr->proc_root);
|
| 514 | if (entry) {
|
| 515 | snd_info_set_text_ops(entry, pstr, snd_pcm_xrun_debug_read);
|
| 516 | entry->c.text.write = snd_pcm_xrun_debug_write;
|
| 517 | entry->mode |= 0200;
|
| 518 | }
|
| 519 | #endif
|
| 520 | return 0;
|
| 521 | }
|
| 522 |
|
| 523 | static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
|
| 524 | {
|
| 525 | snd_info_free_entry(pstr->proc_root);
|
| 526 | pstr->proc_root = NULL;
|
| 527 | return 0;
|
| 528 | }
|
| 529 |
|
| 530 | static struct snd_info_entry *
|
| 531 | create_substream_info_entry(struct snd_pcm_substream *substream,
|
| 532 | const char *name,
|
| 533 | void (*read)(struct snd_info_entry *,
|
| 534 | struct snd_info_buffer *))
|
| 535 | {
|
| 536 | struct snd_info_entry *entry;
|
| 537 |
|
| 538 | entry = snd_info_create_card_entry(substream->pcm->card, name,
|
| 539 | substream->proc_root);
|
| 540 | if (entry)
|
| 541 | snd_info_set_text_ops(entry, substream, read);
|
| 542 | return entry;
|
| 543 | }
|
| 544 |
|
| 545 | static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
|
| 546 | {
|
| 547 | struct snd_info_entry *entry;
|
| 548 | struct snd_card *card;
|
| 549 | char name[16];
|
| 550 |
|
| 551 | card = substream->pcm->card;
|
| 552 |
|
| 553 | sprintf(name, "sub%i", substream->number);
|
| 554 | entry = snd_info_create_card_entry(card, name,
|
| 555 | substream->pstr->proc_root);
|
| 556 | if (!entry)
|
| 557 | return -ENOMEM;
|
| 558 | entry->mode = S_IFDIR | 0555;
|
| 559 | substream->proc_root = entry;
|
| 560 |
|
| 561 | create_substream_info_entry(substream, "info",
|
| 562 | snd_pcm_substream_proc_info_read);
|
| 563 | create_substream_info_entry(substream, "hw_params",
|
| 564 | snd_pcm_substream_proc_hw_params_read);
|
| 565 | create_substream_info_entry(substream, "sw_params",
|
| 566 | snd_pcm_substream_proc_sw_params_read);
|
| 567 | create_substream_info_entry(substream, "status",
|
| 568 | snd_pcm_substream_proc_status_read);
|
| 569 |
|
| 570 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
| 571 | entry = create_substream_info_entry(substream, "xrun_injection", NULL);
|
| 572 | if (entry) {
|
| 573 | entry->c.text.write = snd_pcm_xrun_injection_write;
|
| 574 | entry->mode = S_IFREG | 0200;
|
| 575 | }
|
| 576 | #endif
|
| 577 |
|
| 578 | return 0;
|
| 579 | }
|
| 580 |
|
| 581 | #else
|
| 582 | static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; }
|
| 583 | static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; }
|
| 584 | static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; }
|
| 585 | #endif
|
| 586 |
|
| 587 | static const struct attribute_group *pcm_dev_attr_groups[];
|
| 588 |
|
| 589 | |
| 590 | * PM callbacks: we need to deal only with suspend here, as the resume is
|
| 591 | * triggered either from user-space or the driver's resume callback
|
| 592 |
|
| 593 | static int do_pcm_suspend(struct device *dev)
|
| 594 | {
|
| 595 | struct snd_pcm_str *pstr = dev_get_drvdata(dev);
|
| 596 |
|
| 597 | if (!pstr->pcm->no_device_suspend)
|
| 598 | snd_pcm_suspend_all(pstr->pcm);
|
| 599 | return 0;
|
| 600 | }
|
| 601 |
|
| 602 | static const struct dev_pm_ops pcm_dev_pm_ops = {
|
| 603 | SYSTEM_SLEEP_PM_OPS(do_pcm_suspend, NULL)
|
| 604 | };
|
| 605 |
|
| 606 |
|
| 607 | static const struct device_type pcm_dev_type = {
|
| 608 | .name = "pcm",
|
| 609 | .pm = &pcm_dev_pm_ops,
|
| 610 | };
|
| 611 |
|
| 612 | |
| 613 | * snd_pcm_new_stream - create a new PCM stream
|
| 614 | * @pcm: the pcm instance
|
| 615 | * @stream: the stream direction, SNDRV_PCM_STREAM_XXX
|
| 616 | * @substream_count: the number of substreams
|
| 617 | *
|
| 618 | * Creates a new stream for the pcm.
|
| 619 | * The corresponding stream on the pcm must have been empty before
|
| 620 | * calling this, i.e. zero must be given to the argument of
|
| 621 | * snd_pcm_new().
|
| 622 | *
|
| 623 | * Return: Zero if successful, or a negative error code on failure.
|
| 624 |
|
| 625 | int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
|
| 626 | {
|
| 627 | int idx, err;
|
| 628 | struct snd_pcm_str *pstr = &pcm->streams[stream];
|
| 629 | struct snd_pcm_substream *substream, *prev;
|
| 630 |
|
| 631 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 632 | mutex_init(&pstr->oss.setup_mutex);
|
| 633 | #endif
|
| 634 | pstr->stream = stream;
|
| 635 | pstr->pcm = pcm;
|
| 636 | pstr->substream_count = substream_count;
|
| 637 | if (!substream_count)
|
| 638 | return 0;
|
| 639 |
|
| 640 | err = snd_device_alloc(&pstr->dev, pcm->card);
|
| 641 | if (err < 0)
|
| 642 | return err;
|
| 643 | dev_set_name(pstr->dev, "pcmC%iD%i%c", pcm->card->number, pcm->device,
|
| 644 | stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
|
| 645 | pstr->dev->groups = pcm_dev_attr_groups;
|
| 646 | pstr->dev->type = &pcm_dev_type;
|
| 647 | dev_set_drvdata(pstr->dev, pstr);
|
| 648 |
|
| 649 | if (!pcm->internal) {
|
| 650 | err = snd_pcm_stream_proc_init(pstr);
|
| 651 | if (err < 0) {
|
| 652 | pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
|
| 653 | return err;
|
| 654 | }
|
| 655 | }
|
| 656 | prev = NULL;
|
| 657 | for (idx = 0, prev = NULL; idx < substream_count; idx++) {
|
| 658 | substream = kzalloc_obj(*substream);
|
| 659 | if (!substream)
|
| 660 | return -ENOMEM;
|
| 661 | substream->pcm = pcm;
|
| 662 | substream->pstr = pstr;
|
| 663 | substream->number = idx;
|
| 664 | substream->stream = stream;
|
| 665 | sprintf(substream->name, "subdevice #%i", idx);
|
| 666 | substream->buffer_bytes_max = UINT_MAX;
|
| 667 | if (prev == NULL)
|
| 668 | pstr->substream = substream;
|
| 669 | else
|
| 670 | prev->next = substream;
|
| 671 |
|
| 672 | if (!pcm->internal) {
|
| 673 | err = snd_pcm_substream_proc_init(substream);
|
| 674 | if (err < 0) {
|
| 675 | pcm_err(pcm,
|
| 676 | "Error in snd_pcm_stream_proc_init\n");
|
| 677 | if (prev == NULL)
|
| 678 | pstr->substream = NULL;
|
| 679 | else
|
| 680 | prev->next = NULL;
|
| 681 | kfree(substream);
|
| 682 | return err;
|
| 683 | }
|
| 684 | }
|
| 685 | substream->group = &substream->self_group;
|
| 686 | snd_pcm_group_init(&substream->self_group);
|
| 687 | list_add_tail(&substream->link_list, &substream->self_group.substreams);
|
| 688 | atomic_set(&substream->mmap_count, 0);
|
| 689 | prev = substream;
|
| 690 | }
|
| 691 | return 0;
|
| 692 | }
|
| 693 | EXPORT_SYMBOL(snd_pcm_new_stream);
|
| 694 |
|
| 695 | static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
|
| 696 | int playback_count, int capture_count, bool internal,
|
| 697 | struct snd_pcm **rpcm)
|
| 698 | {
|
| 699 | struct snd_pcm *pcm;
|
| 700 | int err;
|
| 701 | static const struct snd_device_ops ops = {
|
| 702 | .dev_free = snd_pcm_dev_free,
|
| 703 | .dev_register = snd_pcm_dev_register,
|
| 704 | .dev_disconnect = snd_pcm_dev_disconnect,
|
| 705 | };
|
| 706 | static const struct snd_device_ops internal_ops = {
|
| 707 | .dev_free = snd_pcm_dev_free,
|
| 708 | };
|
| 709 |
|
| 710 | if (snd_BUG_ON(!card))
|
| 711 | return -ENXIO;
|
| 712 | if (rpcm)
|
| 713 | *rpcm = NULL;
|
| 714 | pcm = kzalloc_obj(*pcm);
|
| 715 | if (!pcm)
|
| 716 | return -ENOMEM;
|
| 717 | pcm->card = card;
|
| 718 | pcm->device = device;
|
| 719 | pcm->internal = internal;
|
| 720 | mutex_init(&pcm->open_mutex);
|
| 721 | init_waitqueue_head(&pcm->open_wait);
|
| 722 | INIT_LIST_HEAD(&pcm->list);
|
| 723 | if (id)
|
| 724 | strscpy(pcm->id, id, sizeof(pcm->id));
|
| 725 |
|
| 726 | err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
| 727 | playback_count);
|
| 728 | if (err < 0)
|
| 729 | goto free_pcm;
|
| 730 |
|
| 731 | err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count);
|
| 732 | if (err < 0)
|
| 733 | goto free_pcm;
|
| 734 |
|
| 735 | err = snd_device_new(card, SNDRV_DEV_PCM, pcm,
|
| 736 | internal ? &internal_ops : &ops);
|
| 737 | if (err < 0)
|
| 738 | goto free_pcm;
|
| 739 |
|
| 740 | if (rpcm)
|
| 741 | *rpcm = pcm;
|
| 742 | return 0;
|
| 743 |
|
| 744 | free_pcm:
|
| 745 | snd_pcm_free(pcm);
|
| 746 | return err;
|
| 747 | }
|
| 748 |
|
| 749 | |
| 750 | * snd_pcm_new - create a new PCM instance
|
| 751 | * @card: the card instance
|
| 752 | * @id: the id string
|
| 753 | * @device: the device index (zero based)
|
| 754 | * @playback_count: the number of substreams for playback
|
| 755 | * @capture_count: the number of substreams for capture
|
| 756 | * @rpcm: the pointer to store the new pcm instance
|
| 757 | *
|
| 758 | * Creates a new PCM instance.
|
| 759 | *
|
| 760 | * The pcm operators have to be set afterwards to the new instance
|
| 761 | * via snd_pcm_set_ops().
|
| 762 | *
|
| 763 | * Return: Zero if successful, or a negative error code on failure.
|
| 764 |
|
| 765 | int snd_pcm_new(struct snd_card *card, const char *id, int device,
|
| 766 | int playback_count, int capture_count, struct snd_pcm **rpcm)
|
| 767 | {
|
| 768 | return _snd_pcm_new(card, id, device, playback_count, capture_count,
|
| 769 | false, rpcm);
|
| 770 | }
|
| 771 | EXPORT_SYMBOL(snd_pcm_new);
|
| 772 |
|
| 773 | |
| 774 | * snd_pcm_new_internal - create a new internal PCM instance
|
| 775 | * @card: the card instance
|
| 776 | * @id: the id string
|
| 777 | * @device: the device index (zero based - shared with normal PCMs)
|
| 778 | * @playback_count: the number of substreams for playback
|
| 779 | * @capture_count: the number of substreams for capture
|
| 780 | * @rpcm: the pointer to store the new pcm instance
|
| 781 | *
|
| 782 | * Creates a new internal PCM instance with no userspace device or procfs
|
| 783 | * entries. This is used by ASoC Back End PCMs in order to create a PCM that
|
| 784 | * will only be used internally by kernel drivers. i.e. it cannot be opened
|
| 785 | * by userspace. It provides existing ASoC components drivers with a substream
|
| 786 | * and access to any private data.
|
| 787 | *
|
| 788 | * The pcm operators have to be set afterwards to the new instance
|
| 789 | * via snd_pcm_set_ops().
|
| 790 | *
|
| 791 | * Return: Zero if successful, or a negative error code on failure.
|
| 792 |
|
| 793 | int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
|
| 794 | int playback_count, int capture_count,
|
| 795 | struct snd_pcm **rpcm)
|
| 796 | {
|
| 797 | return _snd_pcm_new(card, id, device, playback_count, capture_count,
|
| 798 | true, rpcm);
|
| 799 | }
|
| 800 | EXPORT_SYMBOL(snd_pcm_new_internal);
|
| 801 |
|
| 802 | static void free_chmap(struct snd_pcm_str *pstr)
|
| 803 | {
|
| 804 | if (pstr->chmap_kctl) {
|
| 805 | struct snd_card *card = pstr->pcm->card;
|
| 806 |
|
| 807 | snd_ctl_remove(card, pstr->chmap_kctl);
|
| 808 | pstr->chmap_kctl = NULL;
|
| 809 | }
|
| 810 | }
|
| 811 |
|
| 812 | static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
|
| 813 | {
|
| 814 | struct snd_pcm_substream *substream, *substream_next;
|
| 815 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 816 | struct snd_pcm_oss_setup *setup, *setupn;
|
| 817 | #endif
|
| 818 |
|
| 819 |
|
| 820 | snd_pcm_stream_proc_done(pstr);
|
| 821 |
|
| 822 | substream = pstr->substream;
|
| 823 | while (substream) {
|
| 824 | substream_next = substream->next;
|
| 825 | snd_pcm_timer_done(substream);
|
| 826 | kfree(substream);
|
| 827 | substream = substream_next;
|
| 828 | }
|
| 829 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 830 | for (setup = pstr->oss.setup_list; setup; setup = setupn) {
|
| 831 | setupn = setup->next;
|
| 832 | kfree(setup->task_name);
|
| 833 | kfree(setup);
|
| 834 | }
|
| 835 | #endif
|
| 836 | free_chmap(pstr);
|
| 837 | if (pstr->substream_count)
|
| 838 | put_device(pstr->dev);
|
| 839 | }
|
| 840 |
|
| 841 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 842 | #define pcm_call_notify(pcm, call) \
|
| 843 | do { \
|
| 844 | struct snd_pcm_notify *_notify; \
|
| 845 | list_for_each_entry(_notify, &snd_pcm_notify_list, list) \
|
| 846 | _notify->call(pcm); \
|
| 847 | } while (0)
|
| 848 | #else
|
| 849 | #define pcm_call_notify(pcm, call) do {} while (0)
|
| 850 | #endif
|
| 851 |
|
| 852 | static int snd_pcm_free(struct snd_pcm *pcm)
|
| 853 | {
|
| 854 | if (!pcm)
|
| 855 | return 0;
|
| 856 | if (!pcm->internal)
|
| 857 | pcm_call_notify(pcm, n_unregister);
|
| 858 | if (pcm->private_free)
|
| 859 | pcm->private_free(pcm);
|
| 860 | snd_pcm_lib_preallocate_free_for_all(pcm);
|
| 861 | snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]);
|
| 862 | snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]);
|
| 863 | kfree(pcm);
|
| 864 | return 0;
|
| 865 | }
|
| 866 |
|
| 867 | static int snd_pcm_dev_free(struct snd_device *device)
|
| 868 | {
|
| 869 | struct snd_pcm *pcm = device->device_data;
|
| 870 | return snd_pcm_free(pcm);
|
| 871 | }
|
| 872 |
|
| 873 | int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
|
| 874 | struct file *file,
|
| 875 | struct snd_pcm_substream **rsubstream)
|
| 876 | {
|
| 877 | struct snd_pcm_str * pstr;
|
| 878 | struct snd_pcm_substream *substream;
|
| 879 | struct snd_pcm_runtime *runtime;
|
| 880 | struct snd_card *card;
|
| 881 | int prefer_subdevice;
|
| 882 | size_t size;
|
| 883 |
|
| 884 | if (snd_BUG_ON(!pcm || !rsubstream))
|
| 885 | return -ENXIO;
|
| 886 | if (snd_BUG_ON(stream != SNDRV_PCM_STREAM_PLAYBACK &&
|
| 887 | stream != SNDRV_PCM_STREAM_CAPTURE))
|
| 888 | return -EINVAL;
|
| 889 | *rsubstream = NULL;
|
| 890 | pstr = &pcm->streams[stream];
|
| 891 | if (pstr->substream == NULL || pstr->substream_count == 0)
|
| 892 | return -ENODEV;
|
| 893 |
|
| 894 | card = pcm->card;
|
| 895 | prefer_subdevice = snd_ctl_get_preferred_subdevice(card, SND_CTL_SUBDEV_PCM);
|
| 896 |
|
| 897 | if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
|
| 898 | int opposite = !stream;
|
| 899 |
|
| 900 | for (substream = pcm->streams[opposite].substream; substream;
|
| 901 | substream = substream->next) {
|
| 902 | if (SUBSTREAM_BUSY(substream))
|
| 903 | return -EAGAIN;
|
| 904 | }
|
| 905 | }
|
| 906 |
|
| 907 | if (file->f_flags & O_APPEND) {
|
| 908 | if (prefer_subdevice < 0) {
|
| 909 | if (pstr->substream_count > 1)
|
| 910 | return -EINVAL;
|
| 911 | substream = pstr->substream;
|
| 912 | } else {
|
| 913 | for (substream = pstr->substream; substream;
|
| 914 | substream = substream->next)
|
| 915 | if (substream->number == prefer_subdevice)
|
| 916 | break;
|
| 917 | }
|
| 918 | if (! substream)
|
| 919 | return -ENODEV;
|
| 920 | if (! SUBSTREAM_BUSY(substream))
|
| 921 | return -EBADFD;
|
| 922 | substream->ref_count++;
|
| 923 | *rsubstream = substream;
|
| 924 | return 0;
|
| 925 | }
|
| 926 |
|
| 927 | for (substream = pstr->substream; substream; substream = substream->next) {
|
| 928 | if (!SUBSTREAM_BUSY(substream) &&
|
| 929 | (prefer_subdevice == -1 ||
|
| 930 | substream->number == prefer_subdevice))
|
| 931 | break;
|
| 932 | }
|
| 933 | if (substream == NULL)
|
| 934 | return -EAGAIN;
|
| 935 |
|
| 936 | runtime = kzalloc_obj(*runtime);
|
| 937 | if (runtime == NULL)
|
| 938 | return -ENOMEM;
|
| 939 |
|
| 940 | size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
|
| 941 | runtime->status = alloc_pages_exact(size, GFP_KERNEL);
|
| 942 | if (runtime->status == NULL) {
|
| 943 | kfree(runtime);
|
| 944 | return -ENOMEM;
|
| 945 | }
|
| 946 | memset(runtime->status, 0, size);
|
| 947 |
|
| 948 | size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
|
| 949 | runtime->control = alloc_pages_exact(size, GFP_KERNEL);
|
| 950 | if (runtime->control == NULL) {
|
| 951 | free_pages_exact(runtime->status,
|
| 952 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
|
| 953 | kfree(runtime);
|
| 954 | return -ENOMEM;
|
| 955 | }
|
| 956 | memset(runtime->control, 0, size);
|
| 957 |
|
| 958 | init_waitqueue_head(&runtime->sleep);
|
| 959 | init_waitqueue_head(&runtime->tsleep);
|
| 960 |
|
| 961 | __snd_pcm_set_state(runtime, SNDRV_PCM_STATE_OPEN);
|
| 962 | mutex_init(&runtime->buffer_mutex);
|
| 963 | atomic_set(&runtime->buffer_accessing, 0);
|
| 964 |
|
| 965 | substream->runtime = runtime;
|
| 966 | substream->private_data = pcm->private_data;
|
| 967 | substream->ref_count = 1;
|
| 968 | substream->f_flags = file->f_flags;
|
| 969 | substream->pid = get_pid(task_pid(current));
|
| 970 | pstr->substream_opened++;
|
| 971 | *rsubstream = substream;
|
| 972 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG
|
| 973 | substream->xrun_counter = 0;
|
| 974 | #endif
|
| 975 | return 0;
|
| 976 | }
|
| 977 |
|
| 978 | void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
| 979 | {
|
| 980 | struct snd_pcm_runtime *runtime;
|
| 981 |
|
| 982 | if (PCM_RUNTIME_CHECK(substream))
|
| 983 | return;
|
| 984 | runtime = substream->runtime;
|
| 985 | if (runtime->private_free != NULL)
|
| 986 | runtime->private_free(runtime);
|
| 987 | free_pages_exact(runtime->status,
|
| 988 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
|
| 989 | free_pages_exact(runtime->control,
|
| 990 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
|
| 991 | kfree(runtime->hw_constraints.rules);
|
| 992 |
|
| 993 | if (substream->timer) {
|
| 994 | scoped_guard(spinlock_irq, &substream->timer->lock)
|
| 995 | substream->runtime = NULL;
|
| 996 | } else {
|
| 997 | substream->runtime = NULL;
|
| 998 | }
|
| 999 | mutex_destroy(&runtime->buffer_mutex);
|
| 1000 | snd_fasync_free(runtime->fasync);
|
| 1001 | kfree(runtime);
|
| 1002 | put_pid(substream->pid);
|
| 1003 | substream->pid = NULL;
|
| 1004 | substream->pstr->substream_opened--;
|
| 1005 | }
|
| 1006 |
|
| 1007 | static ssize_t pcm_class_show(struct device *dev,
|
| 1008 | struct device_attribute *attr, char *buf)
|
| 1009 | {
|
| 1010 | struct snd_pcm_str *pstr = dev_get_drvdata(dev);
|
| 1011 | struct snd_pcm *pcm = pstr->pcm;
|
| 1012 | const char *str;
|
| 1013 | static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
|
| 1014 | [SNDRV_PCM_CLASS_GENERIC] = "generic",
|
| 1015 | [SNDRV_PCM_CLASS_MULTI] = "multi",
|
| 1016 | [SNDRV_PCM_CLASS_MODEM] = "modem",
|
| 1017 | [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
|
| 1018 | };
|
| 1019 |
|
| 1020 | if (pcm->dev_class > SNDRV_PCM_CLASS_LAST)
|
| 1021 | str = "none";
|
| 1022 | else
|
| 1023 | str = strs[pcm->dev_class];
|
| 1024 | return sysfs_emit(buf, "%s\n", str);
|
| 1025 | }
|
| 1026 |
|
| 1027 | static DEVICE_ATTR_RO(pcm_class);
|
| 1028 | static struct attribute *pcm_dev_attrs[] = {
|
| 1029 | &dev_attr_pcm_class.attr,
|
| 1030 | NULL
|
| 1031 | };
|
| 1032 |
|
| 1033 | static const struct attribute_group pcm_dev_attr_group = {
|
| 1034 | .attrs = pcm_dev_attrs,
|
| 1035 | };
|
| 1036 |
|
| 1037 | static const struct attribute_group *pcm_dev_attr_groups[] = {
|
| 1038 | &pcm_dev_attr_group,
|
| 1039 | NULL
|
| 1040 | };
|
| 1041 |
|
| 1042 | static int snd_pcm_dev_register(struct snd_device *device)
|
| 1043 | {
|
| 1044 | int cidx, err;
|
| 1045 | struct snd_pcm_substream *substream;
|
| 1046 | struct snd_pcm *pcm;
|
| 1047 |
|
| 1048 | if (snd_BUG_ON(!device || !device->device_data))
|
| 1049 | return -ENXIO;
|
| 1050 | pcm = device->device_data;
|
| 1051 |
|
| 1052 | guard(mutex)(®ister_mutex);
|
| 1053 | err = snd_pcm_add(pcm);
|
| 1054 | if (err)
|
| 1055 | return err;
|
| 1056 | for (cidx = 0; cidx < 2; cidx++) {
|
| 1057 | int devtype = -1;
|
| 1058 | if (pcm->streams[cidx].substream == NULL)
|
| 1059 | continue;
|
| 1060 | switch (cidx) {
|
| 1061 | case SNDRV_PCM_STREAM_PLAYBACK:
|
| 1062 | devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
|
| 1063 | break;
|
| 1064 | case SNDRV_PCM_STREAM_CAPTURE:
|
| 1065 | devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
|
| 1066 | break;
|
| 1067 | }
|
| 1068 |
|
| 1069 | err = snd_register_device(devtype, pcm->card, pcm->device,
|
| 1070 | &snd_pcm_f_ops[cidx], pcm,
|
| 1071 | pcm->streams[cidx].dev);
|
| 1072 | if (err < 0) {
|
| 1073 | list_del_init(&pcm->list);
|
| 1074 | return err;
|
| 1075 | }
|
| 1076 |
|
| 1077 | for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
|
| 1078 | snd_pcm_timer_init(substream);
|
| 1079 | }
|
| 1080 |
|
| 1081 | pcm_call_notify(pcm, n_register);
|
| 1082 | return err;
|
| 1083 | }
|
| 1084 |
|
| 1085 | static int snd_pcm_dev_disconnect(struct snd_device *device)
|
| 1086 | {
|
| 1087 | struct snd_pcm *pcm = device->device_data;
|
| 1088 | struct snd_pcm_substream *substream;
|
| 1089 | int cidx;
|
| 1090 |
|
| 1091 | guard(mutex)(®ister_mutex);
|
| 1092 | guard(mutex)(&pcm->open_mutex);
|
| 1093 | wake_up(&pcm->open_wait);
|
| 1094 | list_del_init(&pcm->list);
|
| 1095 |
|
| 1096 | for_each_pcm_substream(pcm, cidx, substream) {
|
| 1097 | snd_pcm_stream_lock_irq(substream);
|
| 1098 | if (substream->runtime) {
|
| 1099 | if (snd_pcm_running(substream))
|
| 1100 | snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
|
| 1101 |
|
| 1102 | __snd_pcm_set_state(substream->runtime,
|
| 1103 | SNDRV_PCM_STATE_DISCONNECTED);
|
| 1104 | wake_up(&substream->runtime->sleep);
|
| 1105 | wake_up(&substream->runtime->tsleep);
|
| 1106 | }
|
| 1107 | snd_pcm_stream_unlock_irq(substream);
|
| 1108 | }
|
| 1109 |
|
| 1110 | for_each_pcm_substream(pcm, cidx, substream)
|
| 1111 | snd_pcm_sync_stop(substream, false);
|
| 1112 |
|
| 1113 | pcm_call_notify(pcm, n_disconnect);
|
| 1114 | for (cidx = 0; cidx < 2; cidx++) {
|
| 1115 | if (pcm->streams[cidx].dev)
|
| 1116 | snd_unregister_device(pcm->streams[cidx].dev);
|
| 1117 | free_chmap(&pcm->streams[cidx]);
|
| 1118 | }
|
| 1119 | return 0;
|
| 1120 | }
|
| 1121 |
|
| 1122 | #if IS_ENABLED(CONFIG_SND_PCM_OSS)
|
| 1123 | |
| 1124 | * snd_pcm_notify - Add/remove the notify list
|
| 1125 | * @notify: PCM notify list
|
| 1126 | * @nfree: 0 = register, 1 = unregister
|
| 1127 | *
|
| 1128 | * This adds the given notifier to the global list so that the callback is
|
| 1129 | * called for each registered PCM devices. This exists only for PCM OSS
|
| 1130 | * emulation, so far.
|
| 1131 | *
|
| 1132 | * Return: zero if successful, or a negative error code
|
| 1133 |
|
| 1134 | int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
|
| 1135 | {
|
| 1136 | struct snd_pcm *pcm;
|
| 1137 |
|
| 1138 | if (snd_BUG_ON(!notify ||
|
| 1139 | !notify->n_register ||
|
| 1140 | !notify->n_unregister ||
|
| 1141 | !notify->n_disconnect))
|
| 1142 | return -EINVAL;
|
| 1143 | guard(mutex)(®ister_mutex);
|
| 1144 | if (nfree) {
|
| 1145 | list_del(¬ify->list);
|
| 1146 | list_for_each_entry(pcm, &snd_pcm_devices, list)
|
| 1147 | notify->n_unregister(pcm);
|
| 1148 | } else {
|
| 1149 | list_add_tail(¬ify->list, &snd_pcm_notify_list);
|
| 1150 | list_for_each_entry(pcm, &snd_pcm_devices, list)
|
| 1151 | notify->n_register(pcm);
|
| 1152 | }
|
| 1153 | return 0;
|
| 1154 | }
|
| 1155 | EXPORT_SYMBOL(snd_pcm_notify);
|
| 1156 | #endif
|
| 1157 |
|
| 1158 | #ifdef CONFIG_SND_PROC_FS
|
| 1159 | |
| 1160 | * Info interface
|
| 1161 |
|
| 1162 |
|
| 1163 | static void snd_pcm_proc_read(struct snd_info_entry *entry,
|
| 1164 | struct snd_info_buffer *buffer)
|
| 1165 | {
|
| 1166 | struct snd_pcm *pcm;
|
| 1167 |
|
| 1168 | guard(mutex)(®ister_mutex);
|
| 1169 | list_for_each_entry(pcm, &snd_pcm_devices, list) {
|
| 1170 | snd_iprintf(buffer, "%02i-%02i: %s : %s",
|
| 1171 | pcm->card->number, pcm->device, pcm->id, pcm->name);
|
| 1172 | if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
|
| 1173 | snd_iprintf(buffer, " : playback %i",
|
| 1174 | pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);
|
| 1175 | if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
|
| 1176 | snd_iprintf(buffer, " : capture %i",
|
| 1177 | pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
|
| 1178 | snd_iprintf(buffer, "\n");
|
| 1179 | }
|
| 1180 | }
|
| 1181 |
|
| 1182 | static struct snd_info_entry *snd_pcm_proc_entry;
|
| 1183 |
|
| 1184 | static void snd_pcm_proc_init(void)
|
| 1185 | {
|
| 1186 | struct snd_info_entry *entry;
|
| 1187 |
|
| 1188 | entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL);
|
| 1189 | if (entry) {
|
| 1190 | snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);
|
| 1191 | if (snd_info_register(entry) < 0) {
|
| 1192 | snd_info_free_entry(entry);
|
| 1193 | entry = NULL;
|
| 1194 | }
|
| 1195 | }
|
| 1196 | snd_pcm_proc_entry = entry;
|
| 1197 | }
|
| 1198 |
|
| 1199 | static void snd_pcm_proc_done(void)
|
| 1200 | {
|
| 1201 | snd_info_free_entry(snd_pcm_proc_entry);
|
| 1202 | }
|
| 1203 |
|
| 1204 | #else
|
| 1205 | #define snd_pcm_proc_init()
|
| 1206 | #define snd_pcm_proc_done()
|
| 1207 | #endif
|
| 1208 |
|
| 1209 |
|
| 1210 | |
| 1211 | * ENTRY functions
|
| 1212 |
|
| 1213 |
|
| 1214 | static int __init alsa_pcm_init(void)
|
| 1215 | {
|
| 1216 | snd_ctl_register_ioctl(snd_pcm_control_ioctl);
|
| 1217 | snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
|
| 1218 | snd_pcm_proc_init();
|
| 1219 | return 0;
|
| 1220 | }
|
| 1221 |
|
| 1222 | static void __exit alsa_pcm_exit(void)
|
| 1223 | {
|
| 1224 | snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
|
| 1225 | snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
|
| 1226 | snd_pcm_proc_done();
|
| 1227 | }
|
| 1228 |
|
| 1229 | module_init(alsa_pcm_init)
|
| 1230 | module_exit(alsa_pcm_exit)
|