Blame view

sound/core/pcm.c 32 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *  Digital Audio (PCM) abstract layer
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
3
   *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
   *
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  #include <linux/init.h>
  #include <linux/slab.h>
da155d5b4   Paul Gortmaker   sound: Add module...
23
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
  #include <linux/time.h>
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
25
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
27
28
29
30
  #include <sound/core.h>
  #include <sound/minors.h>
  #include <sound/pcm.h>
  #include <sound/control.h>
  #include <sound/info.h>
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
31
  MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Abramo Bagnara <abramo@alsa-project.org>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
  MODULE_DESCRIPTION("Midlevel PCM code for ALSA.");
  MODULE_LICENSE("GPL");
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
34
  static LIST_HEAD(snd_pcm_devices);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  static LIST_HEAD(snd_pcm_notify_list);
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
36
  static DEFINE_MUTEX(register_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37

877211f5e   Takashi Iwai   [ALSA] Remove xxx...
38
39
40
41
  static int snd_pcm_free(struct snd_pcm *pcm);
  static int snd_pcm_dev_free(struct snd_device *device);
  static int snd_pcm_dev_register(struct snd_device *device);
  static int snd_pcm_dev_disconnect(struct snd_device *device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42

f90c06a2b   Pawel MOLL   ALSA: Fix limit o...
43
  static struct snd_pcm *snd_pcm_get(struct snd_card *card, int device)
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
44
  {
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
45
  	struct snd_pcm *pcm;
9244b2c30   Johannes Berg   [ALSA] alsa core:...
46
  	list_for_each_entry(pcm, &snd_pcm_devices, list) {
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
47
48
49
50
51
  		if (pcm->card == card && pcm->device == device)
  			return pcm;
  	}
  	return NULL;
  }
f90c06a2b   Pawel MOLL   ALSA: Fix limit o...
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  static int snd_pcm_next(struct snd_card *card, int device)
  {
  	struct snd_pcm *pcm;
  
  	list_for_each_entry(pcm, &snd_pcm_devices, list) {
  		if (pcm->card == card && pcm->device > device)
  			return pcm->device;
  		else if (pcm->card->number > card->number)
  			return -1;
  	}
  	return -1;
  }
  
  static int snd_pcm_add(struct snd_pcm *newpcm)
  {
  	struct snd_pcm *pcm;
  
  	list_for_each_entry(pcm, &snd_pcm_devices, list) {
  		if (pcm->card == newpcm->card && pcm->device == newpcm->device)
  			return -EBUSY;
  		if (pcm->card->number > newpcm->card->number ||
  				(pcm->card == newpcm->card &&
  				pcm->device > newpcm->device)) {
  			list_add(&newpcm->list, pcm->list.prev);
  			return 0;
  		}
  	}
  	list_add_tail(&newpcm->list, &snd_pcm_devices);
  	return 0;
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
82
83
  static int snd_pcm_control_ioctl(struct snd_card *card,
  				 struct snd_ctl_file *control,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
  				 unsigned int cmd, unsigned long arg)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
87
88
89
90
91
92
  	switch (cmd) {
  	case SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE:
  		{
  			int device;
  
  			if (get_user(device, (int __user *)arg))
  				return -EFAULT;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
93
  			mutex_lock(&register_mutex);
f90c06a2b   Pawel MOLL   ALSA: Fix limit o...
94
  			device = snd_pcm_next(card, device);
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
95
  			mutex_unlock(&register_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
  			if (put_user(device, (int __user *)arg))
  				return -EFAULT;
  			return 0;
  		}
  	case SNDRV_CTL_IOCTL_PCM_INFO:
  		{
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
102
  			struct snd_pcm_info __user *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  			unsigned int device, subdevice;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
104
105
106
107
  			int stream;
  			struct snd_pcm *pcm;
  			struct snd_pcm_str *pstr;
  			struct snd_pcm_substream *substream;
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
108
  			int err;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
109
  			info = (struct snd_pcm_info __user *)arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
  			if (get_user(device, &info->device))
  				return -EFAULT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
  			if (get_user(stream, &info->stream))
  				return -EFAULT;
  			if (stream < 0 || stream > 1)
  				return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
  			if (get_user(subdevice, &info->subdevice))
  				return -EFAULT;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
118
  			mutex_lock(&register_mutex);
f90c06a2b   Pawel MOLL   ALSA: Fix limit o...
119
  			pcm = snd_pcm_get(card, device);
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
  			if (pcm == NULL) {
  				err = -ENXIO;
  				goto _error;
  			}
  			pstr = &pcm->streams[stream];
  			if (pstr->substream_count == 0) {
  				err = -ENOENT;
  				goto _error;
  			}
  			if (subdevice >= pstr->substream_count) {
  				err = -ENXIO;
  				goto _error;
  			}
  			for (substream = pstr->substream; substream;
  			     substream = substream->next)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
  				if (substream->number == (int)subdevice)
  					break;
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
137
138
139
140
141
142
  			if (substream == NULL) {
  				err = -ENXIO;
  				goto _error;
  			}
  			err = snd_pcm_info_user(substream, info);
  		_error:
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
143
  			mutex_unlock(&register_mutex);
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
144
  			return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
150
151
152
153
154
155
156
157
  		}
  	case SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE:
  		{
  			int val;
  			
  			if (get_user(val, (int __user *)arg))
  				return -EFAULT;
  			control->prefer_pcm_subdevice = val;
  			return 0;
  		}
  	}
  	return -ENOIOCTLCMD;
  }
21a3479a0   Jaroslav Kysela   [ALSA] PCM midlev...
158

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  #define FORMAT(v) [SNDRV_PCM_FORMAT_##v] = #v
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
  static char *snd_pcm_format_names[] = {
  	FORMAT(S8),
  	FORMAT(U8),
  	FORMAT(S16_LE),
  	FORMAT(S16_BE),
  	FORMAT(U16_LE),
  	FORMAT(U16_BE),
  	FORMAT(S24_LE),
  	FORMAT(S24_BE),
  	FORMAT(U24_LE),
  	FORMAT(U24_BE),
  	FORMAT(S32_LE),
  	FORMAT(S32_BE),
  	FORMAT(U32_LE),
  	FORMAT(U32_BE),
  	FORMAT(FLOAT_LE),
  	FORMAT(FLOAT_BE),
  	FORMAT(FLOAT64_LE),
  	FORMAT(FLOAT64_BE),
  	FORMAT(IEC958_SUBFRAME_LE),
  	FORMAT(IEC958_SUBFRAME_BE),
  	FORMAT(MU_LAW),
  	FORMAT(A_LAW),
  	FORMAT(IMA_ADPCM),
  	FORMAT(MPEG),
  	FORMAT(GSM),
  	FORMAT(SPECIAL),
  	FORMAT(S24_3LE),
  	FORMAT(S24_3BE),
  	FORMAT(U24_3LE),
  	FORMAT(U24_3BE),
  	FORMAT(S20_3LE),
  	FORMAT(S20_3BE),
  	FORMAT(U20_3LE),
  	FORMAT(U20_3BE),
  	FORMAT(S18_3LE),
  	FORMAT(S18_3BE),
  	FORMAT(U18_3LE),
  	FORMAT(U18_3BE),
7a28826ac   Dan Carpenter   ALSA: pcm: add mo...
200
201
202
203
  	FORMAT(G723_24),
  	FORMAT(G723_24_1B),
  	FORMAT(G723_40),
  	FORMAT(G723_40_1B),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
  };
6e5265ec3   Takashi Iwai   ALSA: Re-export s...
205
  const char *snd_pcm_format_name(snd_pcm_format_t format)
e28563cce   Takashi Iwai   [ALSA] Optimize f...
206
  {
fea952e5c   Clemens Ladisch   ALSA: core: spars...
207
  	if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
7a28826ac   Dan Carpenter   ALSA: pcm: add mo...
208
  		return "Unknown";
fea952e5c   Clemens Ladisch   ALSA: core: spars...
209
  	return snd_pcm_format_names[(__force unsigned int)format];
e28563cce   Takashi Iwai   [ALSA] Optimize f...
210
  }
6e5265ec3   Takashi Iwai   ALSA: Re-export s...
211
212
213
214
215
216
217
218
219
220
221
222
223
  EXPORT_SYMBOL_GPL(snd_pcm_format_name);
  
  #ifdef CONFIG_SND_VERBOSE_PROCFS
  
  #define STATE(v) [SNDRV_PCM_STATE_##v] = #v
  #define STREAM(v) [SNDRV_PCM_STREAM_##v] = #v
  #define READY(v) [SNDRV_PCM_READY_##v] = #v
  #define XRUN(v) [SNDRV_PCM_XRUN_##v] = #v
  #define SILENCE(v) [SNDRV_PCM_SILENCE_##v] = #v
  #define TSTAMP(v) [SNDRV_PCM_TSTAMP_##v] = #v
  #define ACCESS(v) [SNDRV_PCM_ACCESS_##v] = #v
  #define START(v) [SNDRV_PCM_START_##v] = #v
  #define SUBFORMAT(v) [SNDRV_PCM_SUBFORMAT_##v] = #v 
e28563cce   Takashi Iwai   [ALSA] Optimize f...
224

e28563cce   Takashi Iwai   [ALSA] Optimize f...
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
  static char *snd_pcm_stream_names[] = {
  	STREAM(PLAYBACK),
  	STREAM(CAPTURE),
  };
  
  static char *snd_pcm_state_names[] = {
  	STATE(OPEN),
  	STATE(SETUP),
  	STATE(PREPARED),
  	STATE(RUNNING),
  	STATE(XRUN),
  	STATE(DRAINING),
  	STATE(PAUSED),
  	STATE(SUSPENDED),
  };
  
  static char *snd_pcm_access_names[] = {
  	ACCESS(MMAP_INTERLEAVED), 
  	ACCESS(MMAP_NONINTERLEAVED),
  	ACCESS(MMAP_COMPLEX),
  	ACCESS(RW_INTERLEAVED),
  	ACCESS(RW_NONINTERLEAVED),
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
251
252
253
  static char *snd_pcm_subformat_names[] = {
  	SUBFORMAT(STD), 
  };
  
  static char *snd_pcm_tstamp_mode_names[] = {
  	TSTAMP(NONE),
8c1215868   Jaroslav Kysela   [ALSA] PCM interf...
254
  	TSTAMP(ENABLE),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  };
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
256
  static const char *snd_pcm_stream_name(int stream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
257
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
258
259
260
261
262
  	return snd_pcm_stream_names[stream];
  }
  
  static const char *snd_pcm_access_name(snd_pcm_access_t access)
  {
fea952e5c   Clemens Ladisch   ALSA: core: spars...
263
  	return snd_pcm_access_names[(__force int)access];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
266
  static const char *snd_pcm_subformat_name(snd_pcm_subformat_t subformat)
  {
fea952e5c   Clemens Ladisch   ALSA: core: spars...
267
  	return snd_pcm_subformat_names[(__force int)subformat];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
269
  static const char *snd_pcm_tstamp_mode_name(int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
272
273
274
275
  	return snd_pcm_tstamp_mode_names[mode];
  }
  
  static const char *snd_pcm_state_name(snd_pcm_state_t state)
  {
fea952e5c   Clemens Ladisch   ALSA: core: spars...
276
  	return snd_pcm_state_names[(__force int)state];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
278
279
280
  }
  
  #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
  #include <linux/soundcard.h>
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
281

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
  static const char *snd_pcm_oss_format_name(int format)
  {
  	switch (format) {
  	case AFMT_MU_LAW:
  		return "MU_LAW";
  	case AFMT_A_LAW:
  		return "A_LAW";
  	case AFMT_IMA_ADPCM:
  		return "IMA_ADPCM";
  	case AFMT_U8:
  		return "U8";
  	case AFMT_S16_LE:
  		return "S16_LE";
  	case AFMT_S16_BE:
  		return "S16_BE";
  	case AFMT_S8:
  		return "S8";
  	case AFMT_U16_LE:
  		return "U16_LE";
  	case AFMT_U16_BE:
  		return "U16_BE";
  	case AFMT_MPEG:
  		return "MPEG";
  	default:
  		return "unknown";
  	}
  }
  #endif
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
310
311
  static void snd_pcm_proc_info_read(struct snd_pcm_substream *substream,
  				   struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
313
  	struct snd_pcm_info *info;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
  	int err;
7c22f1aaa   Takashi Iwai   [ALSA] Remove snd...
315
316
  	if (! substream)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
  
  	info = kmalloc(sizeof(*info), GFP_KERNEL);
  	if (! info) {
  		printk(KERN_DEBUG "snd_pcm_proc_info_read: cannot malloc
  ");
  		return;
  	}
  
  	err = snd_pcm_info(substream, info);
  	if (err < 0) {
  		snd_iprintf(buffer, "error %d
  ", err);
  		kfree(info);
  		return;
  	}
  	snd_iprintf(buffer, "card: %d
  ", info->card);
  	snd_iprintf(buffer, "device: %d
  ", info->device);
  	snd_iprintf(buffer, "subdevice: %d
  ", info->subdevice);
  	snd_iprintf(buffer, "stream: %s
  ", snd_pcm_stream_name(info->stream));
  	snd_iprintf(buffer, "id: %s
  ", info->id);
  	snd_iprintf(buffer, "name: %s
  ", info->name);
  	snd_iprintf(buffer, "subname: %s
  ", info->subname);
  	snd_iprintf(buffer, "class: %d
  ", info->dev_class);
  	snd_iprintf(buffer, "subclass: %d
  ", info->dev_subclass);
  	snd_iprintf(buffer, "subdevices_count: %d
  ", info->subdevices_count);
  	snd_iprintf(buffer, "subdevices_avail: %d
  ", info->subdevices_avail);
  	kfree(info);
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
356
357
  static void snd_pcm_stream_proc_info_read(struct snd_info_entry *entry,
  					  struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
359
360
  	snd_pcm_proc_info_read(((struct snd_pcm_str *)entry->private_data)->substream,
  			       buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
362
363
  static void snd_pcm_substream_proc_info_read(struct snd_info_entry *entry,
  					     struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
  {
9fe856e47   Joe Perches   sound: Remove unn...
365
  	snd_pcm_proc_info_read(entry->private_data, buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
367
368
  static void snd_pcm_substream_proc_hw_params_read(struct snd_info_entry *entry,
  						  struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
370
  	struct snd_pcm_substream *substream = entry->private_data;
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
371
372
373
374
  	struct snd_pcm_runtime *runtime;
  
  	mutex_lock(&substream->pcm->open_mutex);
  	runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
  	if (!runtime) {
  		snd_iprintf(buffer, "closed
  ");
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
378
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
379
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
  		snd_iprintf(buffer, "no setup
  ");
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
383
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
  	}
  	snd_iprintf(buffer, "access: %s
  ", snd_pcm_access_name(runtime->access));
  	snd_iprintf(buffer, "format: %s
  ", snd_pcm_format_name(runtime->format));
  	snd_iprintf(buffer, "subformat: %s
  ", snd_pcm_subformat_name(runtime->subformat));
  	snd_iprintf(buffer, "channels: %u
  ", runtime->channels);	
  	snd_iprintf(buffer, "rate: %u (%u/%u)
  ", runtime->rate, runtime->rate_num, runtime->rate_den);	
  	snd_iprintf(buffer, "period_size: %lu
  ", runtime->period_size);	
  	snd_iprintf(buffer, "buffer_size: %lu
  ", runtime->buffer_size);	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
  #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
  	if (substream->oss.oss) {
  		snd_iprintf(buffer, "OSS format: %s
  ", snd_pcm_oss_format_name(runtime->oss.format));
  		snd_iprintf(buffer, "OSS channels: %u
  ", runtime->oss.channels);	
  		snd_iprintf(buffer, "OSS rate: %u
  ", runtime->oss.rate);
  		snd_iprintf(buffer, "OSS period bytes: %lu
  ", (unsigned long)runtime->oss.period_bytes);
  		snd_iprintf(buffer, "OSS periods: %u
  ", runtime->oss.periods);
  		snd_iprintf(buffer, "OSS period frames: %lu
  ", (unsigned long)runtime->oss.period_frames);
  	}
  #endif
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
415
416
   unlock:
  	mutex_unlock(&substream->pcm->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
418
419
  static void snd_pcm_substream_proc_sw_params_read(struct snd_info_entry *entry,
  						  struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
421
  	struct snd_pcm_substream *substream = entry->private_data;
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
422
423
424
425
  	struct snd_pcm_runtime *runtime;
  
  	mutex_lock(&substream->pcm->open_mutex);
  	runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
427
428
  	if (!runtime) {
  		snd_iprintf(buffer, "closed
  ");
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
429
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
430
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
433
  	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
  		snd_iprintf(buffer, "no setup
  ");
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
434
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
435
436
437
438
439
  	}
  	snd_iprintf(buffer, "tstamp_mode: %s
  ", snd_pcm_tstamp_mode_name(runtime->tstamp_mode));
  	snd_iprintf(buffer, "period_step: %u
  ", runtime->period_step);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
441
  	snd_iprintf(buffer, "avail_min: %lu
  ", runtime->control->avail_min);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
442
443
444
445
446
447
448
449
450
451
  	snd_iprintf(buffer, "start_threshold: %lu
  ", runtime->start_threshold);
  	snd_iprintf(buffer, "stop_threshold: %lu
  ", runtime->stop_threshold);
  	snd_iprintf(buffer, "silence_threshold: %lu
  ", runtime->silence_threshold);
  	snd_iprintf(buffer, "silence_size: %lu
  ", runtime->silence_size);
  	snd_iprintf(buffer, "boundary: %lu
  ", runtime->boundary);
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
452
453
   unlock:
  	mutex_unlock(&substream->pcm->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
454
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
455
456
  static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
  					       struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
458
  	struct snd_pcm_substream *substream = entry->private_data;
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
459
  	struct snd_pcm_runtime *runtime;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
460
  	struct snd_pcm_status status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  	int err;
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
462
463
464
  
  	mutex_lock(&substream->pcm->open_mutex);
  	runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
  	if (!runtime) {
  		snd_iprintf(buffer, "closed
  ");
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
468
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
471
472
473
474
  	}
  	memset(&status, 0, sizeof(status));
  	err = snd_pcm_status(substream, &status);
  	if (err < 0) {
  		snd_iprintf(buffer, "error %d
  ", err);
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
475
  		goto unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
477
478
  	}
  	snd_iprintf(buffer, "state: %s
  ", snd_pcm_state_name(status.state));
e7373b702   Clemens Ladisch   sound: pcm: recor...
479
480
  	snd_iprintf(buffer, "owner_pid   : %d
  ", pid_vnr(substream->pid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  	snd_iprintf(buffer, "trigger_time: %ld.%09ld
  ",
  		status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec);
  	snd_iprintf(buffer, "tstamp      : %ld.%09ld
  ",
  		status.tstamp.tv_sec, status.tstamp.tv_nsec);
  	snd_iprintf(buffer, "delay       : %ld
  ", status.delay);
  	snd_iprintf(buffer, "avail       : %ld
  ", status.avail);
  	snd_iprintf(buffer, "avail_max   : %ld
  ", status.avail_max);
  	snd_iprintf(buffer, "-----
  ");
  	snd_iprintf(buffer, "hw_ptr      : %ld
  ", runtime->status->hw_ptr);
  	snd_iprintf(buffer, "appl_ptr    : %ld
  ", runtime->control->appl_ptr);
901d46d5a   Takashi Iwai   ALSA: pcm - Fix r...
499
500
   unlock:
  	mutex_unlock(&substream->pcm->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502

61fb63c09   Jaroslav Kysela   [ALSA] PCM core -...
503
  #ifdef CONFIG_SND_PCM_XRUN_DEBUG
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
504
505
  static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry,
  				    struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
507
  	struct snd_pcm_str *pstr = entry->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
509
510
  	snd_iprintf(buffer, "%d
  ", pstr->xrun_debug);
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
511
512
  static void snd_pcm_xrun_debug_write(struct snd_info_entry *entry,
  				     struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
513
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
514
  	struct snd_pcm_str *pstr = entry->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
  	char line[64];
  	if (!snd_info_get_line(buffer, line, sizeof(line)))
  		pstr->xrun_debug = simple_strtoul(line, NULL, 10);
  }
  #endif
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
520
  static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
522
523
  	struct snd_pcm *pcm = pstr->pcm;
  	struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  	char name[16];
  
  	sprintf(name, "pcm%i%c", pcm->device, 
  		pstr->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c');
  	if ((entry = snd_info_create_card_entry(pcm->card, name, pcm->card->proc_root)) == NULL)
  		return -ENOMEM;
  	entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
  	if (snd_info_register(entry) < 0) {
  		snd_info_free_entry(entry);
  		return -ENOMEM;
  	}
  	pstr->proc_root = entry;
  
  	if ((entry = snd_info_create_card_entry(pcm->card, "info", pstr->proc_root)) != NULL) {
bf850204a   Takashi Iwai   [ALSA] Remove unn...
538
  		snd_info_set_text_ops(entry, pstr, snd_pcm_stream_proc_info_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
542
543
544
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			entry = NULL;
  		}
  	}
  	pstr->proc_info_entry = entry;
61fb63c09   Jaroslav Kysela   [ALSA] PCM core -...
545
  #ifdef CONFIG_SND_PCM_XRUN_DEBUG
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
546
547
  	if ((entry = snd_info_create_card_entry(pcm->card, "xrun_debug",
  						pstr->proc_root)) != NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  		entry->c.text.read = snd_pcm_xrun_debug_read;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
549
  		entry->c.text.write = snd_pcm_xrun_debug_write;
bd7bf042e   Takashi Iwai   [ALSA] Fix permis...
550
  		entry->mode |= S_IWUSR;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
555
556
557
558
559
560
  		entry->private_data = pstr;
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			entry = NULL;
  		}
  	}
  	pstr->proc_xrun_debug_entry = entry;
  #endif
  	return 0;
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
561
  static int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
  {
61fb63c09   Jaroslav Kysela   [ALSA] PCM core -...
563
  #ifdef CONFIG_SND_PCM_XRUN_DEBUG
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
564
565
  	snd_info_free_entry(pstr->proc_xrun_debug_entry);
  	pstr->proc_xrun_debug_entry = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  #endif
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
567
568
569
570
  	snd_info_free_entry(pstr->proc_info_entry);
  	pstr->proc_info_entry = NULL;
  	snd_info_free_entry(pstr->proc_root);
  	pstr->proc_root = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
  	return 0;
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
573
  static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
574
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
575
576
  	struct snd_info_entry *entry;
  	struct snd_card *card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
  	char name[16];
  
  	card = substream->pcm->card;
  
  	sprintf(name, "sub%i", substream->number);
  	if ((entry = snd_info_create_card_entry(card, name, substream->pstr->proc_root)) == NULL)
  		return -ENOMEM;
  	entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
  	if (snd_info_register(entry) < 0) {
  		snd_info_free_entry(entry);
  		return -ENOMEM;
  	}
  	substream->proc_root = entry;
  
  	if ((entry = snd_info_create_card_entry(card, "info", substream->proc_root)) != NULL) {
bf850204a   Takashi Iwai   [ALSA] Remove unn...
592
593
  		snd_info_set_text_ops(entry, substream,
  				      snd_pcm_substream_proc_info_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
597
598
599
600
601
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			entry = NULL;
  		}
  	}
  	substream->proc_info_entry = entry;
  
  	if ((entry = snd_info_create_card_entry(card, "hw_params", substream->proc_root)) != NULL) {
bf850204a   Takashi Iwai   [ALSA] Remove unn...
602
603
  		snd_info_set_text_ops(entry, substream,
  				      snd_pcm_substream_proc_hw_params_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
605
606
607
608
609
610
611
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			entry = NULL;
  		}
  	}
  	substream->proc_hw_params_entry = entry;
  
  	if ((entry = snd_info_create_card_entry(card, "sw_params", substream->proc_root)) != NULL) {
bf850204a   Takashi Iwai   [ALSA] Remove unn...
612
613
  		snd_info_set_text_ops(entry, substream,
  				      snd_pcm_substream_proc_sw_params_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
616
617
618
619
620
621
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			entry = NULL;
  		}
  	}
  	substream->proc_sw_params_entry = entry;
  
  	if ((entry = snd_info_create_card_entry(card, "status", substream->proc_root)) != NULL) {
bf850204a   Takashi Iwai   [ALSA] Remove unn...
622
623
  		snd_info_set_text_ops(entry, substream,
  				      snd_pcm_substream_proc_status_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
625
626
627
628
629
630
631
632
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			entry = NULL;
  		}
  	}
  	substream->proc_status_entry = entry;
  
  	return 0;
  }
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
633

877211f5e   Takashi Iwai   [ALSA] Remove xxx...
634
  static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
635
  {
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
636
637
638
639
640
641
642
643
644
645
  	snd_info_free_entry(substream->proc_info_entry);
  	substream->proc_info_entry = NULL;
  	snd_info_free_entry(substream->proc_hw_params_entry);
  	substream->proc_hw_params_entry = NULL;
  	snd_info_free_entry(substream->proc_sw_params_entry);
  	substream->proc_sw_params_entry = NULL;
  	snd_info_free_entry(substream->proc_status_entry);
  	substream->proc_status_entry = NULL;
  	snd_info_free_entry(substream->proc_root);
  	substream->proc_root = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
646
647
  	return 0;
  }
b7d90a356   Takashi Iwai   [ALSA] Fix Oops a...
648
  #else /* !CONFIG_SND_VERBOSE_PROCFS */
e28563cce   Takashi Iwai   [ALSA] Optimize f...
649
650
651
652
  static inline int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) { return 0; }
  static inline int snd_pcm_stream_proc_done(struct snd_pcm_str *pstr) { return 0; }
  static inline int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) { return 0; }
  static inline int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream) { return 0; }
b7d90a356   Takashi Iwai   [ALSA] Fix Oops a...
653
  #endif /* CONFIG_SND_VERBOSE_PROCFS */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
658
659
660
661
662
663
664
665
666
667
  
  /**
   * snd_pcm_new_stream - create a new PCM stream
   * @pcm: the pcm instance
   * @stream: the stream direction, SNDRV_PCM_STREAM_XXX
   * @substream_count: the number of substreams
   *
   * Creates a new stream for the pcm.
   * The corresponding stream on the pcm must have been empty before
   * calling this, i.e. zero must be given to the argument of
   * snd_pcm_new().
   *
   * Returns zero if successful, or a negative error code on failure.
   */
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
668
  int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
  {
  	int idx, err;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
671
672
  	struct snd_pcm_str *pstr = &pcm->streams[stream];
  	struct snd_pcm_substream *substream, *prev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  
  #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
675
  	mutex_init(&pstr->oss.setup_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
679
  #endif
  	pstr->stream = stream;
  	pstr->pcm = pcm;
  	pstr->substream_count = substream_count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
  	if (substream_count > 0) {
  		err = snd_pcm_stream_proc_init(pstr);
73e77ba02   Takashi Iwai   [ALSA] Add error ...
682
683
684
  		if (err < 0) {
  			snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  			return err;
73e77ba02   Takashi Iwai   [ALSA] Add error ...
686
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
  	}
  	prev = NULL;
  	for (idx = 0, prev = NULL; idx < substream_count; idx++) {
ca2c09665   Takashi Iwai   [ALSA] Replace wi...
690
  		substream = kzalloc(sizeof(*substream), GFP_KERNEL);
73e77ba02   Takashi Iwai   [ALSA] Add error ...
691
692
693
  		if (substream == NULL) {
  			snd_printk(KERN_ERR "Cannot allocate PCM substream
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
  			return -ENOMEM;
73e77ba02   Takashi Iwai   [ALSA] Add error ...
695
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
696
697
698
699
700
701
702
703
704
705
706
707
  		substream->pcm = pcm;
  		substream->pstr = pstr;
  		substream->number = idx;
  		substream->stream = stream;
  		sprintf(substream->name, "subdevice #%i", idx);
  		substream->buffer_bytes_max = UINT_MAX;
  		if (prev == NULL)
  			pstr->substream = substream;
  		else
  			prev->next = substream;
  		err = snd_pcm_substream_proc_init(substream);
  		if (err < 0) {
73e77ba02   Takashi Iwai   [ALSA] Add error ...
708
709
  			snd_printk(KERN_ERR "Error in snd_pcm_stream_proc_init
  ");
4d3612859   Akinobu Mita   [ALSA] sound: fix...
710
711
712
713
  			if (prev == NULL)
  				pstr->substream = NULL;
  			else
  				prev->next = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
715
716
717
718
719
720
  			kfree(substream);
  			return err;
  		}
  		substream->group = &substream->self_group;
  		spin_lock_init(&substream->self_group.lock);
  		INIT_LIST_HEAD(&substream->self_group.substreams);
  		list_add_tail(&substream->link_list, &substream->self_group.substreams);
9c323fcbc   Takashi Iwai   [ALSA] Fix mmap_c...
721
  		atomic_set(&substream->mmap_count, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
  		prev = substream;
  	}
  	return 0;
  }				
e88e8ae63   Takashi Iwai   [ALSA] Move OSS-s...
726
  EXPORT_SYMBOL(snd_pcm_new_stream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
  /**
   * snd_pcm_new - create a new PCM instance
   * @card: the card instance
   * @id: the id string
   * @device: the device index (zero based)
   * @playback_count: the number of substreams for playback
   * @capture_count: the number of substreams for capture
   * @rpcm: the pointer to store the new pcm instance
   *
   * Creates a new PCM instance.
   *
   * The pcm operators have to be set afterwards to the new instance
   * via snd_pcm_set_ops().
   *
   * Returns zero if successful, or a negative error code on failure.
   */
e61616530   Tim Blechmann   ALSA: snd_pcm_new...
743
  int snd_pcm_new(struct snd_card *card, const char *id, int device,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
  		int playback_count, int capture_count,
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
745
  	        struct snd_pcm ** rpcm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
746
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
747
  	struct snd_pcm *pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
748
  	int err;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
749
  	static struct snd_device_ops ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
  		.dev_free = snd_pcm_dev_free,
  		.dev_register =	snd_pcm_dev_register,
  		.dev_disconnect = snd_pcm_dev_disconnect,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
  	};
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
754
755
756
757
  	if (snd_BUG_ON(!card))
  		return -ENXIO;
  	if (rpcm)
  		*rpcm = NULL;
ca2c09665   Takashi Iwai   [ALSA] Replace wi...
758
  	pcm = kzalloc(sizeof(*pcm), GFP_KERNEL);
73e77ba02   Takashi Iwai   [ALSA] Add error ...
759
760
761
  	if (pcm == NULL) {
  		snd_printk(KERN_ERR "Cannot allocate PCM
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  		return -ENOMEM;
73e77ba02   Takashi Iwai   [ALSA] Add error ...
763
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
764
765
  	pcm->card = card;
  	pcm->device = device;
73e77ba02   Takashi Iwai   [ALSA] Add error ...
766
  	if (id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
  		strlcpy(pcm->id, id, sizeof(pcm->id));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
768
769
770
771
772
773
774
775
  	if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
  		snd_pcm_free(pcm);
  		return err;
  	}
  	if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) {
  		snd_pcm_free(pcm);
  		return err;
  	}
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
776
  	mutex_init(&pcm->open_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777
778
779
780
781
  	init_waitqueue_head(&pcm->open_wait);
  	if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) {
  		snd_pcm_free(pcm);
  		return err;
  	}
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
782
783
  	if (rpcm)
  		*rpcm = pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
784
785
  	return 0;
  }
e88e8ae63   Takashi Iwai   [ALSA] Move OSS-s...
786
  EXPORT_SYMBOL(snd_pcm_new);
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
787
  static void snd_pcm_free_stream(struct snd_pcm_str * pstr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
788
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
789
  	struct snd_pcm_substream *substream, *substream_next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
790
  #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
791
  	struct snd_pcm_oss_setup *setup, *setupn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
792
793
794
795
  #endif
  	substream = pstr->substream;
  	while (substream) {
  		substream_next = substream->next;
c461482c8   Takashi Iwai   [ALSA] Unregister...
796
  		snd_pcm_timer_done(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
797
798
799
800
801
802
803
804
805
806
807
808
809
  		snd_pcm_substream_proc_done(substream);
  		kfree(substream);
  		substream = substream_next;
  	}
  	snd_pcm_stream_proc_done(pstr);
  #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE)
  	for (setup = pstr->oss.setup_list; setup; setup = setupn) {
  		setupn = setup->next;
  		kfree(setup->task_name);
  		kfree(setup);
  	}
  #endif
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
810
  static int snd_pcm_free(struct snd_pcm *pcm)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  {
c461482c8   Takashi Iwai   [ALSA] Unregister...
812
  	struct snd_pcm_notify *notify;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
813
814
  	if (!pcm)
  		return 0;
c461482c8   Takashi Iwai   [ALSA] Unregister...
815
816
817
  	list_for_each_entry(notify, &snd_pcm_notify_list, list) {
  		notify->n_unregister(pcm);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
818
819
820
821
822
823
824
825
  	if (pcm->private_free)
  		pcm->private_free(pcm);
  	snd_pcm_lib_preallocate_free_for_all(pcm);
  	snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]);
  	snd_pcm_free_stream(&pcm->streams[SNDRV_PCM_STREAM_CAPTURE]);
  	kfree(pcm);
  	return 0;
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
826
  static int snd_pcm_dev_free(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
828
  	struct snd_pcm *pcm = device->device_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
  	return snd_pcm_free(pcm);
  }
3bf75f9b9   Takashi Iwai   [ALSA] Clean up P...
831
832
833
  int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
  			     struct file *file,
  			     struct snd_pcm_substream **rsubstream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
835
836
837
838
839
  	struct snd_pcm_str * pstr;
  	struct snd_pcm_substream *substream;
  	struct snd_pcm_runtime *runtime;
  	struct snd_ctl_file *kctl;
  	struct snd_card *card;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
  	int prefer_subdevice = -1;
  	size_t size;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
842
843
  	if (snd_BUG_ON(!pcm || !rsubstream))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
844
  	*rsubstream = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  	pstr = &pcm->streams[stream];
3bf75f9b9   Takashi Iwai   [ALSA] Clean up P...
846
  	if (pstr->substream == NULL || pstr->substream_count == 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
848
849
  		return -ENODEV;
  
  	card = pcm->card;
399ccdc1c   Takashi Iwai   ALSA: fix locking...
850
  	read_lock(&card->ctl_files_rwlock);
9244b2c30   Johannes Berg   [ALSA] alsa core:...
851
  	list_for_each_entry(kctl, &card->ctl_files, list) {
25d27eded   Clemens Ladisch   control: use refe...
852
  		if (kctl->pid == task_pid(current)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
853
  			prefer_subdevice = kctl->prefer_pcm_subdevice;
2529bba76   Takashi Iwai   [ALSA] Fix substr...
854
855
  			if (prefer_subdevice != -1)
  				break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
857
  		}
  	}
399ccdc1c   Takashi Iwai   ALSA: fix locking...
858
  	read_unlock(&card->ctl_files_rwlock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
  	switch (stream) {
  	case SNDRV_PCM_STREAM_PLAYBACK:
  		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
  			for (substream = pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream; substream; substream = substream->next) {
  				if (SUBSTREAM_BUSY(substream))
  					return -EAGAIN;
  			}
  		}
  		break;
  	case SNDRV_PCM_STREAM_CAPTURE:
  		if (pcm->info_flags & SNDRV_PCM_INFO_HALF_DUPLEX) {
  			for (substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; substream; substream = substream->next) {
  				if (SUBSTREAM_BUSY(substream))
  					return -EAGAIN;
  			}
  		}
  		break;
  	default:
  		return -EINVAL;
  	}
0df63e44c   Takashi Iwai   [ALSA] Add O_APPE...
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
  	if (file->f_flags & O_APPEND) {
  		if (prefer_subdevice < 0) {
  			if (pstr->substream_count > 1)
  				return -EINVAL; /* must be unique */
  			substream = pstr->substream;
  		} else {
  			for (substream = pstr->substream; substream;
  			     substream = substream->next)
  				if (substream->number == prefer_subdevice)
  					break;
  		}
  		if (! substream)
  			return -ENODEV;
  		if (! SUBSTREAM_BUSY(substream))
  			return -EBADFD;
  		substream->ref_count++;
  		*rsubstream = substream;
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
902
903
904
905
906
907
908
909
  	if (prefer_subdevice >= 0) {
  		for (substream = pstr->substream; substream; substream = substream->next)
  			if (!SUBSTREAM_BUSY(substream) && substream->number == prefer_subdevice)
  				goto __ok;
  	}
  	for (substream = pstr->substream; substream; substream = substream->next)
  		if (!SUBSTREAM_BUSY(substream))
  			break;
        __ok:
  	if (substream == NULL)
  		return -EAGAIN;
ca2c09665   Takashi Iwai   [ALSA] Replace wi...
910
  	runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
  	if (runtime == NULL)
  		return -ENOMEM;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
913
  	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
914
915
916
917
918
919
  	runtime->status = snd_malloc_pages(size, GFP_KERNEL);
  	if (runtime->status == NULL) {
  		kfree(runtime);
  		return -ENOMEM;
  	}
  	memset((void*)runtime->status, 0, size);
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
920
  	size = PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
921
922
  	runtime->control = snd_malloc_pages(size, GFP_KERNEL);
  	if (runtime->control == NULL) {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
923
924
  		snd_free_pages((void*)runtime->status,
  			       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
926
927
928
929
930
  		kfree(runtime);
  		return -ENOMEM;
  	}
  	memset((void*)runtime->control, 0, size);
  
  	init_waitqueue_head(&runtime->sleep);
c91a988dc   Jaroslav Kysela   ALSA: pcm_core: F...
931
  	init_waitqueue_head(&runtime->tsleep);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
933
934
935
936
  
  	runtime->status->state = SNDRV_PCM_STATE_OPEN;
  
  	substream->runtime = runtime;
  	substream->private_data = pcm->private_data;
0df63e44c   Takashi Iwai   [ALSA] Add O_APPE...
937
938
  	substream->ref_count = 1;
  	substream->f_flags = file->f_flags;
e7373b702   Clemens Ladisch   sound: pcm: recor...
939
  	substream->pid = get_pid(task_pid(current));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
943
  	pstr->substream_opened++;
  	*rsubstream = substream;
  	return 0;
  }
3bf75f9b9   Takashi Iwai   [ALSA] Clean up P...
944
  void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
945
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
946
  	struct snd_pcm_runtime *runtime;
0df63e44c   Takashi Iwai   [ALSA] Add O_APPE...
947

7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
948
949
  	if (PCM_RUNTIME_CHECK(substream))
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
950
  	runtime = substream->runtime;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
  	if (runtime->private_free != NULL)
  		runtime->private_free(runtime);
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
953
954
955
956
  	snd_free_pages((void*)runtime->status,
  		       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)));
  	snd_free_pages((void*)runtime->control,
  		       PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
  	kfree(runtime->hw_constraints.rules);
4d96eb255   Jaroslav Kysela   ALSA: pcm_lib - a...
958
959
960
961
  #ifdef CONFIG_SND_PCM_XRUN_DEBUG
  	if (runtime->hwptr_log)
  		kfree(runtime->hwptr_log);
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
962
963
  	kfree(runtime);
  	substream->runtime = NULL;
e7373b702   Clemens Ladisch   sound: pcm: recor...
964
965
  	put_pid(substream->pid);
  	substream->pid = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
966
967
  	substream->pstr->substream_opened--;
  }
d80f19fab   Greg Kroah-Hartman   Driver core: conv...
968
969
  static ssize_t show_pcm_class(struct device *dev,
  			      struct device_attribute *attr, char *buf)
9d19f48cf   Takashi Iwai   [ALSA] Add pcm_cl...
970
971
972
973
974
975
976
977
978
  {
  	struct snd_pcm *pcm;
  	const char *str;
  	static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
  		[SNDRV_PCM_CLASS_GENERIC] = "generic",
  		[SNDRV_PCM_CLASS_MULTI] = "multi",
  		[SNDRV_PCM_CLASS_MODEM] = "modem",
  		[SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
  	};
d80f19fab   Greg Kroah-Hartman   Driver core: conv...
979
  	if (! (pcm = dev_get_drvdata(dev)) ||
9d19f48cf   Takashi Iwai   [ALSA] Add pcm_cl...
980
981
982
983
984
985
986
  	    pcm->dev_class > SNDRV_PCM_CLASS_LAST)
  		str = "none";
  	else
  		str = strs[pcm->dev_class];
          return snprintf(buf, PAGE_SIZE, "%s
  ", str);
  }
d80f19fab   Greg Kroah-Hartman   Driver core: conv...
987
  static struct device_attribute pcm_attrs =
9d19f48cf   Takashi Iwai   [ALSA] Add pcm_cl...
988
  	__ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL);
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
989
  static int snd_pcm_dev_register(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
990
  {
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
991
  	int cidx, err;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
992
  	struct snd_pcm_substream *substream;
9244b2c30   Johannes Berg   [ALSA] alsa core:...
993
  	struct snd_pcm_notify *notify;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
994
  	char str[16];
4b3be6afa   Julia Lawall   ALSA: sound: Move...
995
  	struct snd_pcm *pcm;
c78085fcd   Johannes Berg   [ALSA] alsa core:...
996
  	struct device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
997

4b3be6afa   Julia Lawall   ALSA: sound: Move...
998
  	if (snd_BUG_ON(!device || !device->device_data))
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
999
  		return -ENXIO;
4b3be6afa   Julia Lawall   ALSA: sound: Move...
1000
  	pcm = device->device_data;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1001
  	mutex_lock(&register_mutex);
f90c06a2b   Pawel MOLL   ALSA: Fix limit o...
1002
1003
  	err = snd_pcm_add(pcm);
  	if (err) {
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1004
  		mutex_unlock(&register_mutex);
f90c06a2b   Pawel MOLL   ALSA: Fix limit o...
1005
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
1009
1010
1011
1012
1013
  	for (cidx = 0; cidx < 2; cidx++) {
  		int devtype = -1;
  		if (pcm->streams[cidx].substream == NULL)
  			continue;
  		switch (cidx) {
  		case SNDRV_PCM_STREAM_PLAYBACK:
  			sprintf(str, "pcmC%iD%ip", pcm->card->number, pcm->device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1014
1015
1016
1017
  			devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
  			break;
  		case SNDRV_PCM_STREAM_CAPTURE:
  			sprintf(str, "pcmC%iD%ic", pcm->card->number, pcm->device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
1019
1020
  			devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
  			break;
  		}
c78085fcd   Johannes Berg   [ALSA] alsa core:...
1021
1022
1023
1024
1025
  		/* device pointer to use, pcm->dev takes precedence if
  		 * it is assigned, otherwise fall back to card's device
  		 * if possible */
  		dev = pcm->dev;
  		if (!dev)
c2902c8ae   Takashi Iwai   [PATCH] Fix break...
1026
  			dev = snd_card_get_device_link(pcm->card);
c78085fcd   Johannes Berg   [ALSA] alsa core:...
1027
1028
1029
1030
1031
1032
  		/* register pcm */
  		err = snd_register_device_for_dev(devtype, pcm->card,
  						  pcm->device,
  						  &snd_pcm_f_ops[cidx],
  						  pcm, str, dev);
  		if (err < 0) {
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
1033
  			list_del(&pcm->list);
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1034
  			mutex_unlock(&register_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1035
1036
  			return err;
  		}
9d19f48cf   Takashi Iwai   [ALSA] Add pcm_cl...
1037
1038
  		snd_add_device_sysfs_file(devtype, pcm->card, pcm->device,
  					  &pcm_attrs);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1039
1040
1041
  		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
  			snd_pcm_timer_init(substream);
  	}
9244b2c30   Johannes Berg   [ALSA] alsa core:...
1042
1043
  
  	list_for_each_entry(notify, &snd_pcm_notify_list, list)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1044
  		notify->n_register(pcm);
9244b2c30   Johannes Berg   [ALSA] alsa core:...
1045

1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1046
  	mutex_unlock(&register_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
  	return 0;
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1049
  static int snd_pcm_dev_disconnect(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1050
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1051
  	struct snd_pcm *pcm = device->device_data;
c461482c8   Takashi Iwai   [ALSA] Unregister...
1052
  	struct snd_pcm_notify *notify;
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1053
  	struct snd_pcm_substream *substream;
c461482c8   Takashi Iwai   [ALSA] Unregister...
1054
  	int cidx, devtype;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1055

1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1056
  	mutex_lock(&register_mutex);
c461482c8   Takashi Iwai   [ALSA] Unregister...
1057
1058
  	if (list_empty(&pcm->list))
  		goto unlock;
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
1059
  	list_del_init(&pcm->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
1061
1062
1063
  	for (cidx = 0; cidx < 2; cidx++)
  		for (substream = pcm->streams[cidx].substream; substream; substream = substream->next)
  			if (substream->runtime)
  				substream->runtime->status->state = SNDRV_PCM_STATE_DISCONNECTED;
c461482c8   Takashi Iwai   [ALSA] Unregister...
1064
  	list_for_each_entry(notify, &snd_pcm_notify_list, list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1065
1066
  		notify->n_disconnect(pcm);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
  	for (cidx = 0; cidx < 2; cidx++) {
  		devtype = -1;
  		switch (cidx) {
  		case SNDRV_PCM_STREAM_PLAYBACK:
  			devtype = SNDRV_DEVICE_TYPE_PCM_PLAYBACK;
  			break;
  		case SNDRV_PCM_STREAM_CAPTURE:
  			devtype = SNDRV_DEVICE_TYPE_PCM_CAPTURE;
  			break;
  		}
  		snd_unregister_device(devtype, pcm->card, pcm->device);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1078
  	}
c461482c8   Takashi Iwai   [ALSA] Unregister...
1079
   unlock:
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1080
  	mutex_unlock(&register_mutex);
c461482c8   Takashi Iwai   [ALSA] Unregister...
1081
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
  }
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1083
  int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
  {
9244b2c30   Johannes Berg   [ALSA] alsa core:...
1085
  	struct snd_pcm *pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1086

7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
1087
1088
1089
1090
1091
  	if (snd_BUG_ON(!notify ||
  		       !notify->n_register ||
  		       !notify->n_unregister ||
  		       !notify->n_disconnect))
  		return -EINVAL;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1092
  	mutex_lock(&register_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
1094
  	if (nfree) {
  		list_del(&notify->list);
9244b2c30   Johannes Berg   [ALSA] alsa core:...
1095
1096
  		list_for_each_entry(pcm, &snd_pcm_devices, list)
  			notify->n_unregister(pcm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1097
1098
  	} else {
  		list_add_tail(&notify->list, &snd_pcm_notify_list);
9244b2c30   Johannes Berg   [ALSA] alsa core:...
1099
1100
  		list_for_each_entry(pcm, &snd_pcm_devices, list)
  			notify->n_register(pcm);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1101
  	}
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1102
  	mutex_unlock(&register_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1103
1104
  	return 0;
  }
e88e8ae63   Takashi Iwai   [ALSA] Move OSS-s...
1105
  EXPORT_SYMBOL(snd_pcm_notify);
e28563cce   Takashi Iwai   [ALSA] Optimize f...
1106
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
1108
1109
  /*
   *  Info interface
   */
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1110
1111
  static void snd_pcm_proc_read(struct snd_info_entry *entry,
  			      struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1112
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1113
  	struct snd_pcm *pcm;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1114

1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1115
  	mutex_lock(&register_mutex);
9244b2c30   Johannes Berg   [ALSA] alsa core:...
1116
  	list_for_each_entry(pcm, &snd_pcm_devices, list) {
f87135f56   Clemens Ladisch   [ALSA] dynamic mi...
1117
1118
  		snd_iprintf(buffer, "%02i-%02i: %s : %s",
  			    pcm->card->number, pcm->device, pcm->id, pcm->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1119
  		if (pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1120
1121
  			snd_iprintf(buffer, " : playback %i",
  				    pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1122
  		if (pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream)
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1123
1124
  			snd_iprintf(buffer, " : capture %i",
  				    pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1125
1126
1127
  		snd_iprintf(buffer, "
  ");
  	}
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
1128
  	mutex_unlock(&register_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1129
  }
6581f4e74   Takashi Iwai   [ALSA] Remove zer...
1130
  static struct snd_info_entry *snd_pcm_proc_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1131

e28563cce   Takashi Iwai   [ALSA] Optimize f...
1132
  static void snd_pcm_proc_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
  {
877211f5e   Takashi Iwai   [ALSA] Remove xxx...
1134
  	struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1135

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1136
  	if ((entry = snd_info_create_module_entry(THIS_MODULE, "pcm", NULL)) != NULL) {
bf850204a   Takashi Iwai   [ALSA] Remove unn...
1137
  		snd_info_set_text_ops(entry, NULL, snd_pcm_proc_read);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1138
1139
1140
1141
1142
1143
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			entry = NULL;
  		}
  	}
  	snd_pcm_proc_entry = entry;
e28563cce   Takashi Iwai   [ALSA] Optimize f...
1144
1145
1146
1147
  }
  
  static void snd_pcm_proc_done(void)
  {
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
1148
  	snd_info_free_entry(snd_pcm_proc_entry);
e28563cce   Takashi Iwai   [ALSA] Optimize f...
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
  }
  
  #else /* !CONFIG_PROC_FS */
  #define snd_pcm_proc_init()
  #define snd_pcm_proc_done()
  #endif /* CONFIG_PROC_FS */
  
  
  /*
   *  ENTRY functions
   */
  
  static int __init alsa_pcm_init(void)
  {
  	snd_ctl_register_ioctl(snd_pcm_control_ioctl);
  	snd_ctl_register_ioctl_compat(snd_pcm_control_ioctl);
  	snd_pcm_proc_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1166
1167
1168
1169
1170
1171
1172
  	return 0;
  }
  
  static void __exit alsa_pcm_exit(void)
  {
  	snd_ctl_unregister_ioctl(snd_pcm_control_ioctl);
  	snd_ctl_unregister_ioctl_compat(snd_pcm_control_ioctl);
e28563cce   Takashi Iwai   [ALSA] Optimize f...
1173
  	snd_pcm_proc_done();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1174
1175
1176
1177
  }
  
  module_init(alsa_pcm_init)
  module_exit(alsa_pcm_exit)