• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   *  Information interface for ALSA driver
3   *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
4   *
5   *
6   *   This program is free software; you can redistribute it and/or modify
7   *   it under the terms of the GNU General Public License as published by
8   *   the Free Software Foundation; either version 2 of the License, or
9   *   (at your option) any later version.
10   *
11   *   This program is distributed in the hope that it will be useful,
12   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   *   GNU General Public License for more details.
15   *
16   *   You should have received a copy of the GNU General Public License
17   *   along with this program; if not, write to the Free Software
18   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19   *
20   */
21  
22  #include <linux/init.h>
23  #include <linux/time.h>
24  #include <linux/mm.h>
25  #include <linux/slab.h>
26  #include <linux/string.h>
27  #include <linux/module.h>
28  #include <sound/core.h>
29  #include <sound/minors.h>
30  #include <sound/info.h>
31  #include <linux/utsname.h>
32  #include <linux/proc_fs.h>
33  #include <linux/mutex.h>
34  #include <stdarg.h>
35  
snd_info_check_reserved_words(const char * str)36  int snd_info_check_reserved_words(const char *str)
37  {
38  	static char *reserved[] =
39  	{
40  		"version",
41  		"meminfo",
42  		"memdebug",
43  		"detect",
44  		"devices",
45  		"oss",
46  		"cards",
47  		"timers",
48  		"synth",
49  		"pcm",
50  		"seq",
51  		NULL
52  	};
53  	char **xstr = reserved;
54  
55  	while (*xstr) {
56  		if (!strcmp(*xstr, str))
57  			return 0;
58  		xstr++;
59  	}
60  	if (!strncmp(str, "card", 4))
61  		return 0;
62  	return 1;
63  }
64  
65  static DEFINE_MUTEX(info_mutex);
66  
67  struct snd_info_private_data {
68  	struct snd_info_buffer *rbuffer;
69  	struct snd_info_buffer *wbuffer;
70  	struct snd_info_entry *entry;
71  	void *file_private_data;
72  };
73  
74  static int snd_info_version_init(void);
75  static void snd_info_disconnect(struct snd_info_entry *entry);
76  
77  /*
78  
79   */
80  
81  static struct snd_info_entry *snd_proc_root;
82  struct snd_info_entry *snd_seq_root;
83  EXPORT_SYMBOL(snd_seq_root);
84  
85  #ifdef CONFIG_SND_OSSEMUL
86  struct snd_info_entry *snd_oss_root;
87  #endif
88  
alloc_info_private(struct snd_info_entry * entry,struct snd_info_private_data ** ret)89  static int alloc_info_private(struct snd_info_entry *entry,
90  			      struct snd_info_private_data **ret)
91  {
92  	struct snd_info_private_data *data;
93  
94  	if (!entry || !entry->p)
95  		return -ENODEV;
96  	if (!try_module_get(entry->module))
97  		return -EFAULT;
98  	data = kzalloc(sizeof(*data), GFP_KERNEL);
99  	if (!data) {
100  		module_put(entry->module);
101  		return -ENOMEM;
102  	}
103  	data->entry = entry;
104  	*ret = data;
105  	return 0;
106  }
107  
valid_pos(loff_t pos,size_t count)108  static bool valid_pos(loff_t pos, size_t count)
109  {
110  	if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
111  		return false;
112  	if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
113  		return false;
114  	return true;
115  }
116  
117  /*
118   * file ops for binary proc files
119   */
snd_info_entry_llseek(struct file * file,loff_t offset,int orig)120  static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
121  {
122  	struct snd_info_private_data *data;
123  	struct snd_info_entry *entry;
124  	loff_t ret = -EINVAL, size;
125  
126  	data = file->private_data;
127  	entry = data->entry;
128  	mutex_lock(&entry->access);
129  	if (entry->c.ops->llseek) {
130  		offset = entry->c.ops->llseek(entry,
131  					      data->file_private_data,
132  					      file, offset, orig);
133  		goto out;
134  	}
135  
136  	size = entry->size;
137  	switch (orig) {
138  	case SEEK_SET:
139  		break;
140  	case SEEK_CUR:
141  		offset += file->f_pos;
142  		break;
143  	case SEEK_END:
144  		if (!size)
145  			goto out;
146  		offset += size;
147  		break;
148  	default:
149  		goto out;
150  	}
151  	if (offset < 0)
152  		goto out;
153  	if (size && offset > size)
154  		offset = size;
155  	file->f_pos = offset;
156  	ret = offset;
157   out:
158  	mutex_unlock(&entry->access);
159  	return ret;
160  }
161  
snd_info_entry_read(struct file * file,char __user * buffer,size_t count,loff_t * offset)162  static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
163  				   size_t count, loff_t * offset)
164  {
165  	struct snd_info_private_data *data = file->private_data;
166  	struct snd_info_entry *entry = data->entry;
167  	size_t size;
168  	loff_t pos;
169  
170  	pos = *offset;
171  	if (!valid_pos(pos, count))
172  		return -EIO;
173  	if (pos >= entry->size)
174  		return 0;
175  	size = entry->size - pos;
176  	size = min(count, size);
177  	size = entry->c.ops->read(entry, data->file_private_data,
178  				  file, buffer, size, pos);
179  	if ((ssize_t) size > 0)
180  		*offset = pos + size;
181  	return size;
182  }
183  
snd_info_entry_write(struct file * file,const char __user * buffer,size_t count,loff_t * offset)184  static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
185  				    size_t count, loff_t * offset)
186  {
187  	struct snd_info_private_data *data = file->private_data;
188  	struct snd_info_entry *entry = data->entry;
189  	ssize_t size = 0;
190  	loff_t pos;
191  
192  	pos = *offset;
193  	if (!valid_pos(pos, count))
194  		return -EIO;
195  	if (count > 0) {
196  		size_t maxsize = entry->size - pos;
197  		count = min(count, maxsize);
198  		size = entry->c.ops->write(entry, data->file_private_data,
199  					   file, buffer, count, pos);
200  	}
201  	if (size > 0)
202  		*offset = pos + size;
203  	return size;
204  }
205  
snd_info_entry_poll(struct file * file,poll_table * wait)206  static unsigned int snd_info_entry_poll(struct file *file, poll_table *wait)
207  {
208  	struct snd_info_private_data *data = file->private_data;
209  	struct snd_info_entry *entry = data->entry;
210  	unsigned int mask = 0;
211  
212  	if (entry->c.ops->poll)
213  		return entry->c.ops->poll(entry,
214  					  data->file_private_data,
215  					  file, wait);
216  	if (entry->c.ops->read)
217  		mask |= POLLIN | POLLRDNORM;
218  	if (entry->c.ops->write)
219  		mask |= POLLOUT | POLLWRNORM;
220  	return mask;
221  }
222  
snd_info_entry_ioctl(struct file * file,unsigned int cmd,unsigned long arg)223  static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,
224  				unsigned long arg)
225  {
226  	struct snd_info_private_data *data = file->private_data;
227  	struct snd_info_entry *entry = data->entry;
228  
229  	if (!entry->c.ops->ioctl)
230  		return -ENOTTY;
231  	return entry->c.ops->ioctl(entry, data->file_private_data,
232  				   file, cmd, arg);
233  }
234  
snd_info_entry_mmap(struct file * file,struct vm_area_struct * vma)235  static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
236  {
237  	struct inode *inode = file_inode(file);
238  	struct snd_info_private_data *data;
239  	struct snd_info_entry *entry;
240  
241  	data = file->private_data;
242  	if (data == NULL)
243  		return 0;
244  	entry = data->entry;
245  	if (!entry->c.ops->mmap)
246  		return -ENXIO;
247  	return entry->c.ops->mmap(entry, data->file_private_data,
248  				  inode, file, vma);
249  }
250  
snd_info_entry_open(struct inode * inode,struct file * file)251  static int snd_info_entry_open(struct inode *inode, struct file *file)
252  {
253  	struct snd_info_entry *entry = PDE_DATA(inode);
254  	struct snd_info_private_data *data;
255  	int mode, err;
256  
257  	mutex_lock(&info_mutex);
258  	err = alloc_info_private(entry, &data);
259  	if (err < 0)
260  		goto unlock;
261  
262  	mode = file->f_flags & O_ACCMODE;
263  	if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
264  	    ((mode == O_WRONLY || mode == O_RDWR) && !entry->c.ops->write)) {
265  		err = -ENODEV;
266  		goto error;
267  	}
268  
269  	if (entry->c.ops->open) {
270  		err = entry->c.ops->open(entry, mode, &data->file_private_data);
271  		if (err < 0)
272  			goto error;
273  	}
274  
275  	file->private_data = data;
276  	mutex_unlock(&info_mutex);
277  	return 0;
278  
279   error:
280  	kfree(data);
281  	module_put(entry->module);
282   unlock:
283  	mutex_unlock(&info_mutex);
284  	return err;
285  }
286  
snd_info_entry_release(struct inode * inode,struct file * file)287  static int snd_info_entry_release(struct inode *inode, struct file *file)
288  {
289  	struct snd_info_private_data *data = file->private_data;
290  	struct snd_info_entry *entry = data->entry;
291  
292  	if (entry->c.ops->release)
293  		entry->c.ops->release(entry, file->f_flags & O_ACCMODE,
294  				      data->file_private_data);
295  	module_put(entry->module);
296  	kfree(data);
297  	return 0;
298  }
299  
300  static const struct file_operations snd_info_entry_operations =
301  {
302  	.owner =		THIS_MODULE,
303  	.llseek =		snd_info_entry_llseek,
304  	.read =			snd_info_entry_read,
305  	.write =		snd_info_entry_write,
306  	.poll =			snd_info_entry_poll,
307  	.unlocked_ioctl =	snd_info_entry_ioctl,
308  	.mmap =			snd_info_entry_mmap,
309  	.open =			snd_info_entry_open,
310  	.release =		snd_info_entry_release,
311  };
312  
313  /*
314   * file ops for text proc files
315   */
snd_info_text_entry_write(struct file * file,const char __user * buffer,size_t count,loff_t * offset)316  static ssize_t snd_info_text_entry_write(struct file *file,
317  					 const char __user *buffer,
318  					 size_t count, loff_t *offset)
319  {
320  	struct seq_file *m = file->private_data;
321  	struct snd_info_private_data *data = m->private;
322  	struct snd_info_entry *entry = data->entry;
323  	struct snd_info_buffer *buf;
324  	loff_t pos;
325  	size_t next;
326  	int err = 0;
327  
328  	if (!entry->c.text.write)
329  		return -EIO;
330  	pos = *offset;
331  	if (!valid_pos(pos, count))
332  		return -EIO;
333  	next = pos + count;
334  	/* don't handle too large text inputs */
335  	if (next > 16 * 1024)
336  		return -EIO;
337  	mutex_lock(&entry->access);
338  	buf = data->wbuffer;
339  	if (!buf) {
340  		data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
341  		if (!buf) {
342  			err = -ENOMEM;
343  			goto error;
344  		}
345  	}
346  	if (next > buf->len) {
347  		char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
348  		if (!nbuf) {
349  			err = -ENOMEM;
350  			goto error;
351  		}
352  		kvfree(buf->buffer);
353  		buf->buffer = nbuf;
354  		buf->len = PAGE_ALIGN(next);
355  	}
356  	if (copy_from_user(buf->buffer + pos, buffer, count)) {
357  		err = -EFAULT;
358  		goto error;
359  	}
360  	buf->size = next;
361   error:
362  	mutex_unlock(&entry->access);
363  	if (err < 0)
364  		return err;
365  	*offset = next;
366  	return count;
367  }
368  
snd_info_seq_show(struct seq_file * seq,void * p)369  static int snd_info_seq_show(struct seq_file *seq, void *p)
370  {
371  	struct snd_info_private_data *data = seq->private;
372  	struct snd_info_entry *entry = data->entry;
373  
374  	if (!entry->c.text.read) {
375  		return -EIO;
376  	} else {
377  		data->rbuffer->buffer = (char *)seq; /* XXX hack! */
378  		entry->c.text.read(entry, data->rbuffer);
379  	}
380  	return 0;
381  }
382  
snd_info_text_entry_open(struct inode * inode,struct file * file)383  static int snd_info_text_entry_open(struct inode *inode, struct file *file)
384  {
385  	struct snd_info_entry *entry = PDE_DATA(inode);
386  	struct snd_info_private_data *data;
387  	int err;
388  
389  	mutex_lock(&info_mutex);
390  	err = alloc_info_private(entry, &data);
391  	if (err < 0)
392  		goto unlock;
393  
394  	data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
395  	if (!data->rbuffer) {
396  		err = -ENOMEM;
397  		goto error;
398  	}
399  	if (entry->size)
400  		err = single_open_size(file, snd_info_seq_show, data,
401  				       entry->size);
402  	else
403  		err = single_open(file, snd_info_seq_show, data);
404  	if (err < 0)
405  		goto error;
406  	mutex_unlock(&info_mutex);
407  	return 0;
408  
409   error:
410  	kfree(data->rbuffer);
411  	kfree(data);
412  	module_put(entry->module);
413   unlock:
414  	mutex_unlock(&info_mutex);
415  	return err;
416  }
417  
snd_info_text_entry_release(struct inode * inode,struct file * file)418  static int snd_info_text_entry_release(struct inode *inode, struct file *file)
419  {
420  	struct seq_file *m = file->private_data;
421  	struct snd_info_private_data *data = m->private;
422  	struct snd_info_entry *entry = data->entry;
423  
424  	if (data->wbuffer && entry->c.text.write)
425  		entry->c.text.write(entry, data->wbuffer);
426  
427  	single_release(inode, file);
428  	kfree(data->rbuffer);
429  	if (data->wbuffer) {
430  		kvfree(data->wbuffer->buffer);
431  		kfree(data->wbuffer);
432  	}
433  
434  	module_put(entry->module);
435  	kfree(data);
436  	return 0;
437  }
438  
439  static const struct file_operations snd_info_text_entry_ops =
440  {
441  	.owner =		THIS_MODULE,
442  	.open =			snd_info_text_entry_open,
443  	.release =		snd_info_text_entry_release,
444  	.write =		snd_info_text_entry_write,
445  	.llseek =		seq_lseek,
446  	.read =			seq_read,
447  };
448  
create_subdir(struct module * mod,const char * name)449  static struct snd_info_entry *create_subdir(struct module *mod,
450  					    const char *name)
451  {
452  	struct snd_info_entry *entry;
453  
454  	entry = snd_info_create_module_entry(mod, name, NULL);
455  	if (!entry)
456  		return NULL;
457  	entry->mode = S_IFDIR | S_IRUGO | S_IXUGO;
458  	if (snd_info_register(entry) < 0) {
459  		snd_info_free_entry(entry);
460  		return NULL;
461  	}
462  	return entry;
463  }
464  
465  static struct snd_info_entry *
466  snd_info_create_entry(const char *name, struct snd_info_entry *parent);
467  
snd_info_init(void)468  int __init snd_info_init(void)
469  {
470  	snd_proc_root = snd_info_create_entry("asound", NULL);
471  	if (!snd_proc_root)
472  		return -ENOMEM;
473  	snd_proc_root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
474  	snd_proc_root->p = proc_mkdir("asound", NULL);
475  	if (!snd_proc_root->p)
476  		goto error;
477  #ifdef CONFIG_SND_OSSEMUL
478  	snd_oss_root = create_subdir(THIS_MODULE, "oss");
479  	if (!snd_oss_root)
480  		goto error;
481  #endif
482  #if IS_ENABLED(CONFIG_SND_SEQUENCER)
483  	snd_seq_root = create_subdir(THIS_MODULE, "seq");
484  	if (!snd_seq_root)
485  		goto error;
486  #endif
487  	if (snd_info_version_init() < 0 ||
488  	    snd_minor_info_init() < 0 ||
489  	    snd_minor_info_oss_init() < 0 ||
490  	    snd_card_info_init() < 0 ||
491  	    snd_info_minor_register() < 0)
492  		goto error;
493  	return 0;
494  
495   error:
496  	snd_info_free_entry(snd_proc_root);
497  	return -ENOMEM;
498  }
499  
snd_info_done(void)500  int __exit snd_info_done(void)
501  {
502  	snd_info_free_entry(snd_proc_root);
503  	return 0;
504  }
505  
506  /*
507   * create a card proc file
508   * called from init.c
509   */
snd_info_card_create(struct snd_card * card)510  int snd_info_card_create(struct snd_card *card)
511  {
512  	char str[8];
513  	struct snd_info_entry *entry;
514  
515  	if (snd_BUG_ON(!card))
516  		return -ENXIO;
517  
518  	sprintf(str, "card%i", card->number);
519  	entry = create_subdir(card->module, str);
520  	if (!entry)
521  		return -ENOMEM;
522  	card->proc_root = entry;
523  	return 0;
524  }
525  
526  /* register all pending info entries */
snd_info_register_recursive(struct snd_info_entry * entry)527  static int snd_info_register_recursive(struct snd_info_entry *entry)
528  {
529  	struct snd_info_entry *p;
530  	int err;
531  
532  	if (!entry->p) {
533  		err = snd_info_register(entry);
534  		if (err < 0)
535  			return err;
536  	}
537  
538  	list_for_each_entry(p, &entry->children, list) {
539  		err = snd_info_register_recursive(p);
540  		if (err < 0)
541  			return err;
542  	}
543  
544  	return 0;
545  }
546  
547  /*
548   * register the card proc file
549   * called from init.c
550   * can be called multiple times for reinitialization
551   */
snd_info_card_register(struct snd_card * card)552  int snd_info_card_register(struct snd_card *card)
553  {
554  	struct proc_dir_entry *p;
555  	int err;
556  
557  	if (snd_BUG_ON(!card))
558  		return -ENXIO;
559  
560  	err = snd_info_register_recursive(card->proc_root);
561  	if (err < 0)
562  		return err;
563  
564  	if (!strcmp(card->id, card->proc_root->name))
565  		return 0;
566  
567  	if (card->proc_root_link)
568  		return 0;
569  	p = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name);
570  	if (!p)
571  		return -ENOMEM;
572  	card->proc_root_link = p;
573  	return 0;
574  }
575  
576  /*
577   * called on card->id change
578   */
snd_info_card_id_change(struct snd_card * card)579  void snd_info_card_id_change(struct snd_card *card)
580  {
581  	mutex_lock(&info_mutex);
582  	if (card->proc_root_link) {
583  		proc_remove(card->proc_root_link);
584  		card->proc_root_link = NULL;
585  	}
586  	if (strcmp(card->id, card->proc_root->name))
587  		card->proc_root_link = proc_symlink(card->id,
588  						    snd_proc_root->p,
589  						    card->proc_root->name);
590  	mutex_unlock(&info_mutex);
591  }
592  
593  /*
594   * de-register the card proc file
595   * called from init.c
596   */
snd_info_card_disconnect(struct snd_card * card)597  void snd_info_card_disconnect(struct snd_card *card)
598  {
599  	if (!card)
600  		return;
601  	mutex_lock(&info_mutex);
602  	proc_remove(card->proc_root_link);
603  	card->proc_root_link = NULL;
604  	if (card->proc_root)
605  		snd_info_disconnect(card->proc_root);
606  	mutex_unlock(&info_mutex);
607  }
608  
609  /*
610   * release the card proc file resources
611   * called from init.c
612   */
snd_info_card_free(struct snd_card * card)613  int snd_info_card_free(struct snd_card *card)
614  {
615  	if (!card)
616  		return 0;
617  	snd_info_free_entry(card->proc_root);
618  	card->proc_root = NULL;
619  	return 0;
620  }
621  
622  
623  /**
624   * snd_info_get_line - read one line from the procfs buffer
625   * @buffer: the procfs buffer
626   * @line: the buffer to store
627   * @len: the max. buffer size
628   *
629   * Reads one line from the buffer and stores the string.
630   *
631   * Return: Zero if successful, or 1 if error or EOF.
632   */
snd_info_get_line(struct snd_info_buffer * buffer,char * line,int len)633  int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
634  {
635  	int c = -1;
636  
637  	if (snd_BUG_ON(!buffer || !buffer->buffer))
638  		return 1;
639  	if (len <= 0 || buffer->stop || buffer->error)
640  		return 1;
641  	while (!buffer->stop) {
642  		c = buffer->buffer[buffer->curr++];
643  		if (buffer->curr >= buffer->size)
644  			buffer->stop = 1;
645  		if (c == '\n')
646  			break;
647  		if (len > 1) {
648  			len--;
649  			*line++ = c;
650  		}
651  	}
652  	*line = '\0';
653  	return 0;
654  }
655  EXPORT_SYMBOL(snd_info_get_line);
656  
657  /**
658   * snd_info_get_str - parse a string token
659   * @dest: the buffer to store the string token
660   * @src: the original string
661   * @len: the max. length of token - 1
662   *
663   * Parses the original string and copy a token to the given
664   * string buffer.
665   *
666   * Return: The updated pointer of the original string so that
667   * it can be used for the next call.
668   */
snd_info_get_str(char * dest,const char * src,int len)669  const char *snd_info_get_str(char *dest, const char *src, int len)
670  {
671  	int c;
672  
673  	while (*src == ' ' || *src == '\t')
674  		src++;
675  	if (*src == '"' || *src == '\'') {
676  		c = *src++;
677  		while (--len > 0 && *src && *src != c) {
678  			*dest++ = *src++;
679  		}
680  		if (*src == c)
681  			src++;
682  	} else {
683  		while (--len > 0 && *src && *src != ' ' && *src != '\t') {
684  			*dest++ = *src++;
685  		}
686  	}
687  	*dest = 0;
688  	while (*src == ' ' || *src == '\t')
689  		src++;
690  	return src;
691  }
692  EXPORT_SYMBOL(snd_info_get_str);
693  
694  /*
695   * snd_info_create_entry - create an info entry
696   * @name: the proc file name
697   * @parent: the parent directory
698   *
699   * Creates an info entry with the given file name and initializes as
700   * the default state.
701   *
702   * Usually called from other functions such as
703   * snd_info_create_card_entry().
704   *
705   * Return: The pointer of the new instance, or %NULL on failure.
706   */
707  static struct snd_info_entry *
snd_info_create_entry(const char * name,struct snd_info_entry * parent)708  snd_info_create_entry(const char *name, struct snd_info_entry *parent)
709  {
710  	struct snd_info_entry *entry;
711  	entry = kzalloc(sizeof(*entry), GFP_KERNEL);
712  	if (entry == NULL)
713  		return NULL;
714  	entry->name = kstrdup(name, GFP_KERNEL);
715  	if (entry->name == NULL) {
716  		kfree(entry);
717  		return NULL;
718  	}
719  	entry->mode = S_IFREG | S_IRUGO;
720  	entry->content = SNDRV_INFO_CONTENT_TEXT;
721  	mutex_init(&entry->access);
722  	INIT_LIST_HEAD(&entry->children);
723  	INIT_LIST_HEAD(&entry->list);
724  	entry->parent = parent;
725  	if (parent) {
726  		mutex_lock(&parent->access);
727  		list_add_tail(&entry->list, &parent->children);
728  		mutex_unlock(&parent->access);
729  	}
730  	return entry;
731  }
732  
733  /**
734   * snd_info_create_module_entry - create an info entry for the given module
735   * @module: the module pointer
736   * @name: the file name
737   * @parent: the parent directory
738   *
739   * Creates a new info entry and assigns it to the given module.
740   *
741   * Return: The pointer of the new instance, or %NULL on failure.
742   */
snd_info_create_module_entry(struct module * module,const char * name,struct snd_info_entry * parent)743  struct snd_info_entry *snd_info_create_module_entry(struct module * module,
744  					       const char *name,
745  					       struct snd_info_entry *parent)
746  {
747  	struct snd_info_entry *entry = snd_info_create_entry(name, parent);
748  	if (entry)
749  		entry->module = module;
750  	return entry;
751  }
752  EXPORT_SYMBOL(snd_info_create_module_entry);
753  
754  /**
755   * snd_info_create_card_entry - create an info entry for the given card
756   * @card: the card instance
757   * @name: the file name
758   * @parent: the parent directory
759   *
760   * Creates a new info entry and assigns it to the given card.
761   *
762   * Return: The pointer of the new instance, or %NULL on failure.
763   */
snd_info_create_card_entry(struct snd_card * card,const char * name,struct snd_info_entry * parent)764  struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
765  					     const char *name,
766  					     struct snd_info_entry * parent)
767  {
768  	struct snd_info_entry *entry = snd_info_create_entry(name, parent);
769  	if (entry) {
770  		entry->module = card->module;
771  		entry->card = card;
772  	}
773  	return entry;
774  }
775  EXPORT_SYMBOL(snd_info_create_card_entry);
776  
snd_info_disconnect(struct snd_info_entry * entry)777  static void snd_info_disconnect(struct snd_info_entry *entry)
778  {
779  	struct snd_info_entry *p;
780  
781  	if (!entry->p)
782  		return;
783  	list_for_each_entry(p, &entry->children, list)
784  		snd_info_disconnect(p);
785  	proc_remove(entry->p);
786  	entry->p = NULL;
787  }
788  
789  /**
790   * snd_info_free_entry - release the info entry
791   * @entry: the info entry
792   *
793   * Releases the info entry.
794   */
snd_info_free_entry(struct snd_info_entry * entry)795  void snd_info_free_entry(struct snd_info_entry * entry)
796  {
797  	struct snd_info_entry *p, *n;
798  
799  	if (!entry)
800  		return;
801  	if (entry->p) {
802  		mutex_lock(&info_mutex);
803  		snd_info_disconnect(entry);
804  		mutex_unlock(&info_mutex);
805  	}
806  
807  	/* free all children at first */
808  	list_for_each_entry_safe(p, n, &entry->children, list)
809  		snd_info_free_entry(p);
810  
811  	p = entry->parent;
812  	if (p) {
813  		mutex_lock(&p->access);
814  		list_del(&entry->list);
815  		mutex_unlock(&p->access);
816  	}
817  	kfree(entry->name);
818  	if (entry->private_free)
819  		entry->private_free(entry);
820  	kfree(entry);
821  }
822  EXPORT_SYMBOL(snd_info_free_entry);
823  
824  /**
825   * snd_info_register - register the info entry
826   * @entry: the info entry
827   *
828   * Registers the proc info entry.
829   *
830   * Return: Zero if successful, or a negative error code on failure.
831   */
snd_info_register(struct snd_info_entry * entry)832  int snd_info_register(struct snd_info_entry * entry)
833  {
834  	struct proc_dir_entry *root, *p = NULL;
835  
836  	if (snd_BUG_ON(!entry))
837  		return -ENXIO;
838  	root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p;
839  	mutex_lock(&info_mutex);
840  	if (S_ISDIR(entry->mode)) {
841  		p = proc_mkdir_mode(entry->name, entry->mode, root);
842  		if (!p) {
843  			mutex_unlock(&info_mutex);
844  			return -ENOMEM;
845  		}
846  	} else {
847  		const struct file_operations *ops;
848  		if (entry->content == SNDRV_INFO_CONTENT_DATA)
849  			ops = &snd_info_entry_operations;
850  		else
851  			ops = &snd_info_text_entry_ops;
852  		p = proc_create_data(entry->name, entry->mode, root,
853  				     ops, entry);
854  		if (!p) {
855  			mutex_unlock(&info_mutex);
856  			return -ENOMEM;
857  		}
858  		proc_set_size(p, entry->size);
859  	}
860  	entry->p = p;
861  	mutex_unlock(&info_mutex);
862  	return 0;
863  }
864  EXPORT_SYMBOL(snd_info_register);
865  
866  /*
867  
868   */
869  
snd_info_version_read(struct snd_info_entry * entry,struct snd_info_buffer * buffer)870  static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
871  {
872  	snd_iprintf(buffer,
873  		    "Advanced Linux Sound Architecture Driver Version k%s.\n",
874  		    init_utsname()->release);
875  }
876  
snd_info_version_init(void)877  static int __init snd_info_version_init(void)
878  {
879  	struct snd_info_entry *entry;
880  
881  	entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
882  	if (entry == NULL)
883  		return -ENOMEM;
884  	entry->c.text.read = snd_info_version_read;
885  	return snd_info_register(entry); /* freed in error path */
886  }
887