diff options
Diffstat (limited to 'sound/core/hwdep.c')
| -rw-r--r-- | sound/core/hwdep.c | 242 |
1 files changed, 117 insertions, 125 deletions
diff --git a/sound/core/hwdep.c b/sound/core/hwdep.c index d105073298cb..09200df2932c 100644 --- a/sound/core/hwdep.c +++ b/sound/core/hwdep.c @@ -1,22 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Hardware dependent layer * 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/major.h> @@ -25,6 +10,7 @@ #include <linux/time.h> #include <linux/mutex.h> #include <linux/module.h> +#include <linux/sched/signal.h> #include <sound/core.h> #include <sound/control.h> #include <sound/minors.h> @@ -38,7 +24,6 @@ MODULE_LICENSE("GPL"); static LIST_HEAD(snd_hwdep_devices); static DEFINE_MUTEX(register_mutex); -static int snd_hwdep_free(struct snd_hwdep *hwdep); static int snd_hwdep_dev_free(struct snd_device *device); static int snd_hwdep_dev_register(struct snd_device *device); static int snd_hwdep_dev_disconnect(struct snd_device *device); @@ -85,7 +70,7 @@ static int snd_hwdep_open(struct inode *inode, struct file * file) int major = imajor(inode); struct snd_hwdep *hw; int err; - wait_queue_t wait; + wait_queue_entry_t wait; if (major == snd_major) { hw = snd_lookup_minor_data(iminor(inode), @@ -164,12 +149,12 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) struct snd_hwdep *hw = file->private_data; struct module *mod = hw->card->module; - mutex_lock(&hw->open_mutex); - if (hw->ops.release) - err = hw->ops.release(hw, file); - if (hw->used > 0) - hw->used--; - mutex_unlock(&hw->open_mutex); + scoped_guard(mutex, &hw->open_mutex) { + if (hw->ops.release) + err = hw->ops.release(hw, file); + if (hw->used > 0) + hw->used--; + } wake_up(&hw->open_wait); snd_card_file_remove(hw->card, file); @@ -177,7 +162,7 @@ static int snd_hwdep_release(struct inode *inode, struct file * file) return err; } -static unsigned int snd_hwdep_poll(struct file * file, poll_table * wait) +static __poll_t snd_hwdep_poll(struct file * file, poll_table * wait) { struct snd_hwdep *hw = file->private_data; if (hw->ops.poll) @@ -192,8 +177,8 @@ static int snd_hwdep_info(struct snd_hwdep *hw, memset(&info, 0, sizeof(info)); info.card = hw->card->number; - strlcpy(info.id, hw->id, sizeof(info.id)); - strlcpy(info.name, hw->name, sizeof(info.name)); + strscpy(info.id, hw->id, sizeof(info.id)); + strscpy(info.name, hw->name, sizeof(info.name)); info.iface = hw->iface; if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -210,7 +195,8 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw, return -ENXIO; memset(&info, 0, sizeof(info)); info.dsp_loaded = hw->dsp_loaded; - if ((err = hw->ops.dsp_status(hw, &info)) < 0) + err = hw->ops.dsp_status(hw, &info); + if (err < 0) return err; if (copy_to_user(_info, &info, sizeof(info))) return -EFAULT; @@ -218,28 +204,35 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw, } static int snd_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image __user *_info) + struct snd_hwdep_dsp_image *info) { - struct snd_hwdep_dsp_image info; int err; if (! hw->ops.dsp_load) return -ENXIO; - memset(&info, 0, sizeof(info)); - if (copy_from_user(&info, _info, sizeof(info))) - return -EFAULT; + if (info->index >= 32) + return -EINVAL; /* check whether the dsp was already loaded */ - if (hw->dsp_loaded & (1 << info.index)) + if (hw->dsp_loaded & (1u << info->index)) return -EBUSY; - if (!access_ok(VERIFY_READ, info.image, info.length)) - return -EFAULT; - err = hw->ops.dsp_load(hw, &info); + err = hw->ops.dsp_load(hw, info); if (err < 0) return err; - hw->dsp_loaded |= (1 << info.index); + hw->dsp_loaded |= (1u << info->index); return 0; } +static int snd_hwdep_dsp_load_user(struct snd_hwdep *hw, + struct snd_hwdep_dsp_image __user *_info) +{ + struct snd_hwdep_dsp_image info = {}; + + if (copy_from_user(&info, _info, sizeof(info))) + return -EFAULT; + return snd_hwdep_dsp_load(hw, &info); +} + + static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, unsigned long arg) { @@ -253,7 +246,7 @@ static long snd_hwdep_ioctl(struct file * file, unsigned int cmd, case SNDRV_HWDEP_IOCTL_DSP_STATUS: return snd_hwdep_dsp_status(hw, argp); case SNDRV_HWDEP_IOCTL_DSP_LOAD: - return snd_hwdep_dsp_load(hw, argp); + return snd_hwdep_dsp_load_user(hw, argp); } if (hw->ops.ioctl) return hw->ops.ioctl(hw, file, cmd, arg); @@ -279,23 +272,23 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, if (get_user(device, (int __user *)arg)) return -EFAULT; - mutex_lock(®ister_mutex); - - if (device < 0) - device = 0; - else if (device < SNDRV_MINOR_HWDEPS) - device++; - else - device = SNDRV_MINOR_HWDEPS; - - while (device < SNDRV_MINOR_HWDEPS) { - if (snd_hwdep_search(card, device)) - break; - device++; + + scoped_guard(mutex, ®ister_mutex) { + if (device < 0) + device = 0; + else if (device < SNDRV_MINOR_HWDEPS) + device++; + else + device = SNDRV_MINOR_HWDEPS; + + while (device < SNDRV_MINOR_HWDEPS) { + if (snd_hwdep_search(card, device)) + break; + device++; + } + if (device >= SNDRV_MINOR_HWDEPS) + device = -1; } - if (device >= SNDRV_MINOR_HWDEPS) - device = -1; - mutex_unlock(®ister_mutex); if (put_user(device, (int __user *)arg)) return -EFAULT; return 0; @@ -303,19 +296,18 @@ static int snd_hwdep_control_ioctl(struct snd_card *card, case SNDRV_CTL_IOCTL_HWDEP_INFO: { struct snd_hwdep_info __user *info = (struct snd_hwdep_info __user *)arg; - int device, err; + int device; struct snd_hwdep *hwdep; if (get_user(device, &info->device)) return -EFAULT; - mutex_lock(®ister_mutex); - hwdep = snd_hwdep_search(card, device); - if (hwdep) - err = snd_hwdep_info(hwdep, info); - else - err = -ENXIO; - mutex_unlock(®ister_mutex); - return err; + scoped_guard(mutex, ®ister_mutex) { + hwdep = snd_hwdep_search(card, device); + if (!hwdep) + return -ENXIO; + return snd_hwdep_info(hwdep, info); + } + break; } } return -ENOIOCTLCMD; @@ -345,6 +337,16 @@ static const struct file_operations snd_hwdep_f_ops = .mmap = snd_hwdep_mmap, }; +static void snd_hwdep_free(struct snd_hwdep *hwdep) +{ + if (!hwdep) + return; + if (hwdep->private_free) + hwdep->private_free(hwdep); + put_device(hwdep->dev); + kfree(hwdep); +} + /** * snd_hwdep_new - create a new hwdep instance * @card: the card instance @@ -363,7 +365,7 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, { struct snd_hwdep *hwdep; int err; - static struct snd_device_ops ops = { + static const struct snd_device_ops ops = { .dev_free = snd_hwdep_dev_free, .dev_register = snd_hwdep_dev_register, .dev_disconnect = snd_hwdep_dev_disconnect, @@ -374,84 +376,80 @@ int snd_hwdep_new(struct snd_card *card, char *id, int device, if (rhwdep) *rhwdep = NULL; hwdep = kzalloc(sizeof(*hwdep), GFP_KERNEL); - if (hwdep == NULL) { - snd_printk(KERN_ERR "hwdep: cannot allocate\n"); + if (!hwdep) return -ENOMEM; - } + + init_waitqueue_head(&hwdep->open_wait); + mutex_init(&hwdep->open_mutex); hwdep->card = card; hwdep->device = device; if (id) - strlcpy(hwdep->id, id, sizeof(hwdep->id)); + strscpy(hwdep->id, id, sizeof(hwdep->id)); + + err = snd_device_alloc(&hwdep->dev, card); + if (err < 0) { + snd_hwdep_free(hwdep); + return err; + } + + dev_set_name(hwdep->dev, "hwC%iD%i", card->number, device); #ifdef CONFIG_SND_OSSEMUL hwdep->oss_type = -1; #endif - if ((err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops)) < 0) { + + err = snd_device_new(card, SNDRV_DEV_HWDEP, hwdep, &ops); + if (err < 0) { snd_hwdep_free(hwdep); return err; } - init_waitqueue_head(&hwdep->open_wait); - mutex_init(&hwdep->open_mutex); + if (rhwdep) *rhwdep = hwdep; return 0; } - -static int snd_hwdep_free(struct snd_hwdep *hwdep) -{ - if (!hwdep) - return 0; - if (hwdep->private_free) - hwdep->private_free(hwdep); - kfree(hwdep); - return 0; -} +EXPORT_SYMBOL(snd_hwdep_new); static int snd_hwdep_dev_free(struct snd_device *device) { - struct snd_hwdep *hwdep = device->device_data; - return snd_hwdep_free(hwdep); + snd_hwdep_free(device->device_data); + return 0; } static int snd_hwdep_dev_register(struct snd_device *device) { struct snd_hwdep *hwdep = device->device_data; + struct snd_card *card = hwdep->card; int err; - char name[32]; - mutex_lock(®ister_mutex); - if (snd_hwdep_search(hwdep->card, hwdep->device)) { - mutex_unlock(®ister_mutex); + guard(mutex)(®ister_mutex); + if (snd_hwdep_search(card, hwdep->device)) return -EBUSY; - } list_add_tail(&hwdep->list, &snd_hwdep_devices); - sprintf(name, "hwC%iD%i", hwdep->card->number, hwdep->device); - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, - hwdep->card, hwdep->device, - &snd_hwdep_f_ops, hwdep, name)) < 0) { - snd_printk(KERN_ERR "unable to register hardware dependent device %i:%i\n", - hwdep->card->number, hwdep->device); + err = snd_register_device(SNDRV_DEVICE_TYPE_HWDEP, + hwdep->card, hwdep->device, + &snd_hwdep_f_ops, hwdep, hwdep->dev); + if (err < 0) { + dev_err(hwdep->dev, "unable to register\n"); list_del(&hwdep->list); - mutex_unlock(®ister_mutex); return err; } + #ifdef CONFIG_SND_OSSEMUL hwdep->ossreg = 0; if (hwdep->oss_type >= 0) { - if ((hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM) && (hwdep->device != 0)) { - snd_printk (KERN_WARNING "only hwdep device 0 can be registered as OSS direct FM device!\n"); - } else { - if (snd_register_oss_device(hwdep->oss_type, - hwdep->card, hwdep->device, - &snd_hwdep_f_ops, hwdep, - hwdep->oss_dev) < 0) { - snd_printk(KERN_ERR "unable to register OSS compatibility device %i:%i\n", - hwdep->card->number, hwdep->device); - } else - hwdep->ossreg = 1; - } + if (hwdep->oss_type == SNDRV_OSS_DEVICE_TYPE_DMFM && + hwdep->device) + dev_warn(hwdep->dev, + "only hwdep device 0 can be registered as OSS direct FM device!\n"); + else if (snd_register_oss_device(hwdep->oss_type, + card, hwdep->device, + &snd_hwdep_f_ops, hwdep) < 0) + dev_warn(hwdep->dev, + "unable to register OSS compatibility device\n"); + else + hwdep->ossreg = 1; } #endif - mutex_unlock(®ister_mutex); return 0; } @@ -461,25 +459,21 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device) if (snd_BUG_ON(!hwdep)) return -ENXIO; - mutex_lock(®ister_mutex); - if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) { - mutex_unlock(®ister_mutex); + guard(mutex)(®ister_mutex); + if (snd_hwdep_search(hwdep->card, hwdep->device) != hwdep) return -EINVAL; - } - mutex_lock(&hwdep->open_mutex); + guard(mutex)(&hwdep->open_mutex); wake_up(&hwdep->open_wait); #ifdef CONFIG_SND_OSSEMUL if (hwdep->ossreg) snd_unregister_oss_device(hwdep->oss_type, hwdep->card, hwdep->device); #endif - snd_unregister_device(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, hwdep->device); + snd_unregister_device(hwdep->dev); list_del_init(&hwdep->list); - mutex_unlock(&hwdep->open_mutex); - mutex_unlock(®ister_mutex); return 0; } -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_SND_PROC_FS /* * Info interface */ @@ -489,11 +483,10 @@ static void snd_hwdep_proc_read(struct snd_info_entry *entry, { struct snd_hwdep *hwdep; - mutex_lock(®ister_mutex); + guard(mutex)(®ister_mutex); list_for_each_entry(hwdep, &snd_hwdep_devices, list) snd_iprintf(buffer, "%02i-%02i: %s\n", hwdep->card->number, hwdep->device, hwdep->name); - mutex_unlock(®ister_mutex); } static struct snd_info_entry *snd_hwdep_proc_entry; @@ -502,7 +495,8 @@ static void __init snd_hwdep_proc_init(void) { struct snd_info_entry *entry; - if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) { + entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL); + if (entry) { entry->c.text.read = snd_hwdep_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -516,10 +510,10 @@ static void __exit snd_hwdep_proc_done(void) { snd_info_free_entry(snd_hwdep_proc_entry); } -#else /* !CONFIG_PROC_FS */ +#else /* !CONFIG_SND_PROC_FS */ #define snd_hwdep_proc_init() #define snd_hwdep_proc_done() -#endif /* CONFIG_PROC_FS */ +#endif /* CONFIG_SND_PROC_FS */ /* @@ -543,5 +537,3 @@ static void __exit alsa_hwdep_exit(void) module_init(alsa_hwdep_init) module_exit(alsa_hwdep_exit) - -EXPORT_SYMBOL(snd_hwdep_new); |
