Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  Information interface for ALSA driver
0004  *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
0005  */
0006 
0007 #include <linux/init.h>
0008 #include <linux/time.h>
0009 #include <linux/mm.h>
0010 #include <linux/slab.h>
0011 #include <linux/string.h>
0012 #include <linux/module.h>
0013 #include <sound/core.h>
0014 #include <sound/minors.h>
0015 #include <sound/info.h>
0016 #include <linux/utsname.h>
0017 #include <linux/proc_fs.h>
0018 #include <linux/mutex.h>
0019 
0020 int snd_info_check_reserved_words(const char *str)
0021 {
0022     static const char * const reserved[] =
0023     {
0024         "version",
0025         "meminfo",
0026         "memdebug",
0027         "detect",
0028         "devices",
0029         "oss",
0030         "cards",
0031         "timers",
0032         "synth",
0033         "pcm",
0034         "seq",
0035         NULL
0036     };
0037     const char * const *xstr = reserved;
0038 
0039     while (*xstr) {
0040         if (!strcmp(*xstr, str))
0041             return 0;
0042         xstr++;
0043     }
0044     if (!strncmp(str, "card", 4))
0045         return 0;
0046     return 1;
0047 }
0048 
0049 static DEFINE_MUTEX(info_mutex);
0050 
0051 struct snd_info_private_data {
0052     struct snd_info_buffer *rbuffer;
0053     struct snd_info_buffer *wbuffer;
0054     struct snd_info_entry *entry;
0055     void *file_private_data;
0056 };
0057 
0058 static int snd_info_version_init(void);
0059 static void snd_info_disconnect(struct snd_info_entry *entry);
0060 
0061 /*
0062 
0063  */
0064 
0065 static struct snd_info_entry *snd_proc_root;
0066 struct snd_info_entry *snd_seq_root;
0067 EXPORT_SYMBOL(snd_seq_root);
0068 
0069 #ifdef CONFIG_SND_OSSEMUL
0070 struct snd_info_entry *snd_oss_root;
0071 #endif
0072 
0073 static int alloc_info_private(struct snd_info_entry *entry,
0074                   struct snd_info_private_data **ret)
0075 {
0076     struct snd_info_private_data *data;
0077 
0078     if (!entry || !entry->p)
0079         return -ENODEV;
0080     if (!try_module_get(entry->module))
0081         return -EFAULT;
0082     data = kzalloc(sizeof(*data), GFP_KERNEL);
0083     if (!data) {
0084         module_put(entry->module);
0085         return -ENOMEM;
0086     }
0087     data->entry = entry;
0088     *ret = data;
0089     return 0;
0090 }
0091 
0092 static bool valid_pos(loff_t pos, size_t count)
0093 {
0094     if (pos < 0 || (long) pos != pos || (ssize_t) count < 0)
0095         return false;
0096     if ((unsigned long) pos + (unsigned long) count < (unsigned long) pos)
0097         return false;
0098     return true;
0099 }
0100 
0101 /*
0102  * file ops for binary proc files
0103  */
0104 static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig)
0105 {
0106     struct snd_info_private_data *data;
0107     struct snd_info_entry *entry;
0108     loff_t ret = -EINVAL, size;
0109 
0110     data = file->private_data;
0111     entry = data->entry;
0112     mutex_lock(&entry->access);
0113     if (entry->c.ops->llseek) {
0114         ret = entry->c.ops->llseek(entry,
0115                        data->file_private_data,
0116                        file, offset, orig);
0117         goto out;
0118     }
0119 
0120     size = entry->size;
0121     switch (orig) {
0122     case SEEK_SET:
0123         break;
0124     case SEEK_CUR:
0125         offset += file->f_pos;
0126         break;
0127     case SEEK_END:
0128         if (!size)
0129             goto out;
0130         offset += size;
0131         break;
0132     default:
0133         goto out;
0134     }
0135     if (offset < 0)
0136         goto out;
0137     if (size && offset > size)
0138         offset = size;
0139     file->f_pos = offset;
0140     ret = offset;
0141  out:
0142     mutex_unlock(&entry->access);
0143     return ret;
0144 }
0145 
0146 static ssize_t snd_info_entry_read(struct file *file, char __user *buffer,
0147                    size_t count, loff_t * offset)
0148 {
0149     struct snd_info_private_data *data = file->private_data;
0150     struct snd_info_entry *entry = data->entry;
0151     size_t size;
0152     loff_t pos;
0153 
0154     pos = *offset;
0155     if (!valid_pos(pos, count))
0156         return -EIO;
0157     if (pos >= entry->size)
0158         return 0;
0159     size = entry->size - pos;
0160     size = min(count, size);
0161     size = entry->c.ops->read(entry, data->file_private_data,
0162                   file, buffer, size, pos);
0163     if ((ssize_t) size > 0)
0164         *offset = pos + size;
0165     return size;
0166 }
0167 
0168 static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer,
0169                     size_t count, loff_t * offset)
0170 {
0171     struct snd_info_private_data *data = file->private_data;
0172     struct snd_info_entry *entry = data->entry;
0173     ssize_t size = 0;
0174     loff_t pos;
0175 
0176     pos = *offset;
0177     if (!valid_pos(pos, count))
0178         return -EIO;
0179     if (count > 0) {
0180         size_t maxsize = entry->size - pos;
0181         count = min(count, maxsize);
0182         size = entry->c.ops->write(entry, data->file_private_data,
0183                        file, buffer, count, pos);
0184     }
0185     if (size > 0)
0186         *offset = pos + size;
0187     return size;
0188 }
0189 
0190 static __poll_t snd_info_entry_poll(struct file *file, poll_table *wait)
0191 {
0192     struct snd_info_private_data *data = file->private_data;
0193     struct snd_info_entry *entry = data->entry;
0194     __poll_t mask = 0;
0195 
0196     if (entry->c.ops->poll)
0197         return entry->c.ops->poll(entry,
0198                       data->file_private_data,
0199                       file, wait);
0200     if (entry->c.ops->read)
0201         mask |= EPOLLIN | EPOLLRDNORM;
0202     if (entry->c.ops->write)
0203         mask |= EPOLLOUT | EPOLLWRNORM;
0204     return mask;
0205 }
0206 
0207 static long snd_info_entry_ioctl(struct file *file, unsigned int cmd,
0208                 unsigned long arg)
0209 {
0210     struct snd_info_private_data *data = file->private_data;
0211     struct snd_info_entry *entry = data->entry;
0212 
0213     if (!entry->c.ops->ioctl)
0214         return -ENOTTY;
0215     return entry->c.ops->ioctl(entry, data->file_private_data,
0216                    file, cmd, arg);
0217 }
0218 
0219 static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma)
0220 {
0221     struct inode *inode = file_inode(file);
0222     struct snd_info_private_data *data;
0223     struct snd_info_entry *entry;
0224 
0225     data = file->private_data;
0226     if (data == NULL)
0227         return 0;
0228     entry = data->entry;
0229     if (!entry->c.ops->mmap)
0230         return -ENXIO;
0231     return entry->c.ops->mmap(entry, data->file_private_data,
0232                   inode, file, vma);
0233 }
0234 
0235 static int snd_info_entry_open(struct inode *inode, struct file *file)
0236 {
0237     struct snd_info_entry *entry = pde_data(inode);
0238     struct snd_info_private_data *data;
0239     int mode, err;
0240 
0241     mutex_lock(&info_mutex);
0242     err = alloc_info_private(entry, &data);
0243     if (err < 0)
0244         goto unlock;
0245 
0246     mode = file->f_flags & O_ACCMODE;
0247     if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) ||
0248         ((mode == O_WRONLY || mode == O_RDWR) && !entry->c.ops->write)) {
0249         err = -ENODEV;
0250         goto error;
0251     }
0252 
0253     if (entry->c.ops->open) {
0254         err = entry->c.ops->open(entry, mode, &data->file_private_data);
0255         if (err < 0)
0256             goto error;
0257     }
0258 
0259     file->private_data = data;
0260     mutex_unlock(&info_mutex);
0261     return 0;
0262 
0263  error:
0264     kfree(data);
0265     module_put(entry->module);
0266  unlock:
0267     mutex_unlock(&info_mutex);
0268     return err;
0269 }
0270 
0271 static int snd_info_entry_release(struct inode *inode, struct file *file)
0272 {
0273     struct snd_info_private_data *data = file->private_data;
0274     struct snd_info_entry *entry = data->entry;
0275 
0276     if (entry->c.ops->release)
0277         entry->c.ops->release(entry, file->f_flags & O_ACCMODE,
0278                       data->file_private_data);
0279     module_put(entry->module);
0280     kfree(data);
0281     return 0;
0282 }
0283 
0284 static const struct proc_ops snd_info_entry_operations =
0285 {
0286     .proc_lseek = snd_info_entry_llseek,
0287     .proc_read  = snd_info_entry_read,
0288     .proc_write = snd_info_entry_write,
0289     .proc_poll  = snd_info_entry_poll,
0290     .proc_ioctl = snd_info_entry_ioctl,
0291     .proc_mmap  = snd_info_entry_mmap,
0292     .proc_open  = snd_info_entry_open,
0293     .proc_release   = snd_info_entry_release,
0294 };
0295 
0296 /*
0297  * file ops for text proc files
0298  */
0299 static ssize_t snd_info_text_entry_write(struct file *file,
0300                      const char __user *buffer,
0301                      size_t count, loff_t *offset)
0302 {
0303     struct seq_file *m = file->private_data;
0304     struct snd_info_private_data *data = m->private;
0305     struct snd_info_entry *entry = data->entry;
0306     struct snd_info_buffer *buf;
0307     loff_t pos;
0308     size_t next;
0309     int err = 0;
0310 
0311     if (!entry->c.text.write)
0312         return -EIO;
0313     pos = *offset;
0314     if (!valid_pos(pos, count))
0315         return -EIO;
0316     next = pos + count;
0317     /* don't handle too large text inputs */
0318     if (next > 16 * 1024)
0319         return -EIO;
0320     mutex_lock(&entry->access);
0321     buf = data->wbuffer;
0322     if (!buf) {
0323         data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL);
0324         if (!buf) {
0325             err = -ENOMEM;
0326             goto error;
0327         }
0328     }
0329     if (next > buf->len) {
0330         char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL);
0331         if (!nbuf) {
0332             err = -ENOMEM;
0333             goto error;
0334         }
0335         kvfree(buf->buffer);
0336         buf->buffer = nbuf;
0337         buf->len = PAGE_ALIGN(next);
0338     }
0339     if (copy_from_user(buf->buffer + pos, buffer, count)) {
0340         err = -EFAULT;
0341         goto error;
0342     }
0343     buf->size = next;
0344  error:
0345     mutex_unlock(&entry->access);
0346     if (err < 0)
0347         return err;
0348     *offset = next;
0349     return count;
0350 }
0351 
0352 static int snd_info_seq_show(struct seq_file *seq, void *p)
0353 {
0354     struct snd_info_private_data *data = seq->private;
0355     struct snd_info_entry *entry = data->entry;
0356 
0357     if (!entry->c.text.read) {
0358         return -EIO;
0359     } else {
0360         data->rbuffer->buffer = (char *)seq; /* XXX hack! */
0361         entry->c.text.read(entry, data->rbuffer);
0362     }
0363     return 0;
0364 }
0365 
0366 static int snd_info_text_entry_open(struct inode *inode, struct file *file)
0367 {
0368     struct snd_info_entry *entry = pde_data(inode);
0369     struct snd_info_private_data *data;
0370     int err;
0371 
0372     mutex_lock(&info_mutex);
0373     err = alloc_info_private(entry, &data);
0374     if (err < 0)
0375         goto unlock;
0376 
0377     data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL);
0378     if (!data->rbuffer) {
0379         err = -ENOMEM;
0380         goto error;
0381     }
0382     if (entry->size)
0383         err = single_open_size(file, snd_info_seq_show, data,
0384                        entry->size);
0385     else
0386         err = single_open(file, snd_info_seq_show, data);
0387     if (err < 0)
0388         goto error;
0389     mutex_unlock(&info_mutex);
0390     return 0;
0391 
0392  error:
0393     kfree(data->rbuffer);
0394     kfree(data);
0395     module_put(entry->module);
0396  unlock:
0397     mutex_unlock(&info_mutex);
0398     return err;
0399 }
0400 
0401 static int snd_info_text_entry_release(struct inode *inode, struct file *file)
0402 {
0403     struct seq_file *m = file->private_data;
0404     struct snd_info_private_data *data = m->private;
0405     struct snd_info_entry *entry = data->entry;
0406 
0407     if (data->wbuffer && entry->c.text.write)
0408         entry->c.text.write(entry, data->wbuffer);
0409 
0410     single_release(inode, file);
0411     kfree(data->rbuffer);
0412     if (data->wbuffer) {
0413         kvfree(data->wbuffer->buffer);
0414         kfree(data->wbuffer);
0415     }
0416 
0417     module_put(entry->module);
0418     kfree(data);
0419     return 0;
0420 }
0421 
0422 static const struct proc_ops snd_info_text_entry_ops =
0423 {
0424     .proc_open  = snd_info_text_entry_open,
0425     .proc_release   = snd_info_text_entry_release,
0426     .proc_write = snd_info_text_entry_write,
0427     .proc_lseek = seq_lseek,
0428     .proc_read  = seq_read,
0429 };
0430 
0431 static struct snd_info_entry *create_subdir(struct module *mod,
0432                         const char *name)
0433 {
0434     struct snd_info_entry *entry;
0435 
0436     entry = snd_info_create_module_entry(mod, name, NULL);
0437     if (!entry)
0438         return NULL;
0439     entry->mode = S_IFDIR | 0555;
0440     if (snd_info_register(entry) < 0) {
0441         snd_info_free_entry(entry);
0442         return NULL;
0443     }
0444     return entry;
0445 }
0446 
0447 static struct snd_info_entry *
0448 snd_info_create_entry(const char *name, struct snd_info_entry *parent,
0449               struct module *module);
0450 
0451 int __init snd_info_init(void)
0452 {
0453     snd_proc_root = snd_info_create_entry("asound", NULL, THIS_MODULE);
0454     if (!snd_proc_root)
0455         return -ENOMEM;
0456     snd_proc_root->mode = S_IFDIR | 0555;
0457     snd_proc_root->p = proc_mkdir("asound", NULL);
0458     if (!snd_proc_root->p)
0459         goto error;
0460 #ifdef CONFIG_SND_OSSEMUL
0461     snd_oss_root = create_subdir(THIS_MODULE, "oss");
0462     if (!snd_oss_root)
0463         goto error;
0464 #endif
0465 #if IS_ENABLED(CONFIG_SND_SEQUENCER)
0466     snd_seq_root = create_subdir(THIS_MODULE, "seq");
0467     if (!snd_seq_root)
0468         goto error;
0469 #endif
0470     if (snd_info_version_init() < 0 ||
0471         snd_minor_info_init() < 0 ||
0472         snd_minor_info_oss_init() < 0 ||
0473         snd_card_info_init() < 0 ||
0474         snd_info_minor_register() < 0)
0475         goto error;
0476     return 0;
0477 
0478  error:
0479     snd_info_free_entry(snd_proc_root);
0480     return -ENOMEM;
0481 }
0482 
0483 int __exit snd_info_done(void)
0484 {
0485     snd_info_free_entry(snd_proc_root);
0486     return 0;
0487 }
0488 
0489 static void snd_card_id_read(struct snd_info_entry *entry,
0490                  struct snd_info_buffer *buffer)
0491 {
0492     struct snd_card *card = entry->private_data;
0493 
0494     snd_iprintf(buffer, "%s\n", card->id);
0495 }
0496 
0497 /*
0498  * create a card proc file
0499  * called from init.c
0500  */
0501 int snd_info_card_create(struct snd_card *card)
0502 {
0503     char str[8];
0504     struct snd_info_entry *entry;
0505 
0506     if (snd_BUG_ON(!card))
0507         return -ENXIO;
0508 
0509     sprintf(str, "card%i", card->number);
0510     entry = create_subdir(card->module, str);
0511     if (!entry)
0512         return -ENOMEM;
0513     card->proc_root = entry;
0514 
0515     return snd_card_ro_proc_new(card, "id", card, snd_card_id_read);
0516 }
0517 
0518 /*
0519  * register the card proc file
0520  * called from init.c
0521  * can be called multiple times for reinitialization
0522  */
0523 int snd_info_card_register(struct snd_card *card)
0524 {
0525     struct proc_dir_entry *p;
0526     int err;
0527 
0528     if (snd_BUG_ON(!card))
0529         return -ENXIO;
0530 
0531     err = snd_info_register(card->proc_root);
0532     if (err < 0)
0533         return err;
0534 
0535     if (!strcmp(card->id, card->proc_root->name))
0536         return 0;
0537 
0538     if (card->proc_root_link)
0539         return 0;
0540     p = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name);
0541     if (!p)
0542         return -ENOMEM;
0543     card->proc_root_link = p;
0544     return 0;
0545 }
0546 
0547 /*
0548  * called on card->id change
0549  */
0550 void snd_info_card_id_change(struct snd_card *card)
0551 {
0552     mutex_lock(&info_mutex);
0553     if (card->proc_root_link) {
0554         proc_remove(card->proc_root_link);
0555         card->proc_root_link = NULL;
0556     }
0557     if (strcmp(card->id, card->proc_root->name))
0558         card->proc_root_link = proc_symlink(card->id,
0559                             snd_proc_root->p,
0560                             card->proc_root->name);
0561     mutex_unlock(&info_mutex);
0562 }
0563 
0564 /*
0565  * de-register the card proc file
0566  * called from init.c
0567  */
0568 void snd_info_card_disconnect(struct snd_card *card)
0569 {
0570     if (!card)
0571         return;
0572     mutex_lock(&info_mutex);
0573     proc_remove(card->proc_root_link);
0574     card->proc_root_link = NULL;
0575     if (card->proc_root)
0576         snd_info_disconnect(card->proc_root);
0577     mutex_unlock(&info_mutex);
0578 }
0579 
0580 /*
0581  * release the card proc file resources
0582  * called from init.c
0583  */
0584 int snd_info_card_free(struct snd_card *card)
0585 {
0586     if (!card)
0587         return 0;
0588     snd_info_free_entry(card->proc_root);
0589     card->proc_root = NULL;
0590     return 0;
0591 }
0592 
0593 
0594 /**
0595  * snd_info_get_line - read one line from the procfs buffer
0596  * @buffer: the procfs buffer
0597  * @line: the buffer to store
0598  * @len: the max. buffer size
0599  *
0600  * Reads one line from the buffer and stores the string.
0601  *
0602  * Return: Zero if successful, or 1 if error or EOF.
0603  */
0604 int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len)
0605 {
0606     int c;
0607 
0608     if (snd_BUG_ON(!buffer))
0609         return 1;
0610     if (!buffer->buffer)
0611         return 1;
0612     if (len <= 0 || buffer->stop || buffer->error)
0613         return 1;
0614     while (!buffer->stop) {
0615         c = buffer->buffer[buffer->curr++];
0616         if (buffer->curr >= buffer->size)
0617             buffer->stop = 1;
0618         if (c == '\n')
0619             break;
0620         if (len > 1) {
0621             len--;
0622             *line++ = c;
0623         }
0624     }
0625     *line = '\0';
0626     return 0;
0627 }
0628 EXPORT_SYMBOL(snd_info_get_line);
0629 
0630 /**
0631  * snd_info_get_str - parse a string token
0632  * @dest: the buffer to store the string token
0633  * @src: the original string
0634  * @len: the max. length of token - 1
0635  *
0636  * Parses the original string and copy a token to the given
0637  * string buffer.
0638  *
0639  * Return: The updated pointer of the original string so that
0640  * it can be used for the next call.
0641  */
0642 const char *snd_info_get_str(char *dest, const char *src, int len)
0643 {
0644     int c;
0645 
0646     while (*src == ' ' || *src == '\t')
0647         src++;
0648     if (*src == '"' || *src == '\'') {
0649         c = *src++;
0650         while (--len > 0 && *src && *src != c) {
0651             *dest++ = *src++;
0652         }
0653         if (*src == c)
0654             src++;
0655     } else {
0656         while (--len > 0 && *src && *src != ' ' && *src != '\t') {
0657             *dest++ = *src++;
0658         }
0659     }
0660     *dest = 0;
0661     while (*src == ' ' || *src == '\t')
0662         src++;
0663     return src;
0664 }
0665 EXPORT_SYMBOL(snd_info_get_str);
0666 
0667 /*
0668  * snd_info_create_entry - create an info entry
0669  * @name: the proc file name
0670  * @parent: the parent directory
0671  *
0672  * Creates an info entry with the given file name and initializes as
0673  * the default state.
0674  *
0675  * Usually called from other functions such as
0676  * snd_info_create_card_entry().
0677  *
0678  * Return: The pointer of the new instance, or %NULL on failure.
0679  */
0680 static struct snd_info_entry *
0681 snd_info_create_entry(const char *name, struct snd_info_entry *parent,
0682               struct module *module)
0683 {
0684     struct snd_info_entry *entry;
0685     entry = kzalloc(sizeof(*entry), GFP_KERNEL);
0686     if (entry == NULL)
0687         return NULL;
0688     entry->name = kstrdup(name, GFP_KERNEL);
0689     if (entry->name == NULL) {
0690         kfree(entry);
0691         return NULL;
0692     }
0693     entry->mode = S_IFREG | 0444;
0694     entry->content = SNDRV_INFO_CONTENT_TEXT;
0695     mutex_init(&entry->access);
0696     INIT_LIST_HEAD(&entry->children);
0697     INIT_LIST_HEAD(&entry->list);
0698     entry->parent = parent;
0699     entry->module = module;
0700     if (parent) {
0701         mutex_lock(&parent->access);
0702         list_add_tail(&entry->list, &parent->children);
0703         mutex_unlock(&parent->access);
0704     }
0705     return entry;
0706 }
0707 
0708 /**
0709  * snd_info_create_module_entry - create an info entry for the given module
0710  * @module: the module pointer
0711  * @name: the file name
0712  * @parent: the parent directory
0713  *
0714  * Creates a new info entry and assigns it to the given module.
0715  *
0716  * Return: The pointer of the new instance, or %NULL on failure.
0717  */
0718 struct snd_info_entry *snd_info_create_module_entry(struct module * module,
0719                            const char *name,
0720                            struct snd_info_entry *parent)
0721 {
0722     if (!parent)
0723         parent = snd_proc_root;
0724     return snd_info_create_entry(name, parent, module);
0725 }
0726 EXPORT_SYMBOL(snd_info_create_module_entry);
0727 
0728 /**
0729  * snd_info_create_card_entry - create an info entry for the given card
0730  * @card: the card instance
0731  * @name: the file name
0732  * @parent: the parent directory
0733  *
0734  * Creates a new info entry and assigns it to the given card.
0735  *
0736  * Return: The pointer of the new instance, or %NULL on failure.
0737  */
0738 struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card,
0739                          const char *name,
0740                          struct snd_info_entry * parent)
0741 {
0742     if (!parent)
0743         parent = card->proc_root;
0744     return snd_info_create_entry(name, parent, card->module);
0745 }
0746 EXPORT_SYMBOL(snd_info_create_card_entry);
0747 
0748 static void snd_info_disconnect(struct snd_info_entry *entry)
0749 {
0750     struct snd_info_entry *p;
0751 
0752     if (!entry->p)
0753         return;
0754     list_for_each_entry(p, &entry->children, list)
0755         snd_info_disconnect(p);
0756     proc_remove(entry->p);
0757     entry->p = NULL;
0758 }
0759 
0760 /**
0761  * snd_info_free_entry - release the info entry
0762  * @entry: the info entry
0763  *
0764  * Releases the info entry.
0765  */
0766 void snd_info_free_entry(struct snd_info_entry * entry)
0767 {
0768     struct snd_info_entry *p, *n;
0769 
0770     if (!entry)
0771         return;
0772     if (entry->p) {
0773         mutex_lock(&info_mutex);
0774         snd_info_disconnect(entry);
0775         mutex_unlock(&info_mutex);
0776     }
0777 
0778     /* free all children at first */
0779     list_for_each_entry_safe(p, n, &entry->children, list)
0780         snd_info_free_entry(p);
0781 
0782     p = entry->parent;
0783     if (p) {
0784         mutex_lock(&p->access);
0785         list_del(&entry->list);
0786         mutex_unlock(&p->access);
0787     }
0788     kfree(entry->name);
0789     if (entry->private_free)
0790         entry->private_free(entry);
0791     kfree(entry);
0792 }
0793 EXPORT_SYMBOL(snd_info_free_entry);
0794 
0795 static int __snd_info_register(struct snd_info_entry *entry)
0796 {
0797     struct proc_dir_entry *root, *p = NULL;
0798 
0799     if (snd_BUG_ON(!entry))
0800         return -ENXIO;
0801     root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p;
0802     mutex_lock(&info_mutex);
0803     if (entry->p || !root)
0804         goto unlock;
0805     if (S_ISDIR(entry->mode)) {
0806         p = proc_mkdir_mode(entry->name, entry->mode, root);
0807         if (!p) {
0808             mutex_unlock(&info_mutex);
0809             return -ENOMEM;
0810         }
0811     } else {
0812         const struct proc_ops *ops;
0813         if (entry->content == SNDRV_INFO_CONTENT_DATA)
0814             ops = &snd_info_entry_operations;
0815         else
0816             ops = &snd_info_text_entry_ops;
0817         p = proc_create_data(entry->name, entry->mode, root,
0818                      ops, entry);
0819         if (!p) {
0820             mutex_unlock(&info_mutex);
0821             return -ENOMEM;
0822         }
0823         proc_set_size(p, entry->size);
0824     }
0825     entry->p = p;
0826  unlock:
0827     mutex_unlock(&info_mutex);
0828     return 0;
0829 }
0830 
0831 /**
0832  * snd_info_register - register the info entry
0833  * @entry: the info entry
0834  *
0835  * Registers the proc info entry.
0836  * The all children entries are registered recursively.
0837  *
0838  * Return: Zero if successful, or a negative error code on failure.
0839  */
0840 int snd_info_register(struct snd_info_entry *entry)
0841 {
0842     struct snd_info_entry *p;
0843     int err;
0844 
0845     if (!entry->p) {
0846         err = __snd_info_register(entry);
0847         if (err < 0)
0848             return err;
0849     }
0850 
0851     list_for_each_entry(p, &entry->children, list) {
0852         err = snd_info_register(p);
0853         if (err < 0)
0854             return err;
0855     }
0856 
0857     return 0;
0858 }
0859 EXPORT_SYMBOL(snd_info_register);
0860 
0861 /**
0862  * snd_card_rw_proc_new - Create a read/write text proc file entry for the card
0863  * @card: the card instance
0864  * @name: the file name
0865  * @private_data: the arbitrary private data
0866  * @read: the read callback
0867  * @write: the write callback, NULL for read-only
0868  *
0869  * This proc file entry will be registered via snd_card_register() call, and
0870  * it will be removed automatically at the card removal, too.
0871  *
0872  * Return: zero if successful, or a negative error code
0873  */
0874 int snd_card_rw_proc_new(struct snd_card *card, const char *name,
0875              void *private_data,
0876              void (*read)(struct snd_info_entry *,
0877                       struct snd_info_buffer *),
0878              void (*write)(struct snd_info_entry *entry,
0879                        struct snd_info_buffer *buffer))
0880 {
0881     struct snd_info_entry *entry;
0882 
0883     entry = snd_info_create_card_entry(card, name, card->proc_root);
0884     if (!entry)
0885         return -ENOMEM;
0886     snd_info_set_text_ops(entry, private_data, read);
0887     if (write) {
0888         entry->mode |= 0200;
0889         entry->c.text.write = write;
0890     }
0891     return 0;
0892 }
0893 EXPORT_SYMBOL_GPL(snd_card_rw_proc_new);
0894 
0895 /*
0896 
0897  */
0898 
0899 static void snd_info_version_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
0900 {
0901     snd_iprintf(buffer,
0902             "Advanced Linux Sound Architecture Driver Version k%s.\n",
0903             init_utsname()->release);
0904 }
0905 
0906 static int __init snd_info_version_init(void)
0907 {
0908     struct snd_info_entry *entry;
0909 
0910     entry = snd_info_create_module_entry(THIS_MODULE, "version", NULL);
0911     if (entry == NULL)
0912         return -ENOMEM;
0913     entry->c.text.read = snd_info_version_read;
0914     return snd_info_register(entry); /* freed in error path */
0915 }