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

sound.c (10491B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Advanced Linux Sound Architecture
      4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
      5 */
      6
      7#include <linux/init.h>
      8#include <linux/slab.h>
      9#include <linux/time.h>
     10#include <linux/device.h>
     11#include <linux/module.h>
     12#include <linux/debugfs.h>
     13#include <sound/core.h>
     14#include <sound/minors.h>
     15#include <sound/info.h>
     16#include <sound/control.h>
     17#include <sound/initval.h>
     18#include <linux/kmod.h>
     19#include <linux/mutex.h>
     20
     21static int major = CONFIG_SND_MAJOR;
     22int snd_major;
     23EXPORT_SYMBOL(snd_major);
     24
     25static int cards_limit = 1;
     26
     27MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
     28MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards.");
     29MODULE_LICENSE("GPL");
     30module_param(major, int, 0444);
     31MODULE_PARM_DESC(major, "Major # for sound driver.");
     32module_param(cards_limit, int, 0444);
     33MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards.");
     34MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR);
     35
     36/* this one holds the actual max. card number currently available.
     37 * as default, it's identical with cards_limit option.  when more
     38 * modules are loaded manually, this limit number increases, too.
     39 */
     40int snd_ecards_limit;
     41EXPORT_SYMBOL(snd_ecards_limit);
     42
     43#ifdef CONFIG_SND_DEBUG
     44struct dentry *sound_debugfs_root;
     45EXPORT_SYMBOL_GPL(sound_debugfs_root);
     46#endif
     47
     48static struct snd_minor *snd_minors[SNDRV_OS_MINORS];
     49static DEFINE_MUTEX(sound_mutex);
     50
     51#ifdef CONFIG_MODULES
     52
     53/**
     54 * snd_request_card - try to load the card module
     55 * @card: the card number
     56 *
     57 * Tries to load the module "snd-card-X" for the given card number
     58 * via request_module.  Returns immediately if already loaded.
     59 */
     60void snd_request_card(int card)
     61{
     62	if (snd_card_locked(card))
     63		return;
     64	if (card < 0 || card >= cards_limit)
     65		return;
     66	request_module("snd-card-%i", card);
     67}
     68EXPORT_SYMBOL(snd_request_card);
     69
     70static void snd_request_other(int minor)
     71{
     72	char *str;
     73
     74	switch (minor) {
     75	case SNDRV_MINOR_SEQUENCER:	str = "snd-seq";	break;
     76	case SNDRV_MINOR_TIMER:		str = "snd-timer";	break;
     77	default:			return;
     78	}
     79	request_module(str);
     80}
     81
     82#endif	/* modular kernel */
     83
     84/**
     85 * snd_lookup_minor_data - get user data of a registered device
     86 * @minor: the minor number
     87 * @type: device type (SNDRV_DEVICE_TYPE_XXX)
     88 *
     89 * Checks that a minor device with the specified type is registered, and returns
     90 * its user data pointer.
     91 *
     92 * This function increments the reference counter of the card instance
     93 * if an associated instance with the given minor number and type is found.
     94 * The caller must call snd_card_unref() appropriately later.
     95 *
     96 * Return: The user data pointer if the specified device is found. %NULL
     97 * otherwise.
     98 */
     99void *snd_lookup_minor_data(unsigned int minor, int type)
    100{
    101	struct snd_minor *mreg;
    102	void *private_data;
    103
    104	if (minor >= ARRAY_SIZE(snd_minors))
    105		return NULL;
    106	mutex_lock(&sound_mutex);
    107	mreg = snd_minors[minor];
    108	if (mreg && mreg->type == type) {
    109		private_data = mreg->private_data;
    110		if (private_data && mreg->card_ptr)
    111			get_device(&mreg->card_ptr->card_dev);
    112	} else
    113		private_data = NULL;
    114	mutex_unlock(&sound_mutex);
    115	return private_data;
    116}
    117EXPORT_SYMBOL(snd_lookup_minor_data);
    118
    119#ifdef CONFIG_MODULES
    120static struct snd_minor *autoload_device(unsigned int minor)
    121{
    122	int dev;
    123	mutex_unlock(&sound_mutex); /* release lock temporarily */
    124	dev = SNDRV_MINOR_DEVICE(minor);
    125	if (dev == SNDRV_MINOR_CONTROL) {
    126		/* /dev/aloadC? */
    127		int card = SNDRV_MINOR_CARD(minor);
    128		struct snd_card *ref = snd_card_ref(card);
    129		if (!ref)
    130			snd_request_card(card);
    131		else
    132			snd_card_unref(ref);
    133	} else if (dev == SNDRV_MINOR_GLOBAL) {
    134		/* /dev/aloadSEQ */
    135		snd_request_other(minor);
    136	}
    137	mutex_lock(&sound_mutex); /* reacuire lock */
    138	return snd_minors[minor];
    139}
    140#else /* !CONFIG_MODULES */
    141#define autoload_device(minor)	NULL
    142#endif /* CONFIG_MODULES */
    143
    144static int snd_open(struct inode *inode, struct file *file)
    145{
    146	unsigned int minor = iminor(inode);
    147	struct snd_minor *mptr = NULL;
    148	const struct file_operations *new_fops;
    149	int err = 0;
    150
    151	if (minor >= ARRAY_SIZE(snd_minors))
    152		return -ENODEV;
    153	mutex_lock(&sound_mutex);
    154	mptr = snd_minors[minor];
    155	if (mptr == NULL) {
    156		mptr = autoload_device(minor);
    157		if (!mptr) {
    158			mutex_unlock(&sound_mutex);
    159			return -ENODEV;
    160		}
    161	}
    162	new_fops = fops_get(mptr->f_ops);
    163	mutex_unlock(&sound_mutex);
    164	if (!new_fops)
    165		return -ENODEV;
    166	replace_fops(file, new_fops);
    167
    168	if (file->f_op->open)
    169		err = file->f_op->open(inode, file);
    170	return err;
    171}
    172
    173static const struct file_operations snd_fops =
    174{
    175	.owner =	THIS_MODULE,
    176	.open =		snd_open,
    177	.llseek =	noop_llseek,
    178};
    179
    180#ifdef CONFIG_SND_DYNAMIC_MINORS
    181static int snd_find_free_minor(int type, struct snd_card *card, int dev)
    182{
    183	int minor;
    184
    185	/* static minors for module auto loading */
    186	if (type == SNDRV_DEVICE_TYPE_SEQUENCER)
    187		return SNDRV_MINOR_SEQUENCER;
    188	if (type == SNDRV_DEVICE_TYPE_TIMER)
    189		return SNDRV_MINOR_TIMER;
    190
    191	for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
    192		/* skip static minors still used for module auto loading */
    193		if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL)
    194			continue;
    195		if (minor == SNDRV_MINOR_SEQUENCER ||
    196		    minor == SNDRV_MINOR_TIMER)
    197			continue;
    198		if (!snd_minors[minor])
    199			return minor;
    200	}
    201	return -EBUSY;
    202}
    203#else
    204static int snd_find_free_minor(int type, struct snd_card *card, int dev)
    205{
    206	int minor;
    207
    208	switch (type) {
    209	case SNDRV_DEVICE_TYPE_SEQUENCER:
    210	case SNDRV_DEVICE_TYPE_TIMER:
    211		minor = type;
    212		break;
    213	case SNDRV_DEVICE_TYPE_CONTROL:
    214		if (snd_BUG_ON(!card))
    215			return -EINVAL;
    216		minor = SNDRV_MINOR(card->number, type);
    217		break;
    218	case SNDRV_DEVICE_TYPE_HWDEP:
    219	case SNDRV_DEVICE_TYPE_RAWMIDI:
    220	case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
    221	case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
    222	case SNDRV_DEVICE_TYPE_COMPRESS:
    223		if (snd_BUG_ON(!card))
    224			return -EINVAL;
    225		minor = SNDRV_MINOR(card->number, type + dev);
    226		break;
    227	default:
    228		return -EINVAL;
    229	}
    230	if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS))
    231		return -EINVAL;
    232	if (snd_minors[minor])
    233		return -EBUSY;
    234	return minor;
    235}
    236#endif
    237
    238/**
    239 * snd_register_device - Register the ALSA device file for the card
    240 * @type: the device type, SNDRV_DEVICE_TYPE_XXX
    241 * @card: the card instance
    242 * @dev: the device index
    243 * @f_ops: the file operations
    244 * @private_data: user pointer for f_ops->open()
    245 * @device: the device to register
    246 *
    247 * Registers an ALSA device file for the given card.
    248 * The operators have to be set in reg parameter.
    249 *
    250 * Return: Zero if successful, or a negative error code on failure.
    251 */
    252int snd_register_device(int type, struct snd_card *card, int dev,
    253			const struct file_operations *f_ops,
    254			void *private_data, struct device *device)
    255{
    256	int minor;
    257	int err = 0;
    258	struct snd_minor *preg;
    259
    260	if (snd_BUG_ON(!device))
    261		return -EINVAL;
    262
    263	preg = kmalloc(sizeof *preg, GFP_KERNEL);
    264	if (preg == NULL)
    265		return -ENOMEM;
    266	preg->type = type;
    267	preg->card = card ? card->number : -1;
    268	preg->device = dev;
    269	preg->f_ops = f_ops;
    270	preg->private_data = private_data;
    271	preg->card_ptr = card;
    272	mutex_lock(&sound_mutex);
    273	minor = snd_find_free_minor(type, card, dev);
    274	if (minor < 0) {
    275		err = minor;
    276		goto error;
    277	}
    278
    279	preg->dev = device;
    280	device->devt = MKDEV(major, minor);
    281	err = device_add(device);
    282	if (err < 0)
    283		goto error;
    284
    285	snd_minors[minor] = preg;
    286 error:
    287	mutex_unlock(&sound_mutex);
    288	if (err < 0)
    289		kfree(preg);
    290	return err;
    291}
    292EXPORT_SYMBOL(snd_register_device);
    293
    294/**
    295 * snd_unregister_device - unregister the device on the given card
    296 * @dev: the device instance
    297 *
    298 * Unregisters the device file already registered via
    299 * snd_register_device().
    300 *
    301 * Return: Zero if successful, or a negative error code on failure.
    302 */
    303int snd_unregister_device(struct device *dev)
    304{
    305	int minor;
    306	struct snd_minor *preg;
    307
    308	mutex_lock(&sound_mutex);
    309	for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) {
    310		preg = snd_minors[minor];
    311		if (preg && preg->dev == dev) {
    312			snd_minors[minor] = NULL;
    313			device_del(dev);
    314			kfree(preg);
    315			break;
    316		}
    317	}
    318	mutex_unlock(&sound_mutex);
    319	if (minor >= ARRAY_SIZE(snd_minors))
    320		return -ENOENT;
    321	return 0;
    322}
    323EXPORT_SYMBOL(snd_unregister_device);
    324
    325#ifdef CONFIG_SND_PROC_FS
    326/*
    327 *  INFO PART
    328 */
    329static const char *snd_device_type_name(int type)
    330{
    331	switch (type) {
    332	case SNDRV_DEVICE_TYPE_CONTROL:
    333		return "control";
    334	case SNDRV_DEVICE_TYPE_HWDEP:
    335		return "hardware dependent";
    336	case SNDRV_DEVICE_TYPE_RAWMIDI:
    337		return "raw midi";
    338	case SNDRV_DEVICE_TYPE_PCM_PLAYBACK:
    339		return "digital audio playback";
    340	case SNDRV_DEVICE_TYPE_PCM_CAPTURE:
    341		return "digital audio capture";
    342	case SNDRV_DEVICE_TYPE_SEQUENCER:
    343		return "sequencer";
    344	case SNDRV_DEVICE_TYPE_TIMER:
    345		return "timer";
    346	case SNDRV_DEVICE_TYPE_COMPRESS:
    347		return "compress";
    348	default:
    349		return "?";
    350	}
    351}
    352
    353static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
    354{
    355	int minor;
    356	struct snd_minor *mptr;
    357
    358	mutex_lock(&sound_mutex);
    359	for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
    360		mptr = snd_minors[minor];
    361		if (!mptr)
    362			continue;
    363		if (mptr->card >= 0) {
    364			if (mptr->device >= 0)
    365				snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n",
    366					    minor, mptr->card, mptr->device,
    367					    snd_device_type_name(mptr->type));
    368			else
    369				snd_iprintf(buffer, "%3i: [%2i]   : %s\n",
    370					    minor, mptr->card,
    371					    snd_device_type_name(mptr->type));
    372		} else
    373			snd_iprintf(buffer, "%3i:        : %s\n", minor,
    374				    snd_device_type_name(mptr->type));
    375	}
    376	mutex_unlock(&sound_mutex);
    377}
    378
    379int __init snd_minor_info_init(void)
    380{
    381	struct snd_info_entry *entry;
    382
    383	entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
    384	if (!entry)
    385		return -ENOMEM;
    386	entry->c.text.read = snd_minor_info_read;
    387	return snd_info_register(entry); /* freed in error path */
    388}
    389#endif /* CONFIG_SND_PROC_FS */
    390
    391/*
    392 *  INIT PART
    393 */
    394
    395static int __init alsa_sound_init(void)
    396{
    397	snd_major = major;
    398	snd_ecards_limit = cards_limit;
    399	if (register_chrdev(major, "alsa", &snd_fops)) {
    400		pr_err("ALSA core: unable to register native major device number %d\n", major);
    401		return -EIO;
    402	}
    403	if (snd_info_init() < 0) {
    404		unregister_chrdev(major, "alsa");
    405		return -ENOMEM;
    406	}
    407
    408#ifdef CONFIG_SND_DEBUG
    409	sound_debugfs_root = debugfs_create_dir("sound", NULL);
    410#endif
    411#ifndef MODULE
    412	pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
    413#endif
    414	return 0;
    415}
    416
    417static void __exit alsa_sound_exit(void)
    418{
    419#ifdef CONFIG_SND_DEBUG
    420	debugfs_remove(sound_debugfs_root);
    421#endif
    422	snd_info_done();
    423	unregister_chrdev(major, "alsa");
    424}
    425
    426subsys_initcall(alsa_sound_init);
    427module_exit(alsa_sound_exit);