cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

info.c (20714B)


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