diff options
Diffstat (limited to 'sound/core/info.c')
| -rw-r--r-- | sound/core/info.c | 311 |
1 files changed, 160 insertions, 151 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index fe502bc5e6d2..1f5b8a3d9e3b 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -1,22 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Information interface for ALSA driver * Copyright (c) by Jaroslav Kysela <perex@perex.cz> - * - * - * 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 - * */ #include <linux/init.h> @@ -31,11 +16,10 @@ #include <linux/utsname.h> #include <linux/proc_fs.h> #include <linux/mutex.h> -#include <stdarg.h> int snd_info_check_reserved_words(const char *str) { - static char *reserved[] = + static const char * const reserved[] = { "version", "meminfo", @@ -50,7 +34,7 @@ int snd_info_check_reserved_words(const char *str) "seq", NULL }; - char **xstr = reserved; + const char * const *xstr = reserved; while (*xstr) { if (!strcmp(*xstr, str)) @@ -72,7 +56,7 @@ struct snd_info_private_data { }; static int snd_info_version_init(void); -static void snd_info_disconnect(struct snd_info_entry *entry); +static void snd_info_clear_entries(struct snd_info_entry *entry); /* @@ -121,17 +105,15 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) { struct snd_info_private_data *data; struct snd_info_entry *entry; - loff_t ret = -EINVAL, size; + loff_t size; data = file->private_data; entry = data->entry; - mutex_lock(&entry->access); - if (entry->c.ops->llseek) { - offset = entry->c.ops->llseek(entry, - data->file_private_data, - file, offset, orig); - goto out; - } + guard(mutex)(&entry->access); + if (entry->c.ops->llseek) + return entry->c.ops->llseek(entry, + data->file_private_data, + file, offset, orig); size = entry->size; switch (orig) { @@ -142,21 +124,18 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) break; case SEEK_END: if (!size) - goto out; + return -EINVAL; offset += size; break; default: - goto out; + return -EINVAL; } if (offset < 0) - goto out; + return -EINVAL; if (size && offset > size) offset = size; file->f_pos = offset; - ret = offset; - out: - mutex_unlock(&entry->access); - return ret; + return offset; } static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, @@ -250,14 +229,14 @@ static int snd_info_entry_mmap(struct file *file, struct vm_area_struct *vma) static int snd_info_entry_open(struct inode *inode, struct file *file) { - struct snd_info_entry *entry = PDE_DATA(inode); + struct snd_info_entry *entry = pde_data(inode); struct snd_info_private_data *data; int mode, err; - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); err = alloc_info_private(entry, &data); if (err < 0) - goto unlock; + return err; mode = file->f_flags & O_ACCMODE; if (((mode == O_RDONLY || mode == O_RDWR) && !entry->c.ops->read) || @@ -273,14 +252,11 @@ static int snd_info_entry_open(struct inode *inode, struct file *file) } file->private_data = data; - mutex_unlock(&info_mutex); return 0; error: kfree(data); module_put(entry->module); - unlock: - mutex_unlock(&info_mutex); return err; } @@ -297,17 +273,16 @@ static int snd_info_entry_release(struct inode *inode, struct file *file) return 0; } -static const struct file_operations snd_info_entry_operations = +static const struct proc_ops snd_info_entry_operations = { - .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, + .proc_lseek = snd_info_entry_llseek, + .proc_read = snd_info_entry_read, + .proc_write = snd_info_entry_write, + .proc_poll = snd_info_entry_poll, + .proc_ioctl = snd_info_entry_ioctl, + .proc_mmap = snd_info_entry_mmap, + .proc_open = snd_info_entry_open, + .proc_release = snd_info_entry_release, }; /* @@ -323,7 +298,6 @@ static ssize_t snd_info_text_entry_write(struct file *file, struct snd_info_buffer *buf; loff_t pos; size_t next; - int err = 0; if (!entry->c.text.write) return -EIO; @@ -334,34 +308,24 @@ static ssize_t snd_info_text_entry_write(struct file *file, /* don't handle too large text inputs */ if (next > 16 * 1024) return -EIO; - mutex_lock(&entry->access); + guard(mutex)(&entry->access); buf = data->wbuffer; if (!buf) { data->wbuffer = buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (!buf) { - err = -ENOMEM; - goto error; - } + if (!buf) + return -ENOMEM; } if (next > buf->len) { char *nbuf = kvzalloc(PAGE_ALIGN(next), GFP_KERNEL); - if (!nbuf) { - err = -ENOMEM; - goto error; - } + if (!nbuf) + return -ENOMEM; kvfree(buf->buffer); buf->buffer = nbuf; buf->len = PAGE_ALIGN(next); } - if (copy_from_user(buf->buffer + pos, buffer, count)) { - err = -EFAULT; - goto error; - } + if (copy_from_user(buf->buffer + pos, buffer, count)) + return -EFAULT; buf->size = next; - error: - mutex_unlock(&entry->access); - if (err < 0) - return err; *offset = next; return count; } @@ -382,14 +346,14 @@ static int snd_info_seq_show(struct seq_file *seq, void *p) static int snd_info_text_entry_open(struct inode *inode, struct file *file) { - struct snd_info_entry *entry = PDE_DATA(inode); + struct snd_info_entry *entry = pde_data(inode); struct snd_info_private_data *data; int err; - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); err = alloc_info_private(entry, &data); if (err < 0) - goto unlock; + return err; data->rbuffer = kzalloc(sizeof(*data->rbuffer), GFP_KERNEL); if (!data->rbuffer) { @@ -403,15 +367,12 @@ static int snd_info_text_entry_open(struct inode *inode, struct file *file) err = single_open(file, snd_info_seq_show, data); if (err < 0) goto error; - mutex_unlock(&info_mutex); return 0; error: kfree(data->rbuffer); kfree(data); module_put(entry->module); - unlock: - mutex_unlock(&info_mutex); return err; } @@ -436,14 +397,13 @@ static int snd_info_text_entry_release(struct inode *inode, struct file *file) return 0; } -static const struct file_operations snd_info_text_entry_ops = +static const struct proc_ops snd_info_text_entry_ops = { - .owner = THIS_MODULE, - .open = snd_info_text_entry_open, - .release = snd_info_text_entry_release, - .write = snd_info_text_entry_write, - .llseek = seq_lseek, - .read = seq_read, + .proc_open = snd_info_text_entry_open, + .proc_release = snd_info_text_entry_release, + .proc_write = snd_info_text_entry_write, + .proc_lseek = seq_lseek, + .proc_read = seq_read, }; static struct snd_info_entry *create_subdir(struct module *mod, @@ -463,11 +423,12 @@ static struct snd_info_entry *create_subdir(struct module *mod, } static struct snd_info_entry * -snd_info_create_entry(const char *name, struct snd_info_entry *parent); +snd_info_create_entry(const char *name, struct snd_info_entry *parent, + struct module *module); int __init snd_info_init(void) { - snd_proc_root = snd_info_create_entry("asound", NULL); + snd_proc_root = snd_info_create_entry("asound", NULL, THIS_MODULE); if (!snd_proc_root) return -ENOMEM; snd_proc_root->mode = S_IFDIR | 0555; @@ -503,6 +464,14 @@ int __exit snd_info_done(void) return 0; } +static void snd_card_id_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_card *card = entry->private_data; + + snd_iprintf(buffer, "%s\n", card->id); +} + /* * create a card proc file * called from init.c @@ -520,28 +489,8 @@ int snd_info_card_create(struct snd_card *card) if (!entry) return -ENOMEM; card->proc_root = entry; - return 0; -} -/* register all pending info entries */ -static int snd_info_register_recursive(struct snd_info_entry *entry) -{ - struct snd_info_entry *p; - int err; - - if (!entry->p) { - err = snd_info_register(entry); - if (err < 0) - return err; - } - - list_for_each_entry(p, &entry->children, list) { - err = snd_info_register_recursive(p); - if (err < 0) - return err; - } - - return 0; + return snd_card_ro_proc_new(card, "id", card, snd_card_id_read); } /* @@ -557,7 +506,7 @@ int snd_info_card_register(struct snd_card *card) if (snd_BUG_ON(!card)) return -ENXIO; - err = snd_info_register_recursive(card->proc_root); + err = snd_info_register(card->proc_root); if (err < 0) return err; @@ -578,7 +527,7 @@ int snd_info_card_register(struct snd_card *card) */ void snd_info_card_id_change(struct snd_card *card) { - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); if (card->proc_root_link) { proc_remove(card->proc_root_link); card->proc_root_link = NULL; @@ -587,7 +536,6 @@ void snd_info_card_id_change(struct snd_card *card) card->proc_root_link = proc_symlink(card->id, snd_proc_root->p, card->proc_root->name); - mutex_unlock(&info_mutex); } /* @@ -598,12 +546,16 @@ void snd_info_card_disconnect(struct snd_card *card) { if (!card) return; - mutex_lock(&info_mutex); + proc_remove(card->proc_root_link); - card->proc_root_link = NULL; if (card->proc_root) - snd_info_disconnect(card->proc_root); - mutex_unlock(&info_mutex); + proc_remove(card->proc_root->p); + + guard(mutex)(&info_mutex); + if (card->proc_root) + snd_info_clear_entries(card->proc_root); + card->proc_root_link = NULL; + card->proc_root = NULL; } /* @@ -632,9 +584,11 @@ int snd_info_card_free(struct snd_card *card) */ int snd_info_get_line(struct snd_info_buffer *buffer, char *line, int len) { - int c = -1; + int c; - if (snd_BUG_ON(!buffer || !buffer->buffer)) + if (snd_BUG_ON(!buffer)) + return 1; + if (!buffer->buffer) return 1; if (len <= 0 || buffer->stop || buffer->error) return 1; @@ -705,7 +659,8 @@ EXPORT_SYMBOL(snd_info_get_str); * Return: The pointer of the new instance, or %NULL on failure. */ static struct snd_info_entry * -snd_info_create_entry(const char *name, struct snd_info_entry *parent) +snd_info_create_entry(const char *name, struct snd_info_entry *parent, + struct module *module) { struct snd_info_entry *entry; entry = kzalloc(sizeof(*entry), GFP_KERNEL); @@ -722,8 +677,11 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent) INIT_LIST_HEAD(&entry->children); INIT_LIST_HEAD(&entry->list); entry->parent = parent; - if (parent) + entry->module = module; + if (parent) { + guard(mutex)(&parent->access); list_add_tail(&entry->list, &parent->children); + } return entry; } @@ -741,10 +699,9 @@ struct snd_info_entry *snd_info_create_module_entry(struct module * module, const char *name, struct snd_info_entry *parent) { - struct snd_info_entry *entry = snd_info_create_entry(name, parent); - if (entry) - entry->module = module; - return entry; + if (!parent) + parent = snd_proc_root; + return snd_info_create_entry(name, parent, module); } EXPORT_SYMBOL(snd_info_create_module_entry); @@ -762,24 +719,20 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, const char *name, struct snd_info_entry * parent) { - struct snd_info_entry *entry = snd_info_create_entry(name, parent); - if (entry) { - entry->module = card->module; - entry->card = card; - } - return entry; + if (!parent) + parent = card->proc_root; + return snd_info_create_entry(name, parent, card->module); } EXPORT_SYMBOL(snd_info_create_card_entry); -static void snd_info_disconnect(struct snd_info_entry *entry) +static void snd_info_clear_entries(struct snd_info_entry *entry) { struct snd_info_entry *p; if (!entry->p) return; list_for_each_entry(p, &entry->children, list) - snd_info_disconnect(p); - proc_remove(entry->p); + snd_info_clear_entries(p); entry->p = NULL; } @@ -796,16 +749,20 @@ void snd_info_free_entry(struct snd_info_entry * entry) if (!entry) return; if (entry->p) { - mutex_lock(&info_mutex); - snd_info_disconnect(entry); - mutex_unlock(&info_mutex); + proc_remove(entry->p); + guard(mutex)(&info_mutex); + snd_info_clear_entries(entry); } /* free all children at first */ list_for_each_entry_safe(p, n, &entry->children, list) snd_info_free_entry(p); - list_del(&entry->list); + p = entry->parent; + if (p) { + guard(mutex)(&p->access); + list_del(&entry->list); + } kfree(entry->name); if (entry->private_free) entry->private_free(entry); @@ -813,48 +770,100 @@ void snd_info_free_entry(struct snd_info_entry * entry) } EXPORT_SYMBOL(snd_info_free_entry); -/** - * snd_info_register - register the info entry - * @entry: the info entry - * - * Registers the proc info entry. - * - * Return: Zero if successful, or a negative error code on failure. - */ -int snd_info_register(struct snd_info_entry * entry) +static int __snd_info_register(struct snd_info_entry *entry) { struct proc_dir_entry *root, *p = NULL; if (snd_BUG_ON(!entry)) return -ENXIO; root = entry->parent == NULL ? snd_proc_root->p : entry->parent->p; - mutex_lock(&info_mutex); + guard(mutex)(&info_mutex); + if (entry->p || !root) + return 0; if (S_ISDIR(entry->mode)) { p = proc_mkdir_mode(entry->name, entry->mode, root); - if (!p) { - mutex_unlock(&info_mutex); + if (!p) return -ENOMEM; - } } else { - const struct file_operations *ops; + const struct proc_ops *ops; if (entry->content == SNDRV_INFO_CONTENT_DATA) ops = &snd_info_entry_operations; else ops = &snd_info_text_entry_ops; p = proc_create_data(entry->name, entry->mode, root, ops, entry); - if (!p) { - mutex_unlock(&info_mutex); + if (!p) return -ENOMEM; - } proc_set_size(p, entry->size); } entry->p = p; - mutex_unlock(&info_mutex); + return 0; +} + +/** + * snd_info_register - register the info entry + * @entry: the info entry + * + * Registers the proc info entry. + * The all children entries are registered recursively. + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_info_register(struct snd_info_entry *entry) +{ + struct snd_info_entry *p; + int err; + + if (!entry->p) { + err = __snd_info_register(entry); + if (err < 0) + return err; + } + + list_for_each_entry(p, &entry->children, list) { + err = snd_info_register(p); + if (err < 0) + return err; + } + return 0; } EXPORT_SYMBOL(snd_info_register); +/** + * snd_card_rw_proc_new - Create a read/write text proc file entry for the card + * @card: the card instance + * @name: the file name + * @private_data: the arbitrary private data + * @read: the read callback + * @write: the write callback, NULL for read-only + * + * This proc file entry will be registered via snd_card_register() call, and + * it will be removed automatically at the card removal, too. + * + * Return: zero if successful, or a negative error code + */ +int snd_card_rw_proc_new(struct snd_card *card, const char *name, + void *private_data, + void (*read)(struct snd_info_entry *, + struct snd_info_buffer *), + void (*write)(struct snd_info_entry *entry, + struct snd_info_buffer *buffer)) +{ + struct snd_info_entry *entry; + + entry = snd_info_create_card_entry(card, name, card->proc_root); + if (!entry) + return -ENOMEM; + snd_info_set_text_ops(entry, private_data, read); + if (write) { + entry->mode |= 0200; + entry->c.text.write = write; + } + return 0; +} +EXPORT_SYMBOL_GPL(snd_card_rw_proc_new); + /* */ |
