blob: 8f624b7af0ca8dd5e5ad8f198729f838e6869cc5 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Digital Audio (PCM) abstract layer
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02003 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
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 */
21
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/init.h>
23#include <linux/slab.h>
Paul Gortmakerda155d52011-07-15 12:38:28 -040024#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/time.h>
Ingo Molnar1a60d4c2006-01-16 16:29:08 +010026#include <linux/mutex.h>
Paul Gortmaker51990e82012-01-22 11:23:42 -050027#include <linux/device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <sound/core.h>
29#include <sound/minors.h>
30#include <sound/pcm.h>
31#include <sound/control.h>
32#include <sound/info.h>
33
Jaroslav Kyselac1017a42007-10-15 09:50:19 +020034MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
Linus Torvalds1da177e2005-04-16 15:20:36 -070035MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
36MODULE_LICENSE("GPL");
37
Clemens Ladischf87135f2005-11-20 14:06:59 +010038static LIST_HEAD(snd_pcm_devices);
Linus Torvalds1da177e2005-04-16 15:20:36 -070039static LIST_HEAD(snd_pcm_notify_list);
Ingo Molnar1a60d4c2006-01-16 16:29:08 +010040static DEFINE_MUTEX(register_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -070041
Takashi Iwai877211f2005-11-17 13:59:38 +010042static int snd_pcm_free(struct snd_pcm *pcm);
43static int snd_pcm_dev_free(struct snd_device *device);
44static int snd_pcm_dev_register(struct snd_device *device);
45static int snd_pcm_dev_disconnect(struct snd_device *device);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Pawel MOLLf90c06a2008-07-30 12:46:40 +010047static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
Clemens Ladischf87135f2005-11-20 14:06:59 +010048{
Clemens Ladischf87135f2005-11-20 14:06:59 +010049 struct snd_pcm *pcm;
50
Johannes Berg9244b2c2006-10-05 16:02:22 +020051 list_for_each_entry(pcm, &snd_pcm_devices, list) {
Russell Kinga4461f42013-10-31 15:01:37 +000052 if (pcm->internal)
53 continue;
Clemens Ladischf87135f2005-11-20 14:06:59 +010054 if (pcm->card == card && pcm->device == device)
55 return pcm;
56 }
57 return NULL;
58}
59
Pawel MOLLf90c06a2008-07-30 12:46:40 +010060static int snd_pcm_next(struct snd_card *card, int device)
61{
62 struct snd_pcm *pcm;
63
64 list_for_each_entry(pcm, &snd_pcm_devices, list) {
Russell Kinga4461f42013-10-31 15:01:37 +000065 if (pcm->internal)
66 continue;
Pawel MOLLf90c06a2008-07-30 12:46:40 +010067 if (pcm->card == card && pcm->device > device)
68 return pcm->device;
69 else if (pcm->card->number > card->number)
70 return -1;
71 }
72 return -1;
73}
74
75static int snd_pcm_add(struct snd_pcm *newpcm)
76{
77 struct snd_pcm *pcm;
78
79 list_for_each_entry(pcm, &snd_pcm_devices, list) {
80 if (pcm->card == newpcm->card && pcm->device == newpcm->device)
81 return -EBUSY;
82 if (pcm->card->number > newpcm->card->number ||
83 (pcm->card == newpcm->card &&
84 pcm->device > newpcm->device)) {
85 list_add(&newpcm->list, pcm->list.prev);
86 return 0;
87 }
88 }
89 list_add_tail(&newpcm->list, &snd_pcm_devices);
90 return 0;
91}
92
Takashi Iwai877211f2005-11-17 13:59:38 +010093static int snd_pcm_control_ioctl(struct snd_card *card,
94 struct snd_ctl_file *control,
Linus Torvalds1da177e2005-04-16 15:20:36 -070095 unsigned int cmd, unsigned long arg)
96{
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 switch (cmd) {
98 case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
99 {
100 int device;
101
102 if (get_user(device, (int __user *)arg))
103 return -EFAULT;
Ingo Molnar1a60d4c2006-01-16 16:29:08 +0100104 mutex_lock(&register_mutex);
Pawel MOLLf90c06a2008-07-30 12:46:40 +0100105 device = snd_pcm_next(card, device);
Ingo Molnar1a60d4c2006-01-16 16:29:08 +0100106 mutex_unlock(&register_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 if (put_user(device, (int __user *)arg))
108 return -EFAULT;
109 return 0;
110 }
111 case SNDRV_CTL_IOCTL_PCM_INFO:
112 {
Takashi Iwai877211f2005-11-17 13:59:38 +0100113 struct snd_pcm_info __user *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 unsigned int device, subdevice;
Takashi Iwai877211f2005-11-17 13:59:38 +0100115 int stream;
116 struct snd_pcm *pcm;
117 struct snd_pcm_str *pstr;
118 struct snd_pcm_substream *substream;
Clemens Ladischf87135f2005-11-20 14:06:59 +0100119 int err;
120
Takashi Iwai877211f2005-11-17 13:59:38 +0100121 info = (struct snd_pcm_info __user *)arg;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 if (get_user(device, &info->device))
123 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 if (get_user(stream, &info->stream))
125 return -EFAULT;
126 if (stream < 0 || stream > 1)
127 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 if (get_user(subdevice, &info->subdevice))
129 return -EFAULT;
Ingo Molnar1a60d4c2006-01-16 16:29:08 +0100130 mutex_lock(&register_mutex);
Pawel MOLLf90c06a2008-07-30 12:46:40 +0100131 pcm = snd_pcm_get(card, device);
Clemens Ladischf87135f2005-11-20 14:06:59 +0100132 if (pcm == NULL) {
133 err = -ENXIO;
134 goto _error;
135 }
136 pstr = &pcm->streams[stream];
137 if (pstr->substream_count == 0) {
138 err = -ENOENT;
139 goto _error;
140 }
141 if (subdevice >= pstr->substream_count) {
142 err = -ENXIO;
143 goto _error;
144 }
145 for (substream = pstr->substream; substream;
146 substream = substream->next)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 if (substream->number == (int)subdevice)
148 break;
Clemens Ladischf87135f2005-11-20 14:06:59 +0100149 if (substream == NULL) {
150 err = -ENXIO;
151 goto _error;
152 }
153 err = snd_pcm_info_user(substream, info);
154 _error:
Ingo Molnar1a60d4c2006-01-16 16:29:08 +0100155 mutex_unlock(&register_mutex);
Clemens Ladischf87135f2005-11-20 14:06:59 +0100156 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157 }
158 case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
159 {
160 int val;
161
162 if (get_user(val, (int __user *)arg))
163 return -EFAULT;
164 control->prefer_pcm_subdevice = val;
165 return 0;
166 }
167 }
168 return -ENOIOCTLCMD;
169}
Jaroslav Kysela21a34792006-01-13 09:12:11 +0100170
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171#define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173static char *snd_pcm_format_names[] = {
174 FORMAT(S8),
175 FORMAT(U8),
176 FORMAT(S16_LE),
177 FORMAT(S16_BE),
178 FORMAT(U16_LE),
179 FORMAT(U16_BE),
180 FORMAT(S24_LE),
181 FORMAT(S24_BE),
182 FORMAT(U24_LE),
183 FORMAT(U24_BE),
184 FORMAT(S32_LE),
185 FORMAT(S32_BE),
186 FORMAT(U32_LE),
187 FORMAT(U32_BE),
188 FORMAT(FLOAT_LE),
189 FORMAT(FLOAT_BE),
190 FORMAT(FLOAT64_LE),
191 FORMAT(FLOAT64_BE),
192 FORMAT(IEC958_SUBFRAME_LE),
193 FORMAT(IEC958_SUBFRAME_BE),
194 FORMAT(MU_LAW),
195 FORMAT(A_LAW),
196 FORMAT(IMA_ADPCM),
197 FORMAT(MPEG),
198 FORMAT(GSM),
199 FORMAT(SPECIAL),
200 FORMAT(S24_3LE),
201 FORMAT(S24_3BE),
202 FORMAT(U24_3LE),
203 FORMAT(U24_3BE),
204 FORMAT(S20_3LE),
205 FORMAT(S20_3BE),
206 FORMAT(U20_3LE),
207 FORMAT(U20_3BE),
208 FORMAT(S18_3LE),
209 FORMAT(S18_3BE),
210 FORMAT(U18_3LE),
211 FORMAT(U18_3BE),
Dan Carpenter7a288262010-08-27 22:02:15 +0200212 FORMAT(G723_24),
213 FORMAT(G723_24_1B),
214 FORMAT(G723_40),
215 FORMAT(G723_40_1B),
Daniel Mackef7a4f92013-04-17 00:01:36 +0800216 FORMAT(DSD_U8),
217 FORMAT(DSD_U16_LE),
Jurgen Kramerd4288d32014-09-05 10:47:56 +0200218 FORMAT(DSD_U32_LE),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219};
220
Takashi Iwai30b771c2014-10-30 15:02:50 +0100221/**
222 * snd_pcm_format_name - Return a name string for the given PCM format
223 * @format: PCM format
224 */
Takashi Iwai6e5265e2009-09-08 14:26:51 +0200225const char *snd_pcm_format_name(snd_pcm_format_t format)
Takashi Iwaie28563c2005-12-01 10:42:42 +0100226{
Clemens Ladischfea952e2011-02-14 11:00:47 +0100227 if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
Dan Carpenter7a288262010-08-27 22:02:15 +0200228 return "Unknown";
Clemens Ladischfea952e2011-02-14 11:00:47 +0100229 return snd_pcm_format_names[(__force unsigned int)format];
Takashi Iwaie28563c2005-12-01 10:42:42 +0100230}
Takashi Iwai6e5265e2009-09-08 14:26:51 +0200231EXPORT_SYMBOL_GPL(snd_pcm_format_name);
232
233#ifdef CONFIG_SND_VERBOSE_PROCFS
234
235#define STATE(v) [SNDRV_PCM_STATE_##v] = #v
236#define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
237#define READY(v) [SNDRV_PCM_READY_##v] = #v
238#define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
239#define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
240#define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
241#define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
242#define START(v) [SNDRV_PCM_START_##v] = #v
243#define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v
Takashi Iwaie28563c2005-12-01 10:42:42 +0100244
Takashi Iwaie28563c2005-12-01 10:42:42 +0100245static char *snd_pcm_stream_names[] = {
246 STREAM(PLAYBACK),
247 STREAM(CAPTURE),
248};
249
250static char *snd_pcm_state_names[] = {
251 STATE(OPEN),
252 STATE(SETUP),
253 STATE(PREPARED),
254 STATE(RUNNING),
255 STATE(XRUN),
256 STATE(DRAINING),
257 STATE(PAUSED),
258 STATE(SUSPENDED),
259};
260
261static char *snd_pcm_access_names[] = {
262 ACCESS(MMAP_INTERLEAVED),
263 ACCESS(MMAP_NONINTERLEAVED),
264 ACCESS(MMAP_COMPLEX),
265 ACCESS(RW_INTERLEAVED),
266 ACCESS(RW_NONINTERLEAVED),
267};
268
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269static char *snd_pcm_subformat_names[] = {
270 SUBFORMAT(STD),
271};
272
273static char *snd_pcm_tstamp_mode_names[] = {
274 TSTAMP(NONE),
Jaroslav Kysela8c121582008-01-11 08:45:08 +0100275 TSTAMP(ENABLE),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276};
277
Takashi Iwai877211f2005-11-17 13:59:38 +0100278static const char *snd_pcm_stream_name(int stream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 return snd_pcm_stream_names[stream];
281}
282
283static const char *snd_pcm_access_name(snd_pcm_access_t access)
284{
Clemens Ladischfea952e2011-02-14 11:00:47 +0100285 return snd_pcm_access_names[(__force int)access];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700286}
287
Linus Torvalds1da177e2005-04-16 15:20:36 -0700288static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
289{
Clemens Ladischfea952e2011-02-14 11:00:47 +0100290 return snd_pcm_subformat_names[(__force int)subformat];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291}
292
Takashi Iwai877211f2005-11-17 13:59:38 +0100293static const char *snd_pcm_tstamp_mode_name(int mode)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700294{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295 return snd_pcm_tstamp_mode_names[mode];
296}
297
298static const char *snd_pcm_state_name(snd_pcm_state_t state)
299{
Clemens Ladischfea952e2011-02-14 11:00:47 +0100300 return snd_pcm_state_names[(__force int)state];
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301}
302
Takashi Iwai8eeaa2f2014-02-10 09:48:47 +0100303#if IS_ENABLED(CONFIG_SND_PCM_OSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304#include <linux/soundcard.h>
Ingo Molnar1a60d4c2006-01-16 16:29:08 +0100305
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306static const char *snd_pcm_oss_format_name(int format)
307{
308 switch (format) {
309 case AFMT_MU_LAW:
310 return "MU_LAW";
311 case AFMT_A_LAW:
312 return "A_LAW";
313 case AFMT_IMA_ADPCM:
314 return "IMA_ADPCM";
315 case AFMT_U8:
316 return "U8";
317 case AFMT_S16_LE:
318 return "S16_LE";
319 case AFMT_S16_BE:
320 return "S16_BE";
321 case AFMT_S8:
322 return "S8";
323 case AFMT_U16_LE:
324 return "U16_LE";
325 case AFMT_U16_BE:
326 return "U16_BE";
327 case AFMT_MPEG:
328 return "MPEG";
329 default:
330 return "unknown";
331 }
332}
333#endif
334
Takashi Iwai877211f2005-11-17 13:59:38 +0100335static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
336 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700337{
Takashi Iwai877211f2005-11-17 13:59:38 +0100338 struct snd_pcm_info *info;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 int err;
340
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200341 if (! substream)
342 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 info = kmalloc(sizeof(*info), GFP_KERNEL);
345 if (! info) {
Takashi Iwai09e56df2014-02-04 18:19:48 +0100346 pcm_dbg(substream->pcm,
347 "snd_pcm_proc_info_read: cannot malloc\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 return;
349 }
350
351 err = snd_pcm_info(substream, info);
352 if (err < 0) {
353 snd_iprintf(buffer, "error %d\n", err);
354 kfree(info);
355 return;
356 }
357 snd_iprintf(buffer, "card: %d\n", info->card);
358 snd_iprintf(buffer, "device: %d\n", info->device);
359 snd_iprintf(buffer, "subdevice: %d\n", info->subdevice);
360 snd_iprintf(buffer, "stream: %s\n", snd_pcm_stream_name(info->stream));
361 snd_iprintf(buffer, "id: %s\n", info->id);
362 snd_iprintf(buffer, "name: %s\n", info->name);
363 snd_iprintf(buffer, "subname: %s\n", info->subname);
364 snd_iprintf(buffer, "class: %d\n", info->dev_class);
365 snd_iprintf(buffer, "subclass: %d\n", info->dev_subclass);
366 snd_iprintf(buffer, "subdevices_count: %d\n", info->subdevices_count);
367 snd_iprintf(buffer, "subdevices_avail: %d\n", info->subdevices_avail);
368 kfree(info);
369}
370
Takashi Iwai877211f2005-11-17 13:59:38 +0100371static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
372 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700373{
Takashi Iwai877211f2005-11-17 13:59:38 +0100374 snd_pcm_proc_info_read(((struct snd_pcm_str *)entry->private_data)->substream,
375 buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700376}
377
Takashi Iwai877211f2005-11-17 13:59:38 +0100378static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
379 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700380{
Joe Perches9fe856e2010-09-04 18:52:54 -0700381 snd_pcm_proc_info_read(entry->private_data, buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382}
383
Takashi Iwai877211f2005-11-17 13:59:38 +0100384static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
385 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386{
Takashi Iwai877211f2005-11-17 13:59:38 +0100387 struct snd_pcm_substream *substream = entry->private_data;
Takashi Iwai901d46d2010-09-16 23:06:50 +0200388 struct snd_pcm_runtime *runtime;
389
390 mutex_lock(&substream->pcm->open_mutex);
391 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392 if (!runtime) {
393 snd_iprintf(buffer, "closed\n");
Takashi Iwai901d46d2010-09-16 23:06:50 +0200394 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
397 snd_iprintf(buffer, "no setup\n");
Takashi Iwai901d46d2010-09-16 23:06:50 +0200398 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 }
400 snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access));
401 snd_iprintf(buffer, "format: %s\n", snd_pcm_format_name(runtime->format));
402 snd_iprintf(buffer, "subformat: %s\n", snd_pcm_subformat_name(runtime->subformat));
403 snd_iprintf(buffer, "channels: %u\n", runtime->channels);
404 snd_iprintf(buffer, "rate: %u (%u/%u)\n", runtime->rate, runtime->rate_num, runtime->rate_den);
405 snd_iprintf(buffer, "period_size: %lu\n", runtime->period_size);
406 snd_iprintf(buffer, "buffer_size: %lu\n", runtime->buffer_size);
Takashi Iwai8eeaa2f2014-02-10 09:48:47 +0100407#if IS_ENABLED(CONFIG_SND_PCM_OSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 if (substream->oss.oss) {
409 snd_iprintf(buffer, "OSS format: %s\n", snd_pcm_oss_format_name(runtime->oss.format));
410 snd_iprintf(buffer, "OSS channels: %u\n", runtime->oss.channels);
411 snd_iprintf(buffer, "OSS rate: %u\n", runtime->oss.rate);
412 snd_iprintf(buffer, "OSS period bytes: %lu\n", (unsigned long)runtime->oss.period_bytes);
413 snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods);
414 snd_iprintf(buffer, "OSS period frames: %lu\n", (unsigned long)runtime->oss.period_frames);
415 }
416#endif
Takashi Iwai901d46d2010-09-16 23:06:50 +0200417 unlock:
418 mutex_unlock(&substream->pcm->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700419}
420
Takashi Iwai877211f2005-11-17 13:59:38 +0100421static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
422 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423{
Takashi Iwai877211f2005-11-17 13:59:38 +0100424 struct snd_pcm_substream *substream = entry->private_data;
Takashi Iwai901d46d2010-09-16 23:06:50 +0200425 struct snd_pcm_runtime *runtime;
426
427 mutex_lock(&substream->pcm->open_mutex);
428 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 if (!runtime) {
430 snd_iprintf(buffer, "closed\n");
Takashi Iwai901d46d2010-09-16 23:06:50 +0200431 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
434 snd_iprintf(buffer, "no setup\n");
Takashi Iwai901d46d2010-09-16 23:06:50 +0200435 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 }
437 snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
438 snd_iprintf(buffer, "period_step: %u\n", runtime->period_step);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 snd_iprintf(buffer, "avail_min: %lu\n", runtime->control->avail_min);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 snd_iprintf(buffer, "start_threshold: %lu\n", runtime->start_threshold);
441 snd_iprintf(buffer, "stop_threshold: %lu\n", runtime->stop_threshold);
442 snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold);
443 snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size);
444 snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary);
Takashi Iwai901d46d2010-09-16 23:06:50 +0200445 unlock:
446 mutex_unlock(&substream->pcm->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447}
448
Takashi Iwai877211f2005-11-17 13:59:38 +0100449static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
450 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700451{
Takashi Iwai877211f2005-11-17 13:59:38 +0100452 struct snd_pcm_substream *substream = entry->private_data;
Takashi Iwai901d46d2010-09-16 23:06:50 +0200453 struct snd_pcm_runtime *runtime;
Takashi Iwai877211f2005-11-17 13:59:38 +0100454 struct snd_pcm_status status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 int err;
Takashi Iwai901d46d2010-09-16 23:06:50 +0200456
457 mutex_lock(&substream->pcm->open_mutex);
458 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 if (!runtime) {
460 snd_iprintf(buffer, "closed\n");
Takashi Iwai901d46d2010-09-16 23:06:50 +0200461 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 }
463 memset(&status, 0, sizeof(status));
464 err = snd_pcm_status(substream, &status);
465 if (err < 0) {
466 snd_iprintf(buffer, "error %d\n", err);
Takashi Iwai901d46d2010-09-16 23:06:50 +0200467 goto unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 }
469 snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state));
Clemens Ladische7373b72009-11-10 10:13:30 +0100470 snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 snd_iprintf(buffer, "trigger_time: %ld.%09ld\n",
472 status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
473 snd_iprintf(buffer, "tstamp : %ld.%09ld\n",
474 status.tstamp.tv_sec, status.tstamp.tv_nsec);
475 snd_iprintf(buffer, "delay : %ld\n", status.delay);
476 snd_iprintf(buffer, "avail : %ld\n", status.avail);
477 snd_iprintf(buffer, "avail_max : %ld\n", status.avail_max);
478 snd_iprintf(buffer, "-----\n");
479 snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
480 snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
Takashi Iwai901d46d2010-09-16 23:06:50 +0200481 unlock:
482 mutex_unlock(&substream->pcm->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484
Jaroslav Kysela61fb63c2006-04-24 21:57:16 +0200485#ifdef CONFIG_SND_PCM_XRUN_DEBUG
Takashi Iwai2b30d412014-11-04 14:02:40 +0100486static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry,
487 struct snd_info_buffer *buffer)
488{
489 struct snd_pcm_substream *substream = entry->private_data;
490 struct snd_pcm_runtime *runtime;
491
492 snd_pcm_stream_lock_irq(substream);
493 runtime = substream->runtime;
494 if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
495 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
496 snd_pcm_stream_unlock_irq(substream);
497}
498
Takashi Iwai877211f2005-11-17 13:59:38 +0100499static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry,
500 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501{
Takashi Iwai877211f2005-11-17 13:59:38 +0100502 struct snd_pcm_str *pstr = entry->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 snd_iprintf(buffer, "%d\n", pstr->xrun_debug);
504}
505
Takashi Iwai877211f2005-11-17 13:59:38 +0100506static void snd_pcm_xrun_debug_write(struct snd_info_entry *entry,
507 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508{
Takashi Iwai877211f2005-11-17 13:59:38 +0100509 struct snd_pcm_str *pstr = entry->private_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 char line[64];
511 if (!snd_info_get_line(buffer, line, sizeof(line)))
512 pstr->xrun_debug = simple_strtoul(line, NULL, 10);
513}
514#endif
515
Takashi Iwai877211f2005-11-17 13:59:38 +0100516static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
Takashi Iwai877211f2005-11-17 13:59:38 +0100518 struct snd_pcm *pcm = pstr->pcm;
519 struct snd_info_entry *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 char name[16];
521
522 sprintf(name, "pcm%i%c", pcm->device,
523 pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
524 if ((entry = snd_info_create_card_entry(pcm->card, name, pcm->card->proc_root)) == NULL)
525 return -ENOMEM;
526 entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
527 if (snd_info_register(entry) < 0) {
528 snd_info_free_entry(entry);
529 return -ENOMEM;
530 }
531 pstr->proc_root = entry;
532
533 if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) {
Takashi Iwaibf850202006-04-28 15:13:41 +0200534 snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700535 if (snd_info_register(entry) < 0) {
536 snd_info_free_entry(entry);
537 entry = NULL;
538 }
539 }
540 pstr->proc_info_entry = entry;
541
Jaroslav Kysela61fb63c2006-04-24 21:57:16 +0200542#ifdef CONFIG_SND_PCM_XRUN_DEBUG
Takashi Iwai877211f2005-11-17 13:59:38 +0100543 if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
544 pstr->proc_root)) != NULL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 entry->c.text.read = snd_pcm_xrun_debug_read;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 entry->c.text.write = snd_pcm_xrun_debug_write;
Takashi Iwaibd7bf042005-04-12 16:27:28 +0200547 entry->mode |= S_IWUSR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 entry->private_data = pstr;
549 if (snd_info_register(entry) < 0) {
550 snd_info_free_entry(entry);
551 entry = NULL;
552 }
553 }
554 pstr->proc_xrun_debug_entry = entry;
555#endif
556 return 0;
557}
558
Takashi Iwai877211f2005-11-17 13:59:38 +0100559static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560{
Jaroslav Kysela61fb63c2006-04-24 21:57:16 +0200561#ifdef CONFIG_SND_PCM_XRUN_DEBUG
Takashi Iwai746d4a02006-06-23 14:37:59 +0200562 snd_info_free_entry(pstr->proc_xrun_debug_entry);
563 pstr->proc_xrun_debug_entry = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700564#endif
Takashi Iwai746d4a02006-06-23 14:37:59 +0200565 snd_info_free_entry(pstr->proc_info_entry);
566 pstr->proc_info_entry = NULL;
567 snd_info_free_entry(pstr->proc_root);
568 pstr->proc_root = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569 return 0;
570}
571
Takashi Iwai877211f2005-11-17 13:59:38 +0100572static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573{
Takashi Iwai877211f2005-11-17 13:59:38 +0100574 struct snd_info_entry *entry;
575 struct snd_card *card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 char name[16];
577
578 card = substream->pcm->card;
579
580 sprintf(name, "sub%i", substream->number);
581 if ((entry = snd_info_create_card_entry(card, name, substream->pstr->proc_root)) == NULL)
582 return -ENOMEM;
583 entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
584 if (snd_info_register(entry) < 0) {
585 snd_info_free_entry(entry);
586 return -ENOMEM;
587 }
588 substream->proc_root = entry;
589
590 if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) {
Takashi Iwaibf850202006-04-28 15:13:41 +0200591 snd_info_set_text_ops(entry, substream,
592 snd_pcm_substream_proc_info_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700593 if (snd_info_register(entry) < 0) {
594 snd_info_free_entry(entry);
595 entry = NULL;
596 }
597 }
598 substream->proc_info_entry = entry;
599
600 if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) {
Takashi Iwaibf850202006-04-28 15:13:41 +0200601 snd_info_set_text_ops(entry, substream,
602 snd_pcm_substream_proc_hw_params_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603 if (snd_info_register(entry) < 0) {
604 snd_info_free_entry(entry);
605 entry = NULL;
606 }
607 }
608 substream->proc_hw_params_entry = entry;
609
610 if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) {
Takashi Iwaibf850202006-04-28 15:13:41 +0200611 snd_info_set_text_ops(entry, substream,
612 snd_pcm_substream_proc_sw_params_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613 if (snd_info_register(entry) < 0) {
614 snd_info_free_entry(entry);
615 entry = NULL;
616 }
617 }
618 substream->proc_sw_params_entry = entry;
619
620 if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) {
Takashi Iwaibf850202006-04-28 15:13:41 +0200621 snd_info_set_text_ops(entry, substream,
622 snd_pcm_substream_proc_status_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if (snd_info_register(entry) < 0) {
624 snd_info_free_entry(entry);
625 entry = NULL;
626 }
627 }
628 substream->proc_status_entry = entry;
629
Takashi Iwai2b30d412014-11-04 14:02:40 +0100630#ifdef CONFIG_SND_PCM_XRUN_DEBUG
631 entry = snd_info_create_card_entry(card, "xrun_injection",
632 substream->proc_root);
633 if (entry) {
634 entry->private_data = substream;
635 entry->c.text.read = NULL;
636 entry->c.text.write = snd_pcm_xrun_injection_write;
637 entry->mode = S_IFREG | S_IWUSR;
638 if (snd_info_register(entry) < 0) {
639 snd_info_free_entry(entry);
640 entry = NULL;
641 }
642 }
643 substream->proc_xrun_injection_entry = entry;
644#endif /* CONFIG_SND_PCM_XRUN_DEBUG */
645
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 return 0;
647}
Takashi Iwai746d4a02006-06-23 14:37:59 +0200648
Takashi Iwai877211f2005-11-17 13:59:38 +0100649static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650{
Takashi Iwai746d4a02006-06-23 14:37:59 +0200651 snd_info_free_entry(substream->proc_info_entry);
652 substream->proc_info_entry = NULL;
653 snd_info_free_entry(substream->proc_hw_params_entry);
654 substream->proc_hw_params_entry = NULL;
655 snd_info_free_entry(substream->proc_sw_params_entry);
656 substream->proc_sw_params_entry = NULL;
657 snd_info_free_entry(substream->proc_status_entry);
658 substream->proc_status_entry = NULL;
Takashi Iwai2b30d412014-11-04 14:02:40 +0100659#ifdef CONFIG_SND_PCM_XRUN_DEBUG
660 snd_info_free_entry(substream->proc_xrun_injection_entry);
661 substream->proc_xrun_injection_entry = NULL;
662#endif
Takashi Iwai746d4a02006-06-23 14:37:59 +0200663 snd_info_free_entry(substream->proc_root);
664 substream->proc_root = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return 0;
666}
Takashi Iwaib7d90a32006-04-25 12:56:04 +0200667#else /* !CONFIG_SND_VERBOSE_PROCFS */
Takashi Iwaie28563c2005-12-01 10:42:42 +0100668static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; }
669static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; }
670static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; }
671static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; }
Takashi Iwaib7d90a32006-04-25 12:56:04 +0200672#endif /* CONFIG_SND_VERBOSE_PROCFS */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673
674/**
675 * snd_pcm_new_stream - create a new PCM stream
676 * @pcm: the pcm instance
677 * @stream: the stream direction, SNDRV_PCM_STREAM_XXX
678 * @substream_count: the number of substreams
679 *
680 * Creates a new stream for the pcm.
681 * The corresponding stream on the pcm must have been empty before
682 * calling this, i.e. zero must be given to the argument of
683 * snd_pcm_new().
684 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +0100685 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100687int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 int idx, err;
Takashi Iwai877211f2005-11-17 13:59:38 +0100690 struct snd_pcm_str *pstr = &pcm->streams[stream];
691 struct snd_pcm_substream *substream, *prev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Takashi Iwai8eeaa2f2014-02-10 09:48:47 +0100693#if IS_ENABLED(CONFIG_SND_PCM_OSS)
Ingo Molnar1a60d4c2006-01-16 16:29:08 +0100694 mutex_init(&pstr->oss.setup_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700695#endif
696 pstr->stream = stream;
697 pstr->pcm = pcm;
698 pstr->substream_count = substream_count;
Liam Girdwood945e5032012-02-08 20:33:31 +0000699 if (substream_count > 0 && !pcm->internal) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 err = snd_pcm_stream_proc_init(pstr);
Takashi Iwai73e77ba2005-11-17 17:44:01 +0100701 if (err < 0) {
Takashi Iwai09e56df2014-02-04 18:19:48 +0100702 pcm_err(pcm, "Error in snd_pcm_stream_proc_init\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703 return err;
Takashi Iwai73e77ba2005-11-17 17:44:01 +0100704 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 }
706 prev = NULL;
707 for (idx = 0, prev = NULL; idx < substream_count; idx++) {
Takashi Iwaica2c0962005-09-09 14:20:23 +0200708 substream = kzalloc(sizeof(*substream), GFP_KERNEL);
Takashi Iwai73e77ba2005-11-17 17:44:01 +0100709 if (substream == NULL) {
Takashi Iwai09e56df2014-02-04 18:19:48 +0100710 pcm_err(pcm, "Cannot allocate PCM substream\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 return -ENOMEM;
Takashi Iwai73e77ba2005-11-17 17:44:01 +0100712 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 substream->pcm = pcm;
714 substream->pstr = pstr;
715 substream->number = idx;
716 substream->stream = stream;
717 sprintf(substream->name, "subdevice #%i", idx);
718 substream->buffer_bytes_max = UINT_MAX;
719 if (prev == NULL)
720 pstr->substream = substream;
721 else
722 prev->next = substream;
Liam Girdwood945e5032012-02-08 20:33:31 +0000723
724 if (!pcm->internal) {
725 err = snd_pcm_substream_proc_init(substream);
726 if (err < 0) {
Takashi Iwai09e56df2014-02-04 18:19:48 +0100727 pcm_err(pcm,
728 "Error in snd_pcm_stream_proc_init\n");
Liam Girdwood945e5032012-02-08 20:33:31 +0000729 if (prev == NULL)
730 pstr->substream = NULL;
731 else
732 prev->next = NULL;
733 kfree(substream);
734 return err;
735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736 }
737 substream->group = &substream->self_group;
738 spin_lock_init(&substream->self_group.lock);
Takashi Iwai257f8cc2014-08-29 15:32:29 +0200739 mutex_init(&substream->self_group.mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 INIT_LIST_HEAD(&substream->self_group.substreams);
741 list_add_tail(&substream->link_list, &substream->self_group.substreams);
Takashi Iwai9c323fc2006-04-28 15:13:41 +0200742 atomic_set(&substream->mmap_count, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 prev = substream;
744 }
745 return 0;
746}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200747EXPORT_SYMBOL(snd_pcm_new_stream);
748
Liam Girdwood945e5032012-02-08 20:33:31 +0000749static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
750 int playback_count, int capture_count, bool internal,
751 struct snd_pcm **rpcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752{
Takashi Iwai877211f2005-11-17 13:59:38 +0100753 struct snd_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 int err;
Takashi Iwai877211f2005-11-17 13:59:38 +0100755 static struct snd_device_ops ops = {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756 .dev_free = snd_pcm_dev_free,
757 .dev_register = snd_pcm_dev_register,
758 .dev_disconnect = snd_pcm_dev_disconnect,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 };
760
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200761 if (snd_BUG_ON(!card))
762 return -ENXIO;
763 if (rpcm)
764 *rpcm = NULL;
Takashi Iwaica2c0962005-09-09 14:20:23 +0200765 pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
Takashi Iwai73e77ba2005-11-17 17:44:01 +0100766 if (pcm == NULL) {
Takashi Iwai09e56df2014-02-04 18:19:48 +0100767 dev_err(card->dev, "Cannot allocate PCM\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768 return -ENOMEM;
Takashi Iwai73e77ba2005-11-17 17:44:01 +0100769 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700770 pcm->card = card;
771 pcm->device = device;
Liam Girdwood945e5032012-02-08 20:33:31 +0000772 pcm->internal = internal;
Takashi Iwai73e77ba2005-11-17 17:44:01 +0100773 if (id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 strlcpy(pcm->id, id, sizeof(pcm->id));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775 if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
776 snd_pcm_free(pcm);
777 return err;
778 }
779 if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) {
780 snd_pcm_free(pcm);
781 return err;
782 }
Ingo Molnar1a60d4c2006-01-16 16:29:08 +0100783 mutex_init(&pcm->open_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 init_waitqueue_head(&pcm->open_wait);
785 if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
786 snd_pcm_free(pcm);
787 return err;
788 }
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200789 if (rpcm)
790 *rpcm = pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 return 0;
792}
793
Liam Girdwood945e5032012-02-08 20:33:31 +0000794/**
795 * snd_pcm_new - create a new PCM instance
796 * @card: the card instance
797 * @id: the id string
798 * @device: the device index (zero based)
799 * @playback_count: the number of substreams for playback
800 * @capture_count: the number of substreams for capture
801 * @rpcm: the pointer to store the new pcm instance
802 *
803 * Creates a new PCM instance.
804 *
805 * The pcm operators have to be set afterwards to the new instance
806 * via snd_pcm_set_ops().
807 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +0100808 * Return: Zero if successful, or a negative error code on failure.
Liam Girdwood945e5032012-02-08 20:33:31 +0000809 */
810int snd_pcm_new(struct snd_card *card, const char *id, int device,
811 int playback_count, int capture_count, struct snd_pcm **rpcm)
812{
813 return _snd_pcm_new(card, id, device, playback_count, capture_count,
814 false, rpcm);
815}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200816EXPORT_SYMBOL(snd_pcm_new);
817
Liam Girdwood945e5032012-02-08 20:33:31 +0000818/**
819 * snd_pcm_new_internal - create a new internal PCM instance
820 * @card: the card instance
821 * @id: the id string
822 * @device: the device index (zero based - shared with normal PCMs)
823 * @playback_count: the number of substreams for playback
824 * @capture_count: the number of substreams for capture
825 * @rpcm: the pointer to store the new pcm instance
826 *
827 * Creates a new internal PCM instance with no userspace device or procfs
828 * entries. This is used by ASoC Back End PCMs in order to create a PCM that
829 * will only be used internally by kernel drivers. i.e. it cannot be opened
830 * by userspace. It provides existing ASoC components drivers with a substream
831 * and access to any private data.
832 *
833 * The pcm operators have to be set afterwards to the new instance
834 * via snd_pcm_set_ops().
835 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +0100836 * Return: Zero if successful, or a negative error code on failure.
Liam Girdwood945e5032012-02-08 20:33:31 +0000837 */
838int snd_pcm_new_internal(struct snd_card *card, const char *id, int device,
839 int playback_count, int capture_count,
840 struct snd_pcm **rpcm)
841{
842 return _snd_pcm_new(card, id, device, playback_count, capture_count,
843 true, rpcm);
844}
845EXPORT_SYMBOL(snd_pcm_new_internal);
846
Takashi Iwai877211f2005-11-17 13:59:38 +0100847static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
Takashi Iwai877211f2005-11-17 13:59:38 +0100849 struct snd_pcm_substream *substream, *substream_next;
Takashi Iwai8eeaa2f2014-02-10 09:48:47 +0100850#if IS_ENABLED(CONFIG_SND_PCM_OSS)
Takashi Iwai877211f2005-11-17 13:59:38 +0100851 struct snd_pcm_oss_setup *setup, *setupn;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852#endif
853 substream = pstr->substream;
854 while (substream) {
855 substream_next = substream->next;
Takashi Iwaic4614822006-06-23 14:38:23 +0200856 snd_pcm_timer_done(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 snd_pcm_substream_proc_done(substream);
858 kfree(substream);
859 substream = substream_next;
860 }
861 snd_pcm_stream_proc_done(pstr);
Takashi Iwai8eeaa2f2014-02-10 09:48:47 +0100862#if IS_ENABLED(CONFIG_SND_PCM_OSS)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863 for (setup = pstr->oss.setup_list; setup; setup = setupn) {
864 setupn = setup->next;
865 kfree(setup->task_name);
866 kfree(setup);
867 }
868#endif
869}
870
Takashi Iwai877211f2005-11-17 13:59:38 +0100871static int snd_pcm_free(struct snd_pcm *pcm)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872{
Takashi Iwaic4614822006-06-23 14:38:23 +0200873 struct snd_pcm_notify *notify;
874
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200875 if (!pcm)
876 return 0;
Takashi Iwaic4614822006-06-23 14:38:23 +0200877 list_for_each_entry(notify, &snd_pcm_notify_list, list) {
878 notify->n_unregister(pcm);
879 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 if (pcm->private_free)
881 pcm->private_free(pcm);
882 snd_pcm_lib_preallocate_free_for_all(pcm);
883 snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]);
884 snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]);
885 kfree(pcm);
886 return 0;
887}
888
Takashi Iwai877211f2005-11-17 13:59:38 +0100889static int snd_pcm_dev_free(struct snd_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890{
Takashi Iwai877211f2005-11-17 13:59:38 +0100891 struct snd_pcm *pcm = device->device_data;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 return snd_pcm_free(pcm);
893}
894
Takashi Iwai3bf75f92006-03-27 16:40:49 +0200895int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
896 struct file *file,
897 struct snd_pcm_substream **rsubstream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700898{
Takashi Iwai877211f2005-11-17 13:59:38 +0100899 struct snd_pcm_str * pstr;
900 struct snd_pcm_substream *substream;
901 struct snd_pcm_runtime *runtime;
902 struct snd_ctl_file *kctl;
903 struct snd_card *card;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 int prefer_subdevice = -1;
905 size_t size;
906
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200907 if (snd_BUG_ON(!pcm || !rsubstream))
908 return -ENXIO;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 *rsubstream = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 pstr = &pcm->streams[stream];
Takashi Iwai3bf75f92006-03-27 16:40:49 +0200911 if (pstr->substream == NULL || pstr->substream_count == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 return -ENODEV;
913
914 card = pcm->card;
Takashi Iwai399ccdc2008-09-25 14:51:03 +0200915 read_lock(&card->ctl_files_rwlock);
Johannes Berg9244b2c2006-10-05 16:02:22 +0200916 list_for_each_entry(kctl, &card->ctl_files, list) {
Clemens Ladisch25d27ed2009-11-02 09:35:44 +0100917 if (kctl->pid == task_pid(current)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 prefer_subdevice = kctl->prefer_pcm_subdevice;
Takashi Iwai2529bba2006-08-04 12:57:19 +0200919 if (prefer_subdevice != -1)
920 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 }
922 }
Takashi Iwai399ccdc2008-09-25 14:51:03 +0200923 read_unlock(&card->ctl_files_rwlock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 switch (stream) {
926 case SNDRV_PCM_STREAM_PLAYBACK:
927 if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
928 for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {
929 if (SUBSTREAM_BUSY(substream))
930 return -EAGAIN;
931 }
932 }
933 break;
934 case SNDRV_PCM_STREAM_CAPTURE:
935 if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
936 for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {
937 if (SUBSTREAM_BUSY(substream))
938 return -EAGAIN;
939 }
940 }
941 break;
942 default:
943 return -EINVAL;
944 }
945
Takashi Iwai0df63e42006-04-28 15:13:41 +0200946 if (file->f_flags & O_APPEND) {
947 if (prefer_subdevice < 0) {
948 if (pstr->substream_count > 1)
949 return -EINVAL; /* must be unique */
950 substream = pstr->substream;
951 } else {
952 for (substream = pstr->substream; substream;
953 substream = substream->next)
954 if (substream->number == prefer_subdevice)
955 break;
956 }
957 if (! substream)
958 return -ENODEV;
959 if (! SUBSTREAM_BUSY(substream))
960 return -EBADFD;
961 substream->ref_count++;
962 *rsubstream = substream;
963 return 0;
964 }
965
Linus Torvalds1da177e2005-04-16 15:20:36 -0700966 if (prefer_subdevice >= 0) {
967 for (substream = pstr->substream; substream; substream = substream->next)
968 if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
969 goto __ok;
970 }
971 for (substream = pstr->substream; substream; substream = substream->next)
972 if (!SUBSTREAM_BUSY(substream))
973 break;
974 __ok:
975 if (substream == NULL)
976 return -EAGAIN;
977
Takashi Iwaica2c0962005-09-09 14:20:23 +0200978 runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979 if (runtime == NULL)
980 return -ENOMEM;
981
Takashi Iwai877211f2005-11-17 13:59:38 +0100982 size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983 runtime->status = snd_malloc_pages(size, GFP_KERNEL);
984 if (runtime->status == NULL) {
985 kfree(runtime);
986 return -ENOMEM;
987 }
988 memset((void*)runtime->status, 0, size);
989
Takashi Iwai877211f2005-11-17 13:59:38 +0100990 size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 runtime->control = snd_malloc_pages(size, GFP_KERNEL);
992 if (runtime->control == NULL) {
Takashi Iwai877211f2005-11-17 13:59:38 +0100993 snd_free_pages((void*)runtime->status,
994 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 kfree(runtime);
996 return -ENOMEM;
997 }
998 memset((void*)runtime->control, 0, size);
999
1000 init_waitqueue_head(&runtime->sleep);
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01001001 init_waitqueue_head(&runtime->tsleep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001002
1003 runtime->status->state = SNDRV_PCM_STATE_OPEN;
1004
1005 substream->runtime = runtime;
1006 substream->private_data = pcm->private_data;
Takashi Iwai0df63e42006-04-28 15:13:41 +02001007 substream->ref_count = 1;
1008 substream->f_flags = file->f_flags;
Clemens Ladische7373b72009-11-10 10:13:30 +01001009 substream->pid = get_pid(task_pid(current));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010 pstr->substream_opened++;
1011 *rsubstream = substream;
1012 return 0;
1013}
1014
Takashi Iwai3bf75f92006-03-27 16:40:49 +02001015void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001016{
Takashi Iwai877211f2005-11-17 13:59:38 +01001017 struct snd_pcm_runtime *runtime;
Takashi Iwai0df63e42006-04-28 15:13:41 +02001018
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001019 if (PCM_RUNTIME_CHECK(substream))
1020 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001021 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 if (runtime->private_free != NULL)
1023 runtime->private_free(runtime);
Takashi Iwai877211f2005-11-17 13:59:38 +01001024 snd_free_pages((void*)runtime->status,
1025 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
1026 snd_free_pages((void*)runtime->control,
1027 PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001028 kfree(runtime->hw_constraints.rules);
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +01001029#ifdef CONFIG_SND_PCM_XRUN_DEBUG
Sachin Kamat51d503d2012-11-21 14:36:54 +05301030 kfree(runtime->hwptr_log);
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +01001031#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 kfree(runtime);
1033 substream->runtime = NULL;
Clemens Ladische7373b72009-11-10 10:13:30 +01001034 put_pid(substream->pid);
1035 substream->pid = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 substream->pstr->substream_opened--;
1037}
1038
Greg Kroah-Hartmand80f19f2006-08-07 22:19:37 -07001039static ssize_t show_pcm_class(struct device *dev,
1040 struct device_attribute *attr, char *buf)
Takashi Iwai9d19f482006-09-06 14:27:46 +02001041{
1042 struct snd_pcm *pcm;
1043 const char *str;
1044 static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
1045 [SNDRV_PCM_CLASS_GENERIC] = "generic",
1046 [SNDRV_PCM_CLASS_MULTI] = "multi",
1047 [SNDRV_PCM_CLASS_MODEM] = "modem",
1048 [SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
1049 };
1050
Greg Kroah-Hartmand80f19f2006-08-07 22:19:37 -07001051 if (! (pcm = dev_get_drvdata(dev)) ||
Takashi Iwai9d19f482006-09-06 14:27:46 +02001052 pcm->dev_class > SNDRV_PCM_CLASS_LAST)
1053 str = "none";
1054 else
1055 str = strs[pcm->dev_class];
1056 return snprintf(buf, PAGE_SIZE, "%s\n", str);
1057}
1058
Takashi Iwaicaa751b2014-02-25 08:30:50 +01001059static DEVICE_ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
1060static struct attribute *pcm_dev_attrs[] = {
1061 &dev_attr_pcm_class.attr,
1062 NULL
1063};
1064
1065static struct attribute_group pcm_dev_attr_group = {
1066 .attrs = pcm_dev_attrs,
1067};
1068
1069static const struct attribute_group *pcm_dev_attr_groups[] = {
1070 &pcm_dev_attr_group,
1071 NULL
1072};
Takashi Iwai9d19f482006-09-06 14:27:46 +02001073
Takashi Iwai877211f2005-11-17 13:59:38 +01001074static int snd_pcm_dev_register(struct snd_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
Clemens Ladischf87135f2005-11-20 14:06:59 +01001076 int cidx, err;
Takashi Iwai877211f2005-11-17 13:59:38 +01001077 struct snd_pcm_substream *substream;
Johannes Berg9244b2c2006-10-05 16:02:22 +02001078 struct snd_pcm_notify *notify;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079 char str[16];
Julia Lawall4b3be6a2009-10-17 08:33:22 +02001080 struct snd_pcm *pcm;
Johannes Bergc78085f2006-10-05 15:06:34 +02001081 struct device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082
Julia Lawall4b3be6a2009-10-17 08:33:22 +02001083 if (snd_BUG_ON(!device || !device->device_data))
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001084 return -ENXIO;
Julia Lawall4b3be6a2009-10-17 08:33:22 +02001085 pcm = device->device_data;
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001086 mutex_lock(&register_mutex);
Pawel MOLLf90c06a2008-07-30 12:46:40 +01001087 err = snd_pcm_add(pcm);
1088 if (err) {
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001089 mutex_unlock(&register_mutex);
Pawel MOLLf90c06a2008-07-30 12:46:40 +01001090 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 for (cidx = 0; cidx < 2; cidx++) {
1093 int devtype = -1;
Liam Girdwood945e5032012-02-08 20:33:31 +00001094 if (pcm->streams[cidx].substream == NULL || pcm->internal)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 continue;
1096 switch (cidx) {
1097 case SNDRV_PCM_STREAM_PLAYBACK:
1098 sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001099 devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
1100 break;
1101 case SNDRV_PCM_STREAM_CAPTURE:
1102 sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001103 devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
1104 break;
1105 }
Johannes Bergc78085f2006-10-05 15:06:34 +02001106 /* device pointer to use, pcm->dev takes precedence if
1107 * it is assigned, otherwise fall back to card's device
1108 * if possible */
1109 dev = pcm->dev;
1110 if (!dev)
Takashi Iwaic2902c82007-02-09 16:25:48 +01001111 dev = snd_card_get_device_link(pcm->card);
Johannes Bergc78085f2006-10-05 15:06:34 +02001112 /* register pcm */
1113 err = snd_register_device_for_dev(devtype, pcm->card,
1114 pcm->device,
1115 &snd_pcm_f_ops[cidx],
1116 pcm, str, dev);
1117 if (err < 0) {
Clemens Ladischf87135f2005-11-20 14:06:59 +01001118 list_del(&pcm->list);
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001119 mutex_unlock(&register_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001120 return err;
1121 }
Takashi Iwaicaa751b2014-02-25 08:30:50 +01001122
1123 dev = snd_get_device(devtype, pcm->card, pcm->device);
1124 if (dev) {
1125 err = sysfs_create_groups(&dev->kobj,
1126 pcm_dev_attr_groups);
1127 if (err < 0)
1128 dev_warn(dev,
1129 "pcm %d:%d: cannot create sysfs groups\n",
1130 pcm->card->number, pcm->device);
1131 put_device(dev);
1132 }
1133
Linus Torvalds1da177e2005-04-16 15:20:36 -07001134 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
1135 snd_pcm_timer_init(substream);
1136 }
Johannes Berg9244b2c2006-10-05 16:02:22 +02001137
1138 list_for_each_entry(notify, &snd_pcm_notify_list, list)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001139 notify->n_register(pcm);
Johannes Berg9244b2c2006-10-05 16:02:22 +02001140
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001141 mutex_unlock(&register_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 return 0;
1143}
1144
Takashi Iwai877211f2005-11-17 13:59:38 +01001145static int snd_pcm_dev_disconnect(struct snd_device *device)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001146{
Takashi Iwai877211f2005-11-17 13:59:38 +01001147 struct snd_pcm *pcm = device->device_data;
Takashi Iwaic4614822006-06-23 14:38:23 +02001148 struct snd_pcm_notify *notify;
Takashi Iwai877211f2005-11-17 13:59:38 +01001149 struct snd_pcm_substream *substream;
Takashi Iwaic4614822006-06-23 14:38:23 +02001150 int cidx, devtype;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001151
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001152 mutex_lock(&register_mutex);
Takashi Iwaic4614822006-06-23 14:38:23 +02001153 if (list_empty(&pcm->list))
1154 goto unlock;
1155
Takashi Iwai9b0573c2012-10-12 15:07:34 +02001156 mutex_lock(&pcm->open_mutex);
Takashi Iwai0914f792012-10-16 16:43:39 +02001157 wake_up(&pcm->open_wait);
Clemens Ladischf87135f2005-11-20 14:06:59 +01001158 list_del_init(&pcm->list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159 for (cidx = 0; cidx < 2; cidx++)
Takashi Iwai9b0573c2012-10-12 15:07:34 +02001160 for (substream = pcm->streams[cidx].substream; substream; substream = substream->next) {
1161 snd_pcm_stream_lock_irq(substream);
Takashi Iwai0914f792012-10-16 16:43:39 +02001162 if (substream->runtime) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
Takashi Iwai0914f792012-10-16 16:43:39 +02001164 wake_up(&substream->runtime->sleep);
1165 wake_up(&substream->runtime->tsleep);
1166 }
Takashi Iwai9b0573c2012-10-12 15:07:34 +02001167 snd_pcm_stream_unlock_irq(substream);
1168 }
Takashi Iwaic4614822006-06-23 14:38:23 +02001169 list_for_each_entry(notify, &snd_pcm_notify_list, list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 notify->n_disconnect(pcm);
1171 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 for (cidx = 0; cidx < 2; cidx++) {
1173 devtype = -1;
1174 switch (cidx) {
1175 case SNDRV_PCM_STREAM_PLAYBACK:
1176 devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
1177 break;
1178 case SNDRV_PCM_STREAM_CAPTURE:
1179 devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
1180 break;
1181 }
1182 snd_unregister_device(devtype, pcm->card, pcm->device);
Takashi Iwai2d3391e2012-07-27 18:27:00 +02001183 if (pcm->streams[cidx].chmap_kctl) {
1184 snd_ctl_remove(pcm->card, pcm->streams[cidx].chmap_kctl);
1185 pcm->streams[cidx].chmap_kctl = NULL;
1186 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001187 }
Takashi Iwai9b0573c2012-10-12 15:07:34 +02001188 mutex_unlock(&pcm->open_mutex);
Takashi Iwaic4614822006-06-23 14:38:23 +02001189 unlock:
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001190 mutex_unlock(&register_mutex);
Takashi Iwaic4614822006-06-23 14:38:23 +02001191 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192}
1193
Takashi Iwai30b771c2014-10-30 15:02:50 +01001194/**
1195 * snd_pcm_notify - Add/remove the notify list
1196 * @notify: PCM notify list
1197 * @nfree: 0 = register, 1 = unregister
1198 *
1199 * This adds the given notifier to the global list so that the callback is
1200 * called for each registered PCM devices. This exists only for PCM OSS
1201 * emulation, so far.
1202 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001203int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001204{
Johannes Berg9244b2c2006-10-05 16:02:22 +02001205 struct snd_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001206
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001207 if (snd_BUG_ON(!notify ||
1208 !notify->n_register ||
1209 !notify->n_unregister ||
1210 !notify->n_disconnect))
1211 return -EINVAL;
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001212 mutex_lock(&register_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 if (nfree) {
1214 list_del(&notify->list);
Johannes Berg9244b2c2006-10-05 16:02:22 +02001215 list_for_each_entry(pcm, &snd_pcm_devices, list)
1216 notify->n_unregister(pcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001217 } else {
1218 list_add_tail(&notify->list, &snd_pcm_notify_list);
Johannes Berg9244b2c2006-10-05 16:02:22 +02001219 list_for_each_entry(pcm, &snd_pcm_devices, list)
1220 notify->n_register(pcm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001221 }
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001222 mutex_unlock(&register_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 return 0;
1224}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001225EXPORT_SYMBOL(snd_pcm_notify);
1226
Takashi Iwaie28563c2005-12-01 10:42:42 +01001227#ifdef CONFIG_PROC_FS
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228/*
1229 * Info interface
1230 */
1231
Takashi Iwai877211f2005-11-17 13:59:38 +01001232static void snd_pcm_proc_read(struct snd_info_entry *entry,
1233 struct snd_info_buffer *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001234{
Takashi Iwai877211f2005-11-17 13:59:38 +01001235 struct snd_pcm *pcm;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001236
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001237 mutex_lock(&register_mutex);
Johannes Berg9244b2c2006-10-05 16:02:22 +02001238 list_for_each_entry(pcm, &snd_pcm_devices, list) {
Clemens Ladischf87135f2005-11-20 14:06:59 +01001239 snd_iprintf(buffer, "%02i-%02i: %s : %s",
1240 pcm->card->number, pcm->device, pcm->id, pcm->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
Takashi Iwai877211f2005-11-17 13:59:38 +01001242 snd_iprintf(buffer, " : playback %i",
1243 pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001244 if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
Takashi Iwai877211f2005-11-17 13:59:38 +01001245 snd_iprintf(buffer, " : capture %i",
1246 pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001247 snd_iprintf(buffer, "\n");
1248 }
Ingo Molnar1a60d4c2006-01-16 16:29:08 +01001249 mutex_unlock(&register_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001250}
1251
Takashi Iwai6581f4e2006-05-17 17:14:51 +02001252static struct snd_info_entry *snd_pcm_proc_entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253
Takashi Iwaie28563c2005-12-01 10:42:42 +01001254static void snd_pcm_proc_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
Takashi Iwai877211f2005-11-17 13:59:38 +01001256 struct snd_info_entry *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257
Linus Torvalds1da177e2005-04-16 15:20:36 -07001258 if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
Takashi Iwaibf850202006-04-28 15:13:41 +02001259 snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001260 if (snd_info_register(entry) < 0) {
1261 snd_info_free_entry(entry);
1262 entry = NULL;
1263 }
1264 }
1265 snd_pcm_proc_entry = entry;
Takashi Iwaie28563c2005-12-01 10:42:42 +01001266}
1267
1268static void snd_pcm_proc_done(void)
1269{
Takashi Iwai746d4a02006-06-23 14:37:59 +02001270 snd_info_free_entry(snd_pcm_proc_entry);
Takashi Iwaie28563c2005-12-01 10:42:42 +01001271}
1272
1273#else /* !CONFIG_PROC_FS */
1274#define snd_pcm_proc_init()
1275#define snd_pcm_proc_done()
1276#endif /* CONFIG_PROC_FS */
1277
1278
1279/*
1280 * ENTRY functions
1281 */
1282
1283static int __init alsa_pcm_init(void)
1284{
1285 snd_ctl_register_ioctl(snd_pcm_control_ioctl);
1286 snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
1287 snd_pcm_proc_init();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288 return 0;
1289}
1290
1291static void __exit alsa_pcm_exit(void)
1292{
1293 snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
1294 snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
Takashi Iwaie28563c2005-12-01 10:42:42 +01001295 snd_pcm_proc_done();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296}
1297
1298module_init(alsa_pcm_init)
1299module_exit(alsa_pcm_exit)