Blame view

sound/core/info.c 22.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *  Information interface for ALSA driver
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
  #include <linux/init.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <linux/time.h>
27ac792ca   Andrea Righi   PAGE_ALIGN(): cor...
23
  #include <linux/mm.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
24
  #include <linux/slab.h>
543537bd9   Paulo Marques   [PATCH] create a ...
25
  #include <linux/string.h>
da155d5b4   Paul Gortmaker   sound: Add module...
26
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  #include <sound/core.h>
  #include <sound/minors.h>
  #include <sound/info.h>
426627483   Jaroslav Kysela   ALSA: remove the ...
30
  #include <linux/utsname.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  #include <linux/proc_fs.h>
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
32
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
35
36
37
  #include <stdarg.h>
  
  /*
   *
   */
e28563cce   Takashi Iwai   [ALSA] Optimize f...
38
  #ifdef CONFIG_PROC_FS
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
  int snd_info_check_reserved_words(const char *str)
  {
  	static char *reserved[] =
  	{
  		"version",
  		"meminfo",
  		"memdebug",
  		"detect",
  		"devices",
  		"oss",
  		"cards",
  		"timers",
  		"synth",
  		"pcm",
  		"seq",
  		NULL
  	};
  	char **xstr = reserved;
  
  	while (*xstr) {
  		if (!strcmp(*xstr, str))
  			return 0;
  		xstr++;
  	}
  	if (!strncmp(str, "card", 4))
  		return 0;
  	return 1;
  }
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
67
  static DEFINE_MUTEX(info_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68

24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
69
70
71
72
  struct snd_info_private_data {
  	struct snd_info_buffer *rbuffer;
  	struct snd_info_buffer *wbuffer;
  	struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
73
  	void *file_private_data;
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
74
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
75
76
77
  
  static int snd_info_version_init(void);
  static int snd_info_version_done(void);
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
78
  static void snd_info_disconnect(struct snd_info_entry *entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79

7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
80
81
82
83
84
85
86
  /* resize the proc r/w buffer */
  static int resize_info_buffer(struct snd_info_buffer *buffer,
  			      unsigned int nsize)
  {
  	char *nbuf;
  
  	nsize = PAGE_ALIGN(nsize);
0d861ac23   Takashi Iwai   ALSA: info: Avoid...
87
  	nbuf = krealloc(buffer->buffer, nsize, GFP_KERNEL | __GFP_ZERO);
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
88
89
  	if (! nbuf)
  		return -ENOMEM;
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
90
91
92
93
  	buffer->buffer = nbuf;
  	buffer->len = nsize;
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
98
99
100
  /**
   * snd_iprintf - printf on the procfs buffer
   * @buffer: the procfs buffer
   * @fmt: the printf format
   *
   * Outputs the string on the procfs buffer just like printf().
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
101
   * Return: The size of output string, or a negative error code.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
102
   */
4f7454a99   Takashi Iwai   ALSA: Add const p...
103
  int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
  {
  	va_list args;
  	int len, res;
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
107
  	int err = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
108

f001c3acf   Takashi Iwai   [ALSA] Insert mig...
109
  	might_sleep();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
111
112
113
  	if (buffer->stop || buffer->error)
  		return 0;
  	len = buffer->len - buffer->size;
  	va_start(args, fmt);
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
114
  	for (;;) {
dbedca39f   Takashi Iwai   [ALSA] Fix re-use...
115
116
117
118
  		va_list ap;
  		va_copy(ap, args);
  		res = vsnprintf(buffer->buffer + buffer->curr, len, fmt, ap);
  		va_end(ap);
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
119
120
121
122
123
124
  		if (res < len)
  			break;
  		err = resize_info_buffer(buffer, buffer->len + PAGE_SIZE);
  		if (err < 0)
  			break;
  		len = buffer->len - buffer->size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	}
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
126
127
128
129
  	va_end(args);
  
  	if (err < 0)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
132
133
  	buffer->curr += res;
  	buffer->size += res;
  	return res;
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
134
  EXPORT_SYMBOL(snd_iprintf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135
136
137
  /*
  
   */
6581f4e74   Takashi Iwai   [ALSA] Remove zer...
138
139
  static struct proc_dir_entry *snd_proc_root;
  struct snd_info_entry *snd_seq_root;
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
140
  EXPORT_SYMBOL(snd_seq_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  #ifdef CONFIG_SND_OSSEMUL
6581f4e74   Takashi Iwai   [ALSA] Remove zer...
142
  struct snd_info_entry *snd_oss_root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
  static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
146
  	struct snd_info_private_data *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  	struct snd_info_entry *entry;
73029e0ff   Takashi Iwai   ALSA: info - Impl...
148
  	loff_t ret = -EINVAL, size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
  
  	data = file->private_data;
  	entry = data->entry;
5b5cd553e   Takashi Iwai   ALSA: info - Remo...
152
  	mutex_lock(&entry->access);
73029e0ff   Takashi Iwai   ALSA: info - Impl...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
  	if (entry->content == SNDRV_INFO_CONTENT_DATA &&
  	    entry->c.ops->llseek) {
  		offset = entry->c.ops->llseek(entry,
  					      data->file_private_data,
  					      file, offset, orig);
  		goto out;
  	}
  	if (entry->content == SNDRV_INFO_CONTENT_DATA)
  		size = entry->size;
  	else
  		size = 0;
  	switch (orig) {
  	case SEEK_SET:
  		break;
  	case SEEK_CUR:
  		offset += file->f_pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
169
  		break;
73029e0ff   Takashi Iwai   ALSA: info - Impl...
170
171
  	case SEEK_END:
  		if (!size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  			goto out;
73029e0ff   Takashi Iwai   ALSA: info - Impl...
173
  		offset += size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  		break;
73029e0ff   Takashi Iwai   ALSA: info - Impl...
175
176
  	default:
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
177
  	}
73029e0ff   Takashi Iwai   ALSA: info - Impl...
178
179
180
181
182
183
184
  	if (offset < 0)
  		goto out;
  	if (size && offset > size)
  		offset = size;
  	file->f_pos = offset;
  	ret = offset;
   out:
5b5cd553e   Takashi Iwai   ALSA: info - Remo...
185
  	mutex_unlock(&entry->access);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
190
191
  	return ret;
  }
  
  static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
  				   size_t count, loff_t * offset)
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
192
  	struct snd_info_private_data *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
  	struct snd_info_entry *entry;
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
194
  	struct snd_info_buffer *buf;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
197
198
  	size_t size = 0;
  	loff_t pos;
  
  	data = file->private_data;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
199
200
  	if (snd_BUG_ON(!data))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
  	pos = *offset;
  	if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
  		return -EIO;
  	if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
  		return -EIO;
  	entry = data->entry;
  	switch (entry->content) {
  	case SNDRV_INFO_CONTENT_TEXT:
  		buf = data->rbuffer;
  		if (buf == NULL)
  			return -EIO;
  		if (pos >= buf->size)
  			return 0;
  		size = buf->size - pos;
  		size = min(count, size);
  		if (copy_to_user(buffer, buf->buffer + pos, size))
  			return -EFAULT;
  		break;
  	case SNDRV_INFO_CONTENT_DATA:
d97e1b782   Takashi Iwai   ALSA: info - Chec...
220
221
222
223
224
  		if (pos >= entry->size)
  			return 0;
  		if (entry->c.ops->read) {
  			size = entry->size - pos;
  			size = min(count, size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
  			size = entry->c.ops->read(entry,
  						  data->file_private_data,
d97e1b782   Takashi Iwai   ALSA: info - Chec...
227
228
  						  file, buffer, size, pos);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
231
232
233
234
235
236
237
238
  		break;
  	}
  	if ((ssize_t) size > 0)
  		*offset = pos + size;
  	return size;
  }
  
  static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
  				    size_t count, loff_t * offset)
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
239
  	struct snd_info_private_data *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  	struct snd_info_entry *entry;
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
241
  	struct snd_info_buffer *buf;
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
242
  	ssize_t size = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
243
244
245
  	loff_t pos;
  
  	data = file->private_data;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
246
247
  	if (snd_BUG_ON(!data))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
248
249
250
251
252
253
254
255
256
257
258
  	entry = data->entry;
  	pos = *offset;
  	if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
  		return -EIO;
  	if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
  		return -EIO;
  	switch (entry->content) {
  	case SNDRV_INFO_CONTENT_TEXT:
  		buf = data->wbuffer;
  		if (buf == NULL)
  			return -EIO;
f4a747f15   Clemens Ladisch   [ALSA] fix a wron...
259
  		mutex_lock(&entry->access);
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
260
261
262
263
264
265
266
267
  		if (pos + count >= buf->len) {
  			if (resize_info_buffer(buf, pos + count)) {
  				mutex_unlock(&entry->access);
  				return -ENOMEM;
  			}
  		}
  		if (copy_from_user(buf->buffer + pos, buffer, count)) {
  			mutex_unlock(&entry->access);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
  			return -EFAULT;
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
269
270
271
272
  		}
  		buf->size = pos + count;
  		mutex_unlock(&entry->access);
  		size = count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  		break;
  	case SNDRV_INFO_CONTENT_DATA:
d97e1b782   Takashi Iwai   ALSA: info - Chec...
275
276
277
  		if (entry->c.ops->write && count > 0) {
  			size_t maxsize = entry->size - pos;
  			count = min(count, maxsize);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
278
279
280
  			size = entry->c.ops->write(entry,
  						   data->file_private_data,
  						   file, buffer, count, pos);
d97e1b782   Takashi Iwai   ALSA: info - Chec...
281
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
283
284
285
286
287
288
289
290
  		break;
  	}
  	if ((ssize_t) size > 0)
  		*offset = pos + size;
  	return size;
  }
  
  static int snd_info_entry_open(struct inode *inode, struct file *file)
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
291
292
293
  	struct snd_info_entry *entry;
  	struct snd_info_private_data *data;
  	struct snd_info_buffer *buffer;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
294
  	int mode, err;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
295
  	mutex_lock(&info_mutex);
d9dda78ba   Al Viro   procfs: new helpe...
296
  	entry = PDE_DATA(inode);
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
297
  	if (entry == NULL || ! entry->p) {
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
298
  		mutex_unlock(&info_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
300
301
302
303
304
305
306
  		return -ENODEV;
  	}
  	if (!try_module_get(entry->module)) {
  		err = -EFAULT;
  		goto __error1;
  	}
  	mode = file->f_flags & O_ACCMODE;
  	if (mode == O_RDONLY || mode == O_RDWR) {
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
307
  		if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
308
309
310
311
312
313
  		     entry->c.ops->read == NULL)) {
  		    	err = -ENODEV;
  		    	goto __error;
  		}
  	}
  	if (mode == O_WRONLY || mode == O_RDWR) {
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
314
  		if ((entry->content == SNDRV_INFO_CONTENT_DATA &&
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
318
319
  		     entry->c.ops->write == NULL)) {
  		    	err = -ENODEV;
  		    	goto __error;
  		}
  	}
ca2c09665   Takashi Iwai   [ALSA] Replace wi...
320
  	data = kzalloc(sizeof(*data), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
322
323
324
325
326
327
328
  	if (data == NULL) {
  		err = -ENOMEM;
  		goto __error;
  	}
  	data->entry = entry;
  	switch (entry->content) {
  	case SNDRV_INFO_CONTENT_TEXT:
  		if (mode == O_RDONLY || mode == O_RDWR) {
ca2c09665   Takashi Iwai   [ALSA] Replace wi...
329
  			buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
330
331
  			if (buffer == NULL)
  				goto __nomem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
  			data->rbuffer = buffer;
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
333
  			buffer->len = PAGE_SIZE;
0d861ac23   Takashi Iwai   ALSA: info: Avoid...
334
  			buffer->buffer = kzalloc(buffer->len, GFP_KERNEL);
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
335
336
  			if (buffer->buffer == NULL)
  				goto __nomem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
  		}
  		if (mode == O_WRONLY || mode == O_RDWR) {
ca2c09665   Takashi Iwai   [ALSA] Replace wi...
339
  			buffer = kzalloc(sizeof(*buffer), GFP_KERNEL);
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
340
341
  			if (buffer == NULL)
  				goto __nomem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  			data->wbuffer = buffer;
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
343
344
345
346
  			buffer->len = PAGE_SIZE;
  			buffer->buffer = kmalloc(buffer->len, GFP_KERNEL);
  			if (buffer->buffer == NULL)
  				goto __nomem;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
351
352
353
354
355
356
357
358
359
  		}
  		break;
  	case SNDRV_INFO_CONTENT_DATA:	/* data */
  		if (entry->c.ops->open) {
  			if ((err = entry->c.ops->open(entry, mode,
  						      &data->file_private_data)) < 0) {
  				kfree(data);
  				goto __error;
  			}
  		}
  		break;
  	}
  	file->private_data = data;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
360
  	mutex_unlock(&info_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
361
362
363
  	if (entry->content == SNDRV_INFO_CONTENT_TEXT &&
  	    (mode == O_RDONLY || mode == O_RDWR)) {
  		if (entry->c.text.read) {
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
364
  			mutex_lock(&entry->access);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
  			entry->c.text.read(entry, data->rbuffer);
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
366
  			mutex_unlock(&entry->access);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
368
369
  		}
  	}
  	return 0;
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
370
371
372
373
374
375
376
377
378
379
380
   __nomem:
  	if (data->rbuffer) {
  		kfree(data->rbuffer->buffer);
  		kfree(data->rbuffer);
  	}
  	if (data->wbuffer) {
  		kfree(data->wbuffer->buffer);
  		kfree(data->wbuffer);
  	}
  	kfree(data);
  	err = -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
382
383
        __error:
  	module_put(entry->module);
        __error1:
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
384
  	mutex_unlock(&info_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
385
386
387
388
389
  	return err;
  }
  
  static int snd_info_entry_release(struct inode *inode, struct file *file)
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
390
391
  	struct snd_info_entry *entry;
  	struct snd_info_private_data *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
397
398
  	int mode;
  
  	mode = file->f_flags & O_ACCMODE;
  	data = file->private_data;
  	entry = data->entry;
  	switch (entry->content) {
  	case SNDRV_INFO_CONTENT_TEXT:
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
399
400
  		if (data->rbuffer) {
  			kfree(data->rbuffer->buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
401
402
  			kfree(data->rbuffer);
  		}
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
403
  		if (data->wbuffer) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
  			if (entry->c.text.write) {
  				entry->c.text.write(entry, data->wbuffer);
  				if (data->wbuffer->error) {
f2f9307a4   Takashi Iwai   ALSA: core: Use s...
407
408
409
410
411
412
413
414
415
416
  					if (entry->card)
  						dev_warn(entry->card->dev, "info: data write error to %s (%i)
  ",
  							 entry->name,
  							 data->wbuffer->error);
  					else
  						pr_warn("ALSA: info: data write error to %s (%i)
  ",
  							entry->name,
  							data->wbuffer->error);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
417
418
  				}
  			}
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
419
  			kfree(data->wbuffer->buffer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
  			kfree(data->wbuffer);
  		}
  		break;
  	case SNDRV_INFO_CONTENT_DATA:
  		if (entry->c.ops->release)
  			entry->c.ops->release(entry, mode,
  					      data->file_private_data);
  		break;
  	}
  	module_put(entry->module);
  	kfree(data);
  	return 0;
  }
  
  static unsigned int snd_info_entry_poll(struct file *file, poll_table * wait)
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
436
  	struct snd_info_private_data *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
  	struct snd_info_entry *entry;
  	unsigned int mask;
  
  	data = file->private_data;
  	if (data == NULL)
  		return 0;
  	entry = data->entry;
  	mask = 0;
  	switch (entry->content) {
  	case SNDRV_INFO_CONTENT_DATA:
  		if (entry->c.ops->poll)
  			return entry->c.ops->poll(entry,
  						  data->file_private_data,
  						  file, wait);
  		if (entry->c.ops->read)
  			mask |= POLLIN | POLLRDNORM;
  		if (entry->c.ops->write)
  			mask |= POLLOUT | POLLWRNORM;
  		break;
  	}
  	return mask;
  }
d99e98891   Ingo Molnar   [ALSA] Remove BKL...
459
460
  static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,
  				unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
461
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
462
  	struct snd_info_private_data *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
  	struct snd_info_entry *entry;
  
  	data = file->private_data;
  	if (data == NULL)
  		return 0;
  	entry = data->entry;
  	switch (entry->content) {
  	case SNDRV_INFO_CONTENT_DATA:
  		if (entry->c.ops->ioctl)
  			return entry->c.ops->ioctl(entry,
  						   data->file_private_data,
  						   file, cmd, arg);
  		break;
  	}
  	return -ENOTTY;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
479
480
  static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
  {
496ad9aa8   Al Viro   new helper: file_...
481
  	struct inode *inode = file_inode(file);
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
482
  	struct snd_info_private_data *data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  	struct snd_info_entry *entry;
  
  	data = file->private_data;
  	if (data == NULL)
  		return 0;
  	entry = data->entry;
  	switch (entry->content) {
  	case SNDRV_INFO_CONTENT_DATA:
  		if (entry->c.ops->mmap)
  			return entry->c.ops->mmap(entry,
  						  data->file_private_data,
  						  inode, file, vma);
  		break;
  	}
  	return -ENXIO;
  }
9c2e08c59   Arjan van de Ven   [PATCH] mark stru...
499
  static const struct file_operations snd_info_entry_operations =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  {
d99e98891   Ingo Molnar   [ALSA] Remove BKL...
501
502
503
504
505
506
507
508
509
  	.owner =		THIS_MODULE,
  	.llseek =		snd_info_entry_llseek,
  	.read =			snd_info_entry_read,
  	.write =		snd_info_entry_write,
  	.poll =			snd_info_entry_poll,
  	.unlocked_ioctl =	snd_info_entry_ioctl,
  	.mmap =			snd_info_entry_mmap,
  	.open =			snd_info_entry_open,
  	.release =		snd_info_entry_release,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
513
  int __init snd_info_init(void)
  {
  	struct proc_dir_entry *p;
e55d92b92   Al Viro   get rid of create...
514
  	p = proc_mkdir("asound", NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
519
  	if (p == NULL)
  		return -ENOMEM;
  	snd_proc_root = p;
  #ifdef CONFIG_SND_OSSEMUL
  	{
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
520
  		struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
525
526
527
528
529
530
  		if ((entry = snd_info_create_module_entry(THIS_MODULE, "oss", NULL)) == NULL)
  			return -ENOMEM;
  		entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			return -ENOMEM;
  		}
  		snd_oss_root = entry;
  	}
  #endif
8eeaa2f9e   Takashi Iwai   ALSA: Replace wit...
531
  #if IS_ENABLED(CONFIG_SND_SEQUENCER)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  	{
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
533
  		struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
536
537
538
539
540
541
542
543
544
  		if ((entry = snd_info_create_module_entry(THIS_MODULE, "seq", NULL)) == NULL)
  			return -ENOMEM;
  		entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
  		if (snd_info_register(entry) < 0) {
  			snd_info_free_entry(entry);
  			return -ENOMEM;
  		}
  		snd_seq_root = entry;
  	}
  #endif
  	snd_info_version_init();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
549
550
551
552
553
554
555
  	snd_minor_info_init();
  	snd_minor_info_oss_init();
  	snd_card_info_init();
  	return 0;
  }
  
  int __exit snd_info_done(void)
  {
  	snd_card_info_done();
  	snd_minor_info_oss_done();
  	snd_minor_info_done();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556
557
  	snd_info_version_done();
  	if (snd_proc_root) {
8eeaa2f9e   Takashi Iwai   ALSA: Replace wit...
558
  #if IS_ENABLED(CONFIG_SND_SEQUENCER)
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
559
  		snd_info_free_entry(snd_seq_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
560
561
  #endif
  #ifdef CONFIG_SND_OSSEMUL
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
562
  		snd_info_free_entry(snd_oss_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  #endif
a8ca16ea7   David Howells   proc: Supply a fu...
564
  		proc_remove(snd_proc_root);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
566
567
568
569
570
571
572
573
574
575
576
577
  	}
  	return 0;
  }
  
  /*
  
   */
  
  
  /*
   * create a card proc file
   * called from init.c
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
578
  int snd_info_card_create(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
579
580
  {
  	char str[8];
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
581
  	struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582

7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
583
584
  	if (snd_BUG_ON(!card))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
  
  	sprintf(str, "card%i", card->number);
  	if ((entry = snd_info_create_module_entry(card->module, str, NULL)) == NULL)
  		return -ENOMEM;
  	entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
  	if (snd_info_register(entry) < 0) {
  		snd_info_free_entry(entry);
  		return -ENOMEM;
  	}
  	card->proc_root = entry;
  	return 0;
  }
  
  /*
   * register the card proc file
   * called from init.c
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
602
  int snd_info_card_register(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
603
604
  {
  	struct proc_dir_entry *p;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
605
606
  	if (snd_BUG_ON(!card))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
610
611
612
613
614
615
616
617
618
  
  	if (!strcmp(card->id, card->proc_root->name))
  		return 0;
  
  	p = proc_symlink(card->id, snd_proc_root, card->proc_root->name);
  	if (p == NULL)
  		return -ENOMEM;
  	card->proc_root_link = p;
  	return 0;
  }
  
  /*
c2eb9c4ea   Jaroslav Kysela   ALSA: when card i...
619
620
621
622
623
624
   * called on card->id change
   */
  void snd_info_card_id_change(struct snd_card *card)
  {
  	mutex_lock(&info_mutex);
  	if (card->proc_root_link) {
a8ca16ea7   David Howells   proc: Supply a fu...
625
  		proc_remove(card->proc_root_link);
c2eb9c4ea   Jaroslav Kysela   ALSA: when card i...
626
627
628
629
630
631
632
633
634
635
  		card->proc_root_link = NULL;
  	}
  	if (strcmp(card->id, card->proc_root->name))
  		card->proc_root_link = proc_symlink(card->id,
  						    snd_proc_root,
  						    card->proc_root->name);
  	mutex_unlock(&info_mutex);
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
   * de-register the card proc file
   * called from init.c
   */
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
639
  void snd_info_card_disconnect(struct snd_card *card)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
640
  {
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
641
642
  	if (!card)
  		return;
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
643
  	mutex_lock(&info_mutex);
a8ca16ea7   David Howells   proc: Supply a fu...
644
645
  	proc_remove(card->proc_root_link);
  	card->proc_root_link = NULL;
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
646
647
648
649
650
651
652
653
654
655
656
  	if (card->proc_root)
  		snd_info_disconnect(card->proc_root);
  	mutex_unlock(&info_mutex);
  }
  
  /*
   * release the card proc file resources
   * called from init.c
   */
  int snd_info_card_free(struct snd_card *card)
  {
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
657
658
  	if (!card)
  		return 0;
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
659
660
  	snd_info_free_entry(card->proc_root);
  	card->proc_root = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
661
662
663
664
665
666
667
668
  	return 0;
  }
  
  
  /**
   * snd_info_get_line - read one line from the procfs buffer
   * @buffer: the procfs buffer
   * @line: the buffer to store
ddc64b278   Clemens Ladisch   ALSA: core: fix b...
669
   * @len: the max. buffer size
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
671
672
   *
   * Reads one line from the buffer and stores the string.
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
673
   * Return: Zero if successful, or 1 if error or EOF.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
675
  int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
  {
  	int c = -1;
0bc0ec903   Takashi Iwai   ALSA: info: Small...
678
679
  	if (snd_BUG_ON(!buffer || !buffer->buffer))
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
681
  	if (len <= 0 || buffer->stop || buffer->error)
  		return 1;
0bc0ec903   Takashi Iwai   ALSA: info: Small...
682
  	while (!buffer->stop) {
7e4eeec8a   Takashi Iwai   [ALSA] Make buffe...
683
  		c = buffer->buffer[buffer->curr++];
0bc0ec903   Takashi Iwai   ALSA: info: Small...
684
  		if (buffer->curr >= buffer->size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  			buffer->stop = 1;
0bc0ec903   Takashi Iwai   ALSA: info: Small...
686
687
  		if (c == '
  ')
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  			break;
ddc64b278   Clemens Ladisch   ALSA: core: fix b...
689
  		if (len > 1) {
0bc0ec903   Takashi Iwai   ALSA: info: Small...
690
691
  			len--;
  			*line++ = c;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694
695
696
  	*line = '\0';
  	return 0;
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
697
  EXPORT_SYMBOL(snd_info_get_line);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
  /**
856def8a4   Henrik Kretzschmar   [ALSA] typo-fix a...
699
   * snd_info_get_str - parse a string token
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
700
701
702
703
704
705
706
   * @dest: the buffer to store the string token
   * @src: the original string
   * @len: the max. length of token - 1
   *
   * Parses the original string and copy a token to the given
   * string buffer.
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
707
   * Return: The updated pointer of the original string so that
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
   * it can be used for the next call.
   */
4f7454a99   Takashi Iwai   ALSA: Add const p...
710
  const char *snd_info_get_str(char *dest, const char *src, int len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  {
  	int c;
  
  	while (*src == ' ' || *src == '\t')
  		src++;
  	if (*src == '"' || *src == '\'') {
  		c = *src++;
  		while (--len > 0 && *src && *src != c) {
  			*dest++ = *src++;
  		}
  		if (*src == c)
  			src++;
  	} else {
  		while (--len > 0 && *src && *src != ' ' && *src != '\t') {
  			*dest++ = *src++;
  		}
  	}
  	*dest = 0;
  	while (*src == ' ' || *src == '\t')
  		src++;
  	return src;
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
733
  EXPORT_SYMBOL(snd_info_get_str);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
734
735
736
737
738
739
740
741
742
743
  /**
   * snd_info_create_entry - create an info entry
   * @name: the proc file name
   *
   * Creates an info entry with the given file name and initializes as
   * the default state.
   *
   * Usually called from other functions such as
   * snd_info_create_card_entry().
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
744
   * Return: The pointer of the new instance, or %NULL on failure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
746
  static struct snd_info_entry *snd_info_create_entry(const char *name)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
748
  	struct snd_info_entry *entry;
ca2c09665   Takashi Iwai   [ALSA] Replace wi...
749
  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  	if (entry == NULL)
  		return NULL;
543537bd9   Paulo Marques   [PATCH] create a ...
752
  	entry->name = kstrdup(name, GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
753
754
755
756
757
758
  	if (entry->name == NULL) {
  		kfree(entry);
  		return NULL;
  	}
  	entry->mode = S_IFREG | S_IRUGO;
  	entry->content = SNDRV_INFO_CONTENT_TEXT;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
759
  	mutex_init(&entry->access);
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
760
761
  	INIT_LIST_HEAD(&entry->children);
  	INIT_LIST_HEAD(&entry->list);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
763
764
765
766
767
768
769
770
771
772
  	return entry;
  }
  
  /**
   * snd_info_create_module_entry - create an info entry for the given module
   * @module: the module pointer
   * @name: the file name
   * @parent: the parent directory
   *
   * Creates a new info entry and assigns it to the given module.
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
773
   * Return: The pointer of the new instance, or %NULL on failure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
775
  struct snd_info_entry *snd_info_create_module_entry(struct module * module,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
776
  					       const char *name,
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
777
  					       struct snd_info_entry *parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
778
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
779
  	struct snd_info_entry *entry = snd_info_create_entry(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
780
781
782
783
784
785
  	if (entry) {
  		entry->module = module;
  		entry->parent = parent;
  	}
  	return entry;
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
786
  EXPORT_SYMBOL(snd_info_create_module_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
787
788
789
790
791
792
793
794
  /**
   * snd_info_create_card_entry - create an info entry for the given card
   * @card: the card instance
   * @name: the file name
   * @parent: the parent directory
   *
   * Creates a new info entry and assigns it to the given card.
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
795
   * Return: The pointer of the new instance, or %NULL on failure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
796
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
797
  struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
  					     const char *name,
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
799
  					     struct snd_info_entry * parent)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
801
  	struct snd_info_entry *entry = snd_info_create_entry(name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
804
805
806
807
808
  	if (entry) {
  		entry->module = card->module;
  		entry->card = card;
  		entry->parent = parent;
  	}
  	return entry;
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
809
  EXPORT_SYMBOL(snd_info_create_card_entry);
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
810
  static void snd_info_disconnect(struct snd_info_entry *entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
811
  {
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
812
813
  	struct list_head *p, *n;
  	struct proc_dir_entry *root;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814

746d4a02e   Takashi Iwai   [ALSA] Fix discon...
815
816
817
818
819
820
821
822
  	list_for_each_safe(p, n, &entry->children) {
  		snd_info_disconnect(list_entry(p, struct snd_info_entry, list));
  	}
  
  	if (! entry->p)
  		return;
  	list_del_init(&entry->list);
  	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
823
  	snd_BUG_ON(!root);
a8ca16ea7   David Howells   proc: Supply a fu...
824
  	proc_remove(entry->p);
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
825
  	entry->p = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  }
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
827
  static int snd_info_dev_free_entry(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
829
  	struct snd_info_entry *entry = device->device_data;
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
830
  	snd_info_free_entry(entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
832
  	return 0;
  }
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
833
  static int snd_info_dev_register_entry(struct snd_device *device)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
834
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
835
  	struct snd_info_entry *entry = device->device_data;
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
836
  	return snd_info_register(entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
  }
  
  /**
   * snd_card_proc_new - create an info entry for the given card
   * @card: the card instance
   * @name: the file name
   * @entryp: the pointer to store the new info entry
   *
   * Creates a new info entry and assigns it to the given card.
   * Unlike snd_info_create_card_entry(), this function registers the
   * info entry as an ALSA device component, so that it can be
   * unregistered/released without explicit call.
   * Also, you don't have to register this entry via snd_info_register(),
   * since this will be registered by snd_card_register() automatically.
   *
   * The parent is assumed as card->proc_root.
   *
   * For releasing this entry, use snd_device_free() instead of
   * snd_info_free_entry(). 
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
857
   * Return: Zero if successful, or a negative error code on failure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
859
860
  int snd_card_proc_new(struct snd_card *card, const char *name,
  		      struct snd_info_entry **entryp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
862
  	static struct snd_device_ops ops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
  		.dev_free = snd_info_dev_free_entry,
  		.dev_register =	snd_info_dev_register_entry,
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
865
  		/* disconnect is done via snd_info_card_disconnect() */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
  	};
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
867
  	struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
868
869
870
871
872
873
874
875
876
877
878
879
880
  	int err;
  
  	entry = snd_info_create_card_entry(card, name, card->proc_root);
  	if (! entry)
  		return -ENOMEM;
  	if ((err = snd_device_new(card, SNDRV_DEV_INFO, entry, &ops)) < 0) {
  		snd_info_free_entry(entry);
  		return err;
  	}
  	if (entryp)
  		*entryp = entry;
  	return 0;
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
881
  EXPORT_SYMBOL(snd_card_proc_new);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
882
883
884
885
886
887
  /**
   * snd_info_free_entry - release the info entry
   * @entry: the info entry
   *
   * Releases the info entry.  Don't call this after registered.
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
888
  void snd_info_free_entry(struct snd_info_entry * entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
889
890
891
  {
  	if (entry == NULL)
  		return;
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
892
893
894
895
896
  	if (entry->p) {
  		mutex_lock(&info_mutex);
  		snd_info_disconnect(entry);
  		mutex_unlock(&info_mutex);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
897
898
899
900
901
  	kfree(entry->name);
  	if (entry->private_free)
  		entry->private_free(entry);
  	kfree(entry);
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
902
  EXPORT_SYMBOL(snd_info_free_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
904
905
906
907
908
  /**
   * snd_info_register - register the info entry
   * @entry: the info entry
   *
   * Registers the proc info entry.
   *
eb7c06e8e   Yacine Belkadi   ALSA: add/change ...
909
   * Return: Zero if successful, or a negative error code on failure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
   */
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
911
  int snd_info_register(struct snd_info_entry * entry)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
912
913
  {
  	struct proc_dir_entry *root, *p = NULL;
7eaa943c8   Takashi Iwai   ALSA: Kill snd_as...
914
915
  	if (snd_BUG_ON(!entry))
  		return -ENXIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
916
  	root = entry->parent == NULL ? snd_proc_root : entry->parent->p;
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
917
  	mutex_lock(&info_mutex);
aee0c612b   Al Viro   snd_info_register...
918
919
920
921
922
923
924
925
926
927
928
929
930
  	if (S_ISDIR(entry->mode)) {
  		p = proc_mkdir_mode(entry->name, entry->mode, root);
  		if (!p) {
  			mutex_unlock(&info_mutex);
  			return -ENOMEM;
  		}
  	} else {
  		p = proc_create_data(entry->name, entry->mode, root,
  					&snd_info_entry_operations, entry);
  		if (!p) {
  			mutex_unlock(&info_mutex);
  			return -ENOMEM;
  		}
271a15eab   David Howells   proc: Supply PDE ...
931
  		proc_set_size(p, entry->size);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
932
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
933
  	entry->p = p;
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
934
935
  	if (entry->parent)
  		list_add_tail(&entry->list, &entry->parent->children);
1a60d4c5a   Ingo Molnar   [ALSA] semaphore ...
936
  	mutex_unlock(&info_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
937
938
  	return 0;
  }
c0d3fb39e   Takashi Iwai   [ALSA] Clean up E...
939
  EXPORT_SYMBOL(snd_info_register);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
940
941
942
  /*
  
   */
6581f4e74   Takashi Iwai   [ALSA] Remove zer...
943
  static struct snd_info_entry *snd_info_version_entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
944

24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
945
  static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
947
  {
  	snd_iprintf(buffer,
426627483   Jaroslav Kysela   ALSA: remove the ...
948
949
950
  		    "Advanced Linux Sound Architecture Driver Version k%s.
  ",
  		    init_utsname()->release);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
951
952
953
954
  }
  
  static int __init snd_info_version_init(void)
  {
24c1f9318   Takashi Iwai   [ALSA] Remove xxx...
955
  	struct snd_info_entry *entry;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
956
957
958
959
  
  	entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
  	if (entry == NULL)
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
960
961
962
963
964
965
966
967
968
969
970
  	entry->c.text.read = snd_info_version_read;
  	if (snd_info_register(entry) < 0) {
  		snd_info_free_entry(entry);
  		return -ENOMEM;
  	}
  	snd_info_version_entry = entry;
  	return 0;
  }
  
  static int __exit snd_info_version_done(void)
  {
746d4a02e   Takashi Iwai   [ALSA] Fix discon...
971
  	snd_info_free_entry(snd_info_version_entry);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
972
973
974
975
  	return 0;
  }
  
  #endif /* CONFIG_PROC_FS */