11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * Advanced Linux Sound Architecture 4c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 51da177e4SLinus Torvalds */ 61da177e4SLinus Torvalds 71da177e4SLinus Torvalds #include <linux/init.h> 81da177e4SLinus Torvalds #include <linux/slab.h> 91da177e4SLinus Torvalds #include <linux/time.h> 109a1a2a1dSTakashi Iwai #include <linux/device.h> 1165a77217SPaul Gortmaker #include <linux/module.h> 122d670ea2SHui Wang #include <linux/debugfs.h> 131da177e4SLinus Torvalds #include <sound/core.h> 141da177e4SLinus Torvalds #include <sound/minors.h> 151da177e4SLinus Torvalds #include <sound/info.h> 161da177e4SLinus Torvalds #include <sound/control.h> 171da177e4SLinus Torvalds #include <sound/initval.h> 181da177e4SLinus Torvalds #include <linux/kmod.h> 191a60d4c5SIngo Molnar #include <linux/mutex.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds static int major = CONFIG_SND_MAJOR; 221da177e4SLinus Torvalds int snd_major; 23c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_major); 24c0d3fb39STakashi Iwai 251da177e4SLinus Torvalds static int cards_limit = 1; 261da177e4SLinus Torvalds 27c1017a4cSJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 281da177e4SLinus Torvalds MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); 291da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 301da177e4SLinus Torvalds module_param(major, int, 0444); 311da177e4SLinus Torvalds MODULE_PARM_DESC(major, "Major # for sound driver."); 321da177e4SLinus Torvalds module_param(cards_limit, int, 0444); 331da177e4SLinus Torvalds MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); 341da177e4SLinus Torvalds MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds /* this one holds the actual max. card number currently available. 371da177e4SLinus Torvalds * as default, it's identical with cards_limit option. when more 381da177e4SLinus Torvalds * modules are loaded manually, this limit number increases, too. 391da177e4SLinus Torvalds */ 401da177e4SLinus Torvalds int snd_ecards_limit; 41c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_ecards_limit); 421da177e4SLinus Torvalds 432d670ea2SHui Wang #ifdef CONFIG_SND_DEBUG 442d670ea2SHui Wang struct dentry *sound_debugfs_root; 452d670ea2SHui Wang EXPORT_SYMBOL_GPL(sound_debugfs_root); 462d670ea2SHui Wang #endif 472d670ea2SHui Wang 486983b724SClemens Ladisch static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; 491a60d4c5SIngo Molnar static DEFINE_MUTEX(sound_mutex); 501da177e4SLinus Torvalds 51ee2da997SJohannes Berg #ifdef CONFIG_MODULES 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds /** 541da177e4SLinus Torvalds * snd_request_card - try to load the card module 551da177e4SLinus Torvalds * @card: the card number 561da177e4SLinus Torvalds * 571da177e4SLinus Torvalds * Tries to load the module "snd-card-X" for the given card number 58ee2da997SJohannes Berg * via request_module. Returns immediately if already loaded. 591da177e4SLinus Torvalds */ 601da177e4SLinus Torvalds void snd_request_card(int card) 611da177e4SLinus Torvalds { 62746df948STakashi Iwai if (snd_card_locked(card)) 631da177e4SLinus Torvalds return; 641da177e4SLinus Torvalds if (card < 0 || card >= cards_limit) 651da177e4SLinus Torvalds return; 661da177e4SLinus Torvalds request_module("snd-card-%i", card); 671da177e4SLinus Torvalds } 68c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_request_card); 69c0d3fb39STakashi Iwai 701da177e4SLinus Torvalds static void snd_request_other(int minor) 711da177e4SLinus Torvalds { 721da177e4SLinus Torvalds char *str; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds switch (minor) { 751da177e4SLinus Torvalds case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; 761da177e4SLinus Torvalds case SNDRV_MINOR_TIMER: str = "snd-timer"; break; 771da177e4SLinus Torvalds default: return; 781da177e4SLinus Torvalds } 791da177e4SLinus Torvalds request_module(str); 801da177e4SLinus Torvalds } 811da177e4SLinus Torvalds 82ee2da997SJohannes Berg #endif /* modular kernel */ 831da177e4SLinus Torvalds 84f87135f5SClemens Ladisch /** 85f87135f5SClemens Ladisch * snd_lookup_minor_data - get user data of a registered device 86f87135f5SClemens Ladisch * @minor: the minor number 87f87135f5SClemens Ladisch * @type: device type (SNDRV_DEVICE_TYPE_XXX) 88f87135f5SClemens Ladisch * 89f87135f5SClemens Ladisch * Checks that a minor device with the specified type is registered, and returns 90f87135f5SClemens Ladisch * its user data pointer. 91a0830dbdSTakashi Iwai * 92a0830dbdSTakashi Iwai * This function increments the reference counter of the card instance 93a0830dbdSTakashi Iwai * if an associated instance with the given minor number and type is found. 94a0830dbdSTakashi Iwai * The caller must call snd_card_unref() appropriately later. 95eb7c06e8SYacine Belkadi * 96eb7c06e8SYacine Belkadi * Return: The user data pointer if the specified device is found. %NULL 97eb7c06e8SYacine Belkadi * otherwise. 98f87135f5SClemens Ladisch */ 99f87135f5SClemens Ladisch void *snd_lookup_minor_data(unsigned int minor, int type) 100f87135f5SClemens Ladisch { 101f87135f5SClemens Ladisch struct snd_minor *mreg; 102f87135f5SClemens Ladisch void *private_data; 103f87135f5SClemens Ladisch 1043a63e444SAdrian Bunk if (minor >= ARRAY_SIZE(snd_minors)) 105f87135f5SClemens Ladisch return NULL; 1061a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 107f87135f5SClemens Ladisch mreg = snd_minors[minor]; 108a0830dbdSTakashi Iwai if (mreg && mreg->type == type) { 109f87135f5SClemens Ladisch private_data = mreg->private_data; 1108bb4d9ceSTakashi Iwai if (private_data && mreg->card_ptr) 111f2464064STakashi Iwai get_device(&mreg->card_ptr->card_dev); 112a0830dbdSTakashi Iwai } else 113f87135f5SClemens Ladisch private_data = NULL; 1141a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 115f87135f5SClemens Ladisch return private_data; 116f87135f5SClemens Ladisch } 117c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_lookup_minor_data); 118c0d3fb39STakashi Iwai 119ee2da997SJohannes Berg #ifdef CONFIG_MODULES 1204cf19b84STakashi Iwai static struct snd_minor *autoload_device(unsigned int minor) 1214cf19b84STakashi Iwai { 1224cf19b84STakashi Iwai int dev; 1234cf19b84STakashi Iwai mutex_unlock(&sound_mutex); /* release lock temporarily */ 1244cf19b84STakashi Iwai dev = SNDRV_MINOR_DEVICE(minor); 125332682b1SClemens Ladisch if (dev == SNDRV_MINOR_CONTROL) { 126332682b1SClemens Ladisch /* /dev/aloadC? */ 127332682b1SClemens Ladisch int card = SNDRV_MINOR_CARD(minor); 128f4fa9689STakashi Iwai struct snd_card *ref = snd_card_ref(card); 129f4fa9689STakashi Iwai if (!ref) 130332682b1SClemens Ladisch snd_request_card(card); 131f4fa9689STakashi Iwai else 132f4fa9689STakashi Iwai snd_card_unref(ref); 133332682b1SClemens Ladisch } else if (dev == SNDRV_MINOR_GLOBAL) { 134332682b1SClemens Ladisch /* /dev/aloadSEQ */ 1351da177e4SLinus Torvalds snd_request_other(minor); 1361da177e4SLinus Torvalds } 1374cf19b84STakashi Iwai mutex_lock(&sound_mutex); /* reacuire lock */ 1384cf19b84STakashi Iwai return snd_minors[minor]; 1394cf19b84STakashi Iwai } 1404cf19b84STakashi Iwai #else /* !CONFIG_MODULES */ 1414cf19b84STakashi Iwai #define autoload_device(minor) NULL 1424cf19b84STakashi Iwai #endif /* CONFIG_MODULES */ 1434cf19b84STakashi Iwai 1444cf19b84STakashi Iwai static int snd_open(struct inode *inode, struct file *file) 1454cf19b84STakashi Iwai { 1464cf19b84STakashi Iwai unsigned int minor = iminor(inode); 1474cf19b84STakashi Iwai struct snd_minor *mptr = NULL; 148e84f9e57SAl Viro const struct file_operations *new_fops; 1494cf19b84STakashi Iwai int err = 0; 1504cf19b84STakashi Iwai 1514cf19b84STakashi Iwai if (minor >= ARRAY_SIZE(snd_minors)) 1521da177e4SLinus Torvalds return -ENODEV; 1534cf19b84STakashi Iwai mutex_lock(&sound_mutex); 1544cf19b84STakashi Iwai mptr = snd_minors[minor]; 1554cf19b84STakashi Iwai if (mptr == NULL) { 1564cf19b84STakashi Iwai mptr = autoload_device(minor); 1574cf19b84STakashi Iwai if (!mptr) { 1584cf19b84STakashi Iwai mutex_unlock(&sound_mutex); 1594cf19b84STakashi Iwai return -ENODEV; 1604cf19b84STakashi Iwai } 161332682b1SClemens Ladisch } 162e84f9e57SAl Viro new_fops = fops_get(mptr->f_ops); 1634cf19b84STakashi Iwai mutex_unlock(&sound_mutex); 164e84f9e57SAl Viro if (!new_fops) 165e84f9e57SAl Viro return -ENODEV; 166e84f9e57SAl Viro replace_fops(file, new_fops); 1674cf19b84STakashi Iwai 168e84f9e57SAl Viro if (file->f_op->open) 1691da177e4SLinus Torvalds err = file->f_op->open(inode, file); 1701da177e4SLinus Torvalds return err; 1711da177e4SLinus Torvalds } 1721da177e4SLinus Torvalds 1739c2e08c5SArjan van de Ven static const struct file_operations snd_fops = 1741da177e4SLinus Torvalds { 1751da177e4SLinus Torvalds .owner = THIS_MODULE, 1766038f373SArnd Bergmann .open = snd_open, 1776038f373SArnd Bergmann .llseek = noop_llseek, 1781da177e4SLinus Torvalds }; 1791da177e4SLinus Torvalds 180332682b1SClemens Ladisch #ifdef CONFIG_SND_DYNAMIC_MINORS 18138ebb703STakashi Iwai static int snd_find_free_minor(int type, struct snd_card *card, int dev) 182332682b1SClemens Ladisch { 183332682b1SClemens Ladisch int minor; 184332682b1SClemens Ladisch 18503cfe6f5SKay Sievers /* static minors for module auto loading */ 18603cfe6f5SKay Sievers if (type == SNDRV_DEVICE_TYPE_SEQUENCER) 18703cfe6f5SKay Sievers return SNDRV_MINOR_SEQUENCER; 18803cfe6f5SKay Sievers if (type == SNDRV_DEVICE_TYPE_TIMER) 18903cfe6f5SKay Sievers return SNDRV_MINOR_TIMER; 19003cfe6f5SKay Sievers 191332682b1SClemens Ladisch for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { 19203cfe6f5SKay Sievers /* skip static minors still used for module auto loading */ 19303cfe6f5SKay Sievers if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL) 19403cfe6f5SKay Sievers continue; 19503cfe6f5SKay Sievers if (minor == SNDRV_MINOR_SEQUENCER || 19603cfe6f5SKay Sievers minor == SNDRV_MINOR_TIMER) 197332682b1SClemens Ladisch continue; 198332682b1SClemens Ladisch if (!snd_minors[minor]) 199332682b1SClemens Ladisch return minor; 200332682b1SClemens Ladisch } 201332682b1SClemens Ladisch return -EBUSY; 202332682b1SClemens Ladisch } 203332682b1SClemens Ladisch #else 20438ebb703STakashi Iwai static int snd_find_free_minor(int type, struct snd_card *card, int dev) 2051da177e4SLinus Torvalds { 2061da177e4SLinus Torvalds int minor; 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds switch (type) { 2091da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_SEQUENCER: 2101da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_TIMER: 2111da177e4SLinus Torvalds minor = type; 2121da177e4SLinus Torvalds break; 2131da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_CONTROL: 2147eaa943cSTakashi Iwai if (snd_BUG_ON(!card)) 2157eaa943cSTakashi Iwai return -EINVAL; 2161da177e4SLinus Torvalds minor = SNDRV_MINOR(card->number, type); 2171da177e4SLinus Torvalds break; 2181da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_HWDEP: 2191da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_RAWMIDI: 2201da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 2211da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 2223eafc959SOmair Mohammed Abdullah case SNDRV_DEVICE_TYPE_COMPRESS: 2237eaa943cSTakashi Iwai if (snd_BUG_ON(!card)) 2247eaa943cSTakashi Iwai return -EINVAL; 2251da177e4SLinus Torvalds minor = SNDRV_MINOR(card->number, type + dev); 2261da177e4SLinus Torvalds break; 2271da177e4SLinus Torvalds default: 2281da177e4SLinus Torvalds return -EINVAL; 2291da177e4SLinus Torvalds } 2307eaa943cSTakashi Iwai if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) 2317eaa943cSTakashi Iwai return -EINVAL; 23238ebb703STakashi Iwai if (snd_minors[minor]) 23338ebb703STakashi Iwai return -EBUSY; 2341da177e4SLinus Torvalds return minor; 2351da177e4SLinus Torvalds } 236332682b1SClemens Ladisch #endif 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds /** 23940a4b263STakashi Iwai * snd_register_device - Register the ALSA device file for the card 2401da177e4SLinus Torvalds * @type: the device type, SNDRV_DEVICE_TYPE_XXX 2411da177e4SLinus Torvalds * @card: the card instance 2421da177e4SLinus Torvalds * @dev: the device index 2432af677fcSClemens Ladisch * @f_ops: the file operations 244f87135f5SClemens Ladisch * @private_data: user pointer for f_ops->open() 24540a4b263STakashi Iwai * @device: the device to register 2461da177e4SLinus Torvalds * 2471da177e4SLinus Torvalds * Registers an ALSA device file for the given card. 2481da177e4SLinus Torvalds * The operators have to be set in reg parameter. 2491da177e4SLinus Torvalds * 250eb7c06e8SYacine Belkadi * Return: Zero if successful, or a negative error code on failure. 2511da177e4SLinus Torvalds */ 25240a4b263STakashi Iwai int snd_register_device(int type, struct snd_card *card, int dev, 25312b131c4SJohannes Berg const struct file_operations *f_ops, 25440a4b263STakashi Iwai void *private_data, struct device *device) 2551da177e4SLinus Torvalds { 256332682b1SClemens Ladisch int minor; 25792b7952dSTakashi Iwai int err = 0; 258512bbd6aSTakashi Iwai struct snd_minor *preg; 2591da177e4SLinus Torvalds 26040a4b263STakashi Iwai if (snd_BUG_ON(!device)) 26140a4b263STakashi Iwai return -EINVAL; 26240a4b263STakashi Iwai 263562b590dSClemens Ladisch preg = kmalloc(sizeof *preg, GFP_KERNEL); 2641da177e4SLinus Torvalds if (preg == NULL) 2651da177e4SLinus Torvalds return -ENOMEM; 2662af677fcSClemens Ladisch preg->type = type; 2676983b724SClemens Ladisch preg->card = card ? card->number : -1; 2681da177e4SLinus Torvalds preg->device = dev; 2692af677fcSClemens Ladisch preg->f_ops = f_ops; 270f87135f5SClemens Ladisch preg->private_data = private_data; 271a0830dbdSTakashi Iwai preg->card_ptr = card; 2721a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 27338ebb703STakashi Iwai minor = snd_find_free_minor(type, card, dev); 274332682b1SClemens Ladisch if (minor < 0) { 27592b7952dSTakashi Iwai err = minor; 27692b7952dSTakashi Iwai goto error; 2772469049eSMariusz Kozlowski } 2782469049eSMariusz Kozlowski 27992b7952dSTakashi Iwai preg->dev = device; 28092b7952dSTakashi Iwai device->devt = MKDEV(major, minor); 28192b7952dSTakashi Iwai err = device_add(device); 28292b7952dSTakashi Iwai if (err < 0) 28392b7952dSTakashi Iwai goto error; 28492b7952dSTakashi Iwai 28592b7952dSTakashi Iwai snd_minors[minor] = preg; 28692b7952dSTakashi Iwai error: 2871a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 28892b7952dSTakashi Iwai if (err < 0) 28992b7952dSTakashi Iwai kfree(preg); 29092b7952dSTakashi Iwai return err; 2911da177e4SLinus Torvalds } 29240a4b263STakashi Iwai EXPORT_SYMBOL(snd_register_device); 293c0d3fb39STakashi Iwai 2941da177e4SLinus Torvalds /** 2951da177e4SLinus Torvalds * snd_unregister_device - unregister the device on the given card 29640a4b263STakashi Iwai * @dev: the device instance 2971da177e4SLinus Torvalds * 2981da177e4SLinus Torvalds * Unregisters the device file already registered via 2991da177e4SLinus Torvalds * snd_register_device(). 3001da177e4SLinus Torvalds * 301eb7c06e8SYacine Belkadi * Return: Zero if successful, or a negative error code on failure. 3021da177e4SLinus Torvalds */ 30340a4b263STakashi Iwai int snd_unregister_device(struct device *dev) 3041da177e4SLinus Torvalds { 3059d19f48cSTakashi Iwai int minor; 30692b7952dSTakashi Iwai struct snd_minor *preg; 3071da177e4SLinus Torvalds 3081a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 30940a4b263STakashi Iwai for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { 31092b7952dSTakashi Iwai preg = snd_minors[minor]; 31140a4b263STakashi Iwai if (preg && preg->dev == dev) { 3126983b724SClemens Ladisch snd_minors[minor] = NULL; 31340a4b263STakashi Iwai device_del(dev); 31440a4b263STakashi Iwai kfree(preg); 31540a4b263STakashi Iwai break; 31640a4b263STakashi Iwai } 31740a4b263STakashi Iwai } 3181a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 31940a4b263STakashi Iwai if (minor >= ARRAY_SIZE(snd_minors)) 32040a4b263STakashi Iwai return -ENOENT; 3211da177e4SLinus Torvalds return 0; 3221da177e4SLinus Torvalds } 323c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_unregister_device); 324c0d3fb39STakashi Iwai 325cd6a6503SJie Yang #ifdef CONFIG_SND_PROC_FS 3261da177e4SLinus Torvalds /* 3271da177e4SLinus Torvalds * INFO PART 3281da177e4SLinus Torvalds */ 3292af677fcSClemens Ladisch static const char *snd_device_type_name(int type) 3302af677fcSClemens Ladisch { 3312af677fcSClemens Ladisch switch (type) { 3322af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_CONTROL: 3332af677fcSClemens Ladisch return "control"; 3342af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_HWDEP: 3352af677fcSClemens Ladisch return "hardware dependent"; 3362af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_RAWMIDI: 3372af677fcSClemens Ladisch return "raw midi"; 3382af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 3392af677fcSClemens Ladisch return "digital audio playback"; 3402af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 3412af677fcSClemens Ladisch return "digital audio capture"; 3422af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_SEQUENCER: 3432af677fcSClemens Ladisch return "sequencer"; 3442af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_TIMER: 3452af677fcSClemens Ladisch return "timer"; 3462c28156dSJaroslav Kysela case SNDRV_DEVICE_TYPE_COMPRESS: 3472c28156dSJaroslav Kysela return "compress"; 3482af677fcSClemens Ladisch default: 3492af677fcSClemens Ladisch return "?"; 3502af677fcSClemens Ladisch } 3512af677fcSClemens Ladisch } 3522af677fcSClemens Ladisch 353512bbd6aSTakashi Iwai static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 3541da177e4SLinus Torvalds { 3556983b724SClemens Ladisch int minor; 356512bbd6aSTakashi Iwai struct snd_minor *mptr; 3571da177e4SLinus Torvalds 3581a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 3596983b724SClemens Ladisch for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { 360*e3ded899STakashi Iwai mptr = snd_minors[minor]; 361*e3ded899STakashi Iwai if (!mptr) 3626983b724SClemens Ladisch continue; 3636983b724SClemens Ladisch if (mptr->card >= 0) { 3646983b724SClemens Ladisch if (mptr->device >= 0) 365d001544dSClemens Ladisch snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n", 3666983b724SClemens Ladisch minor, mptr->card, mptr->device, 3676983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3681da177e4SLinus Torvalds else 369d001544dSClemens Ladisch snd_iprintf(buffer, "%3i: [%2i] : %s\n", 3706983b724SClemens Ladisch minor, mptr->card, 3716983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3726983b724SClemens Ladisch } else 3736983b724SClemens Ladisch snd_iprintf(buffer, "%3i: : %s\n", minor, 3746983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3751da177e4SLinus Torvalds } 3761a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 3771da177e4SLinus Torvalds } 3781da177e4SLinus Torvalds 3791da177e4SLinus Torvalds int __init snd_minor_info_init(void) 3801da177e4SLinus Torvalds { 381512bbd6aSTakashi Iwai struct snd_info_entry *entry; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); 384b591b6e9STakashi Iwai if (!entry) 385b591b6e9STakashi Iwai return -ENOMEM; 3861da177e4SLinus Torvalds entry->c.text.read = snd_minor_info_read; 387b591b6e9STakashi Iwai return snd_info_register(entry); /* freed in error path */ 3881da177e4SLinus Torvalds } 389cd6a6503SJie Yang #endif /* CONFIG_SND_PROC_FS */ 3901da177e4SLinus Torvalds 3911da177e4SLinus Torvalds /* 3921da177e4SLinus Torvalds * INIT PART 3931da177e4SLinus Torvalds */ 3941da177e4SLinus Torvalds 3951da177e4SLinus Torvalds static int __init alsa_sound_init(void) 3961da177e4SLinus Torvalds { 3971da177e4SLinus Torvalds snd_major = major; 3981da177e4SLinus Torvalds snd_ecards_limit = cards_limit; 3991da177e4SLinus Torvalds if (register_chrdev(major, "alsa", &snd_fops)) { 400f2f9307aSTakashi Iwai pr_err("ALSA core: unable to register native major device number %d\n", major); 4011da177e4SLinus Torvalds return -EIO; 4021da177e4SLinus Torvalds } 4031da177e4SLinus Torvalds if (snd_info_init() < 0) { 4041da177e4SLinus Torvalds unregister_chrdev(major, "alsa"); 4051da177e4SLinus Torvalds return -ENOMEM; 4061da177e4SLinus Torvalds } 4072d670ea2SHui Wang 4082d670ea2SHui Wang #ifdef CONFIG_SND_DEBUG 4092d670ea2SHui Wang sound_debugfs_root = debugfs_create_dir("sound", NULL); 4102d670ea2SHui Wang #endif 4111da177e4SLinus Torvalds #ifndef MODULE 412f2f9307aSTakashi Iwai pr_info("Advanced Linux Sound Architecture Driver Initialized.\n"); 4131da177e4SLinus Torvalds #endif 4141da177e4SLinus Torvalds return 0; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds static void __exit alsa_sound_exit(void) 4181da177e4SLinus Torvalds { 4192d670ea2SHui Wang #ifdef CONFIG_SND_DEBUG 4202d670ea2SHui Wang debugfs_remove(sound_debugfs_root); 4212d670ea2SHui Wang #endif 4221da177e4SLinus Torvalds snd_info_done(); 42368fc4fabSAkinobu Mita unregister_chrdev(major, "alsa"); 4241da177e4SLinus Torvalds } 4251da177e4SLinus Torvalds 426c181a13aSThadeu Lima de Souza Cascardo subsys_initcall(alsa_sound_init); 427c181a13aSThadeu Lima de Souza Cascardo module_exit(alsa_sound_exit); 428