11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Advanced Linux Sound Architecture 3c1017a4cSJaroslav Kysela * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 71da177e4SLinus Torvalds * it under the terms of the GNU General Public License as published by 81da177e4SLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 91da177e4SLinus Torvalds * (at your option) any later version. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * This program is distributed in the hope that it will be useful, 121da177e4SLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 131da177e4SLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 141da177e4SLinus Torvalds * GNU General Public License for more details. 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * You should have received a copy of the GNU General Public License 171da177e4SLinus Torvalds * along with this program; if not, write to the Free Software 181da177e4SLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 191da177e4SLinus Torvalds * 201da177e4SLinus Torvalds */ 211da177e4SLinus Torvalds 221da177e4SLinus Torvalds #include <linux/init.h> 231da177e4SLinus Torvalds #include <linux/slab.h> 241da177e4SLinus Torvalds #include <linux/time.h> 259a1a2a1dSTakashi Iwai #include <linux/device.h> 2665a77217SPaul Gortmaker #include <linux/module.h> 271da177e4SLinus Torvalds #include <sound/core.h> 281da177e4SLinus Torvalds #include <sound/minors.h> 291da177e4SLinus Torvalds #include <sound/info.h> 301da177e4SLinus Torvalds #include <sound/control.h> 311da177e4SLinus Torvalds #include <sound/initval.h> 321da177e4SLinus Torvalds #include <linux/kmod.h> 331a60d4c5SIngo Molnar #include <linux/mutex.h> 341da177e4SLinus Torvalds 351da177e4SLinus Torvalds static int major = CONFIG_SND_MAJOR; 361da177e4SLinus Torvalds int snd_major; 37c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_major); 38c0d3fb39STakashi Iwai 391da177e4SLinus Torvalds static int cards_limit = 1; 401da177e4SLinus Torvalds 41c1017a4cSJaroslav Kysela MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 421da177e4SLinus Torvalds MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); 431da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 441da177e4SLinus Torvalds module_param(major, int, 0444); 451da177e4SLinus Torvalds MODULE_PARM_DESC(major, "Major # for sound driver."); 461da177e4SLinus Torvalds module_param(cards_limit, int, 0444); 471da177e4SLinus Torvalds MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); 481da177e4SLinus Torvalds MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); 491da177e4SLinus Torvalds 501da177e4SLinus Torvalds /* this one holds the actual max. card number currently available. 511da177e4SLinus Torvalds * as default, it's identical with cards_limit option. when more 521da177e4SLinus Torvalds * modules are loaded manually, this limit number increases, too. 531da177e4SLinus Torvalds */ 541da177e4SLinus Torvalds int snd_ecards_limit; 55c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_ecards_limit); 561da177e4SLinus Torvalds 576983b724SClemens Ladisch static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; 581a60d4c5SIngo Molnar static DEFINE_MUTEX(sound_mutex); 591da177e4SLinus Torvalds 60ee2da997SJohannes Berg #ifdef CONFIG_MODULES 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds /** 631da177e4SLinus Torvalds * snd_request_card - try to load the card module 641da177e4SLinus Torvalds * @card: the card number 651da177e4SLinus Torvalds * 661da177e4SLinus Torvalds * Tries to load the module "snd-card-X" for the given card number 67ee2da997SJohannes Berg * via request_module. Returns immediately if already loaded. 681da177e4SLinus Torvalds */ 691da177e4SLinus Torvalds void snd_request_card(int card) 701da177e4SLinus Torvalds { 71746df948STakashi Iwai if (snd_card_locked(card)) 721da177e4SLinus Torvalds return; 731da177e4SLinus Torvalds if (card < 0 || card >= cards_limit) 741da177e4SLinus Torvalds return; 751da177e4SLinus Torvalds request_module("snd-card-%i", card); 761da177e4SLinus Torvalds } 771da177e4SLinus Torvalds 78c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_request_card); 79c0d3fb39STakashi Iwai 801da177e4SLinus Torvalds static void snd_request_other(int minor) 811da177e4SLinus Torvalds { 821da177e4SLinus Torvalds char *str; 831da177e4SLinus Torvalds 841da177e4SLinus Torvalds switch (minor) { 851da177e4SLinus Torvalds case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; 861da177e4SLinus Torvalds case SNDRV_MINOR_TIMER: str = "snd-timer"; break; 871da177e4SLinus Torvalds default: return; 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds request_module(str); 901da177e4SLinus Torvalds } 911da177e4SLinus Torvalds 92ee2da997SJohannes Berg #endif /* modular kernel */ 931da177e4SLinus Torvalds 94f87135f5SClemens Ladisch /** 95f87135f5SClemens Ladisch * snd_lookup_minor_data - get user data of a registered device 96f87135f5SClemens Ladisch * @minor: the minor number 97f87135f5SClemens Ladisch * @type: device type (SNDRV_DEVICE_TYPE_XXX) 98f87135f5SClemens Ladisch * 99f87135f5SClemens Ladisch * Checks that a minor device with the specified type is registered, and returns 100f87135f5SClemens Ladisch * its user data pointer. 101a0830dbdSTakashi Iwai * 102a0830dbdSTakashi Iwai * This function increments the reference counter of the card instance 103a0830dbdSTakashi Iwai * if an associated instance with the given minor number and type is found. 104a0830dbdSTakashi Iwai * The caller must call snd_card_unref() appropriately later. 105eb7c06e8SYacine Belkadi * 106eb7c06e8SYacine Belkadi * Return: The user data pointer if the specified device is found. %NULL 107eb7c06e8SYacine Belkadi * otherwise. 108f87135f5SClemens Ladisch */ 109f87135f5SClemens Ladisch void *snd_lookup_minor_data(unsigned int minor, int type) 110f87135f5SClemens Ladisch { 111f87135f5SClemens Ladisch struct snd_minor *mreg; 112f87135f5SClemens Ladisch void *private_data; 113f87135f5SClemens Ladisch 1143a63e444SAdrian Bunk if (minor >= ARRAY_SIZE(snd_minors)) 115f87135f5SClemens Ladisch return NULL; 1161a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 117f87135f5SClemens Ladisch mreg = snd_minors[minor]; 118a0830dbdSTakashi Iwai if (mreg && mreg->type == type) { 119f87135f5SClemens Ladisch private_data = mreg->private_data; 1208bb4d9ceSTakashi Iwai if (private_data && mreg->card_ptr) 121f2464064STakashi Iwai get_device(&mreg->card_ptr->card_dev); 122a0830dbdSTakashi Iwai } else 123f87135f5SClemens Ladisch private_data = NULL; 1241a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 125f87135f5SClemens Ladisch return private_data; 126f87135f5SClemens Ladisch } 127f87135f5SClemens Ladisch 128c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_lookup_minor_data); 129c0d3fb39STakashi Iwai 130ee2da997SJohannes Berg #ifdef CONFIG_MODULES 1314cf19b84STakashi Iwai static struct snd_minor *autoload_device(unsigned int minor) 1324cf19b84STakashi Iwai { 1334cf19b84STakashi Iwai int dev; 1344cf19b84STakashi Iwai mutex_unlock(&sound_mutex); /* release lock temporarily */ 1354cf19b84STakashi Iwai dev = SNDRV_MINOR_DEVICE(minor); 136332682b1SClemens Ladisch if (dev == SNDRV_MINOR_CONTROL) { 137332682b1SClemens Ladisch /* /dev/aloadC? */ 138332682b1SClemens Ladisch int card = SNDRV_MINOR_CARD(minor); 1391da177e4SLinus Torvalds if (snd_cards[card] == NULL) 140332682b1SClemens Ladisch snd_request_card(card); 141332682b1SClemens Ladisch } else if (dev == SNDRV_MINOR_GLOBAL) { 142332682b1SClemens Ladisch /* /dev/aloadSEQ */ 1431da177e4SLinus Torvalds snd_request_other(minor); 1441da177e4SLinus Torvalds } 1454cf19b84STakashi Iwai mutex_lock(&sound_mutex); /* reacuire lock */ 1464cf19b84STakashi Iwai return snd_minors[minor]; 1474cf19b84STakashi Iwai } 1484cf19b84STakashi Iwai #else /* !CONFIG_MODULES */ 1494cf19b84STakashi Iwai #define autoload_device(minor) NULL 1504cf19b84STakashi Iwai #endif /* CONFIG_MODULES */ 1514cf19b84STakashi Iwai 1524cf19b84STakashi Iwai static int snd_open(struct inode *inode, struct file *file) 1534cf19b84STakashi Iwai { 1544cf19b84STakashi Iwai unsigned int minor = iminor(inode); 1554cf19b84STakashi Iwai struct snd_minor *mptr = NULL; 156e84f9e57SAl Viro const struct file_operations *new_fops; 1574cf19b84STakashi Iwai int err = 0; 1584cf19b84STakashi Iwai 1594cf19b84STakashi Iwai if (minor >= ARRAY_SIZE(snd_minors)) 1601da177e4SLinus Torvalds return -ENODEV; 1614cf19b84STakashi Iwai mutex_lock(&sound_mutex); 1624cf19b84STakashi Iwai mptr = snd_minors[minor]; 1634cf19b84STakashi Iwai if (mptr == NULL) { 1644cf19b84STakashi Iwai mptr = autoload_device(minor); 1654cf19b84STakashi Iwai if (!mptr) { 1664cf19b84STakashi Iwai mutex_unlock(&sound_mutex); 1674cf19b84STakashi Iwai return -ENODEV; 1684cf19b84STakashi Iwai } 169332682b1SClemens Ladisch } 170e84f9e57SAl Viro new_fops = fops_get(mptr->f_ops); 1714cf19b84STakashi Iwai mutex_unlock(&sound_mutex); 172e84f9e57SAl Viro if (!new_fops) 173e84f9e57SAl Viro return -ENODEV; 174e84f9e57SAl Viro replace_fops(file, new_fops); 1754cf19b84STakashi Iwai 176e84f9e57SAl Viro if (file->f_op->open) 1771da177e4SLinus Torvalds err = file->f_op->open(inode, file); 1781da177e4SLinus Torvalds return err; 1791da177e4SLinus Torvalds } 1801da177e4SLinus Torvalds 1819c2e08c5SArjan van de Ven static const struct file_operations snd_fops = 1821da177e4SLinus Torvalds { 1831da177e4SLinus Torvalds .owner = THIS_MODULE, 1846038f373SArnd Bergmann .open = snd_open, 1856038f373SArnd Bergmann .llseek = noop_llseek, 1861da177e4SLinus Torvalds }; 1871da177e4SLinus Torvalds 188332682b1SClemens Ladisch #ifdef CONFIG_SND_DYNAMIC_MINORS 18938ebb703STakashi Iwai static int snd_find_free_minor(int type, struct snd_card *card, int dev) 190332682b1SClemens Ladisch { 191332682b1SClemens Ladisch int minor; 192332682b1SClemens Ladisch 19303cfe6f5SKay Sievers /* static minors for module auto loading */ 19403cfe6f5SKay Sievers if (type == SNDRV_DEVICE_TYPE_SEQUENCER) 19503cfe6f5SKay Sievers return SNDRV_MINOR_SEQUENCER; 19603cfe6f5SKay Sievers if (type == SNDRV_DEVICE_TYPE_TIMER) 19703cfe6f5SKay Sievers return SNDRV_MINOR_TIMER; 19803cfe6f5SKay Sievers 199332682b1SClemens Ladisch for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { 20003cfe6f5SKay Sievers /* skip static minors still used for module auto loading */ 20103cfe6f5SKay Sievers if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL) 20203cfe6f5SKay Sievers continue; 20303cfe6f5SKay Sievers if (minor == SNDRV_MINOR_SEQUENCER || 20403cfe6f5SKay Sievers minor == SNDRV_MINOR_TIMER) 205332682b1SClemens Ladisch continue; 206332682b1SClemens Ladisch if (!snd_minors[minor]) 207332682b1SClemens Ladisch return minor; 208332682b1SClemens Ladisch } 209332682b1SClemens Ladisch return -EBUSY; 210332682b1SClemens Ladisch } 211332682b1SClemens Ladisch #else 21238ebb703STakashi Iwai static int snd_find_free_minor(int type, struct snd_card *card, int dev) 2131da177e4SLinus Torvalds { 2141da177e4SLinus Torvalds int minor; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds switch (type) { 2171da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_SEQUENCER: 2181da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_TIMER: 2191da177e4SLinus Torvalds minor = type; 2201da177e4SLinus Torvalds break; 2211da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_CONTROL: 2227eaa943cSTakashi Iwai if (snd_BUG_ON(!card)) 2237eaa943cSTakashi Iwai return -EINVAL; 2241da177e4SLinus Torvalds minor = SNDRV_MINOR(card->number, type); 2251da177e4SLinus Torvalds break; 2261da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_HWDEP: 2271da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_RAWMIDI: 2281da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 2291da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 2303eafc959SOmair Mohammed Abdullah case SNDRV_DEVICE_TYPE_COMPRESS: 2317eaa943cSTakashi Iwai if (snd_BUG_ON(!card)) 2327eaa943cSTakashi Iwai return -EINVAL; 2331da177e4SLinus Torvalds minor = SNDRV_MINOR(card->number, type + dev); 2341da177e4SLinus Torvalds break; 2351da177e4SLinus Torvalds default: 2361da177e4SLinus Torvalds return -EINVAL; 2371da177e4SLinus Torvalds } 2387eaa943cSTakashi Iwai if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) 2397eaa943cSTakashi Iwai return -EINVAL; 24038ebb703STakashi Iwai if (snd_minors[minor]) 24138ebb703STakashi Iwai return -EBUSY; 2421da177e4SLinus Torvalds return minor; 2431da177e4SLinus Torvalds } 244332682b1SClemens Ladisch #endif 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds /** 24740a4b263STakashi Iwai * snd_register_device - Register the ALSA device file for the card 2481da177e4SLinus Torvalds * @type: the device type, SNDRV_DEVICE_TYPE_XXX 2491da177e4SLinus Torvalds * @card: the card instance 2501da177e4SLinus Torvalds * @dev: the device index 2512af677fcSClemens Ladisch * @f_ops: the file operations 252f87135f5SClemens Ladisch * @private_data: user pointer for f_ops->open() 25340a4b263STakashi Iwai * @device: the device to register 2541da177e4SLinus Torvalds * 2551da177e4SLinus Torvalds * Registers an ALSA device file for the given card. 2561da177e4SLinus Torvalds * The operators have to be set in reg parameter. 2571da177e4SLinus Torvalds * 258eb7c06e8SYacine Belkadi * Return: Zero if successful, or a negative error code on failure. 2591da177e4SLinus Torvalds */ 26040a4b263STakashi Iwai int snd_register_device(int type, struct snd_card *card, int dev, 26112b131c4SJohannes Berg const struct file_operations *f_ops, 26240a4b263STakashi Iwai void *private_data, struct device *device) 2631da177e4SLinus Torvalds { 264332682b1SClemens Ladisch int minor; 26592b7952dSTakashi Iwai int err = 0; 266512bbd6aSTakashi Iwai struct snd_minor *preg; 2671da177e4SLinus Torvalds 26840a4b263STakashi Iwai if (snd_BUG_ON(!device)) 26940a4b263STakashi Iwai return -EINVAL; 27040a4b263STakashi Iwai 271562b590dSClemens Ladisch preg = kmalloc(sizeof *preg, GFP_KERNEL); 2721da177e4SLinus Torvalds if (preg == NULL) 2731da177e4SLinus Torvalds return -ENOMEM; 2742af677fcSClemens Ladisch preg->type = type; 2756983b724SClemens Ladisch preg->card = card ? card->number : -1; 2761da177e4SLinus Torvalds preg->device = dev; 2772af677fcSClemens Ladisch preg->f_ops = f_ops; 278f87135f5SClemens Ladisch preg->private_data = private_data; 279a0830dbdSTakashi Iwai preg->card_ptr = card; 2801a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 28138ebb703STakashi Iwai minor = snd_find_free_minor(type, card, dev); 282332682b1SClemens Ladisch if (minor < 0) { 28392b7952dSTakashi Iwai err = minor; 28492b7952dSTakashi Iwai goto error; 2852469049eSMariusz Kozlowski } 2862469049eSMariusz Kozlowski 28792b7952dSTakashi Iwai preg->dev = device; 28892b7952dSTakashi Iwai device->devt = MKDEV(major, minor); 28992b7952dSTakashi Iwai err = device_add(device); 29092b7952dSTakashi Iwai if (err < 0) 29192b7952dSTakashi Iwai goto error; 29292b7952dSTakashi Iwai 29392b7952dSTakashi Iwai snd_minors[minor] = preg; 29492b7952dSTakashi Iwai error: 2951a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 29692b7952dSTakashi Iwai if (err < 0) 29792b7952dSTakashi Iwai kfree(preg); 29892b7952dSTakashi Iwai return err; 2991da177e4SLinus Torvalds } 30040a4b263STakashi Iwai EXPORT_SYMBOL(snd_register_device); 301c0d3fb39STakashi Iwai 3021da177e4SLinus Torvalds /** 3031da177e4SLinus Torvalds * snd_unregister_device - unregister the device on the given card 30440a4b263STakashi Iwai * @dev: the device instance 3051da177e4SLinus Torvalds * 3061da177e4SLinus Torvalds * Unregisters the device file already registered via 3071da177e4SLinus Torvalds * snd_register_device(). 3081da177e4SLinus Torvalds * 309eb7c06e8SYacine Belkadi * Return: Zero if successful, or a negative error code on failure. 3101da177e4SLinus Torvalds */ 31140a4b263STakashi Iwai int snd_unregister_device(struct device *dev) 3121da177e4SLinus Torvalds { 3139d19f48cSTakashi Iwai int minor; 31492b7952dSTakashi Iwai struct snd_minor *preg; 3151da177e4SLinus Torvalds 3161a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 31740a4b263STakashi Iwai for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { 31892b7952dSTakashi Iwai preg = snd_minors[minor]; 31940a4b263STakashi Iwai if (preg && preg->dev == dev) { 3206983b724SClemens Ladisch snd_minors[minor] = NULL; 32140a4b263STakashi Iwai device_del(dev); 32240a4b263STakashi Iwai kfree(preg); 32340a4b263STakashi Iwai break; 32440a4b263STakashi Iwai } 32540a4b263STakashi Iwai } 3261a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 32740a4b263STakashi Iwai if (minor >= ARRAY_SIZE(snd_minors)) 32840a4b263STakashi Iwai return -ENOENT; 3291da177e4SLinus Torvalds return 0; 3301da177e4SLinus Torvalds } 331c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_unregister_device); 332c0d3fb39STakashi Iwai 333*cd6a6503SJie Yang #ifdef CONFIG_SND_PROC_FS 3341da177e4SLinus Torvalds /* 3351da177e4SLinus Torvalds * INFO PART 3361da177e4SLinus Torvalds */ 3372af677fcSClemens Ladisch static const char *snd_device_type_name(int type) 3382af677fcSClemens Ladisch { 3392af677fcSClemens Ladisch switch (type) { 3402af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_CONTROL: 3412af677fcSClemens Ladisch return "control"; 3422af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_HWDEP: 3432af677fcSClemens Ladisch return "hardware dependent"; 3442af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_RAWMIDI: 3452af677fcSClemens Ladisch return "raw midi"; 3462af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 3472af677fcSClemens Ladisch return "digital audio playback"; 3482af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 3492af677fcSClemens Ladisch return "digital audio capture"; 3502af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_SEQUENCER: 3512af677fcSClemens Ladisch return "sequencer"; 3522af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_TIMER: 3532af677fcSClemens Ladisch return "timer"; 3542af677fcSClemens Ladisch default: 3552af677fcSClemens Ladisch return "?"; 3562af677fcSClemens Ladisch } 3572af677fcSClemens Ladisch } 3582af677fcSClemens Ladisch 359512bbd6aSTakashi Iwai static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 3601da177e4SLinus Torvalds { 3616983b724SClemens Ladisch int minor; 362512bbd6aSTakashi Iwai struct snd_minor *mptr; 3631da177e4SLinus Torvalds 3641a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 3656983b724SClemens Ladisch for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { 3666983b724SClemens Ladisch if (!(mptr = snd_minors[minor])) 3676983b724SClemens Ladisch continue; 3686983b724SClemens Ladisch if (mptr->card >= 0) { 3696983b724SClemens Ladisch if (mptr->device >= 0) 370d001544dSClemens Ladisch snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n", 3716983b724SClemens Ladisch minor, mptr->card, mptr->device, 3726983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3731da177e4SLinus Torvalds else 374d001544dSClemens Ladisch snd_iprintf(buffer, "%3i: [%2i] : %s\n", 3756983b724SClemens Ladisch minor, mptr->card, 3766983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3776983b724SClemens Ladisch } else 3786983b724SClemens Ladisch snd_iprintf(buffer, "%3i: : %s\n", minor, 3796983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3801da177e4SLinus Torvalds } 3811a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 3821da177e4SLinus Torvalds } 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds int __init snd_minor_info_init(void) 3851da177e4SLinus Torvalds { 386512bbd6aSTakashi Iwai struct snd_info_entry *entry; 3871da177e4SLinus Torvalds 3881da177e4SLinus Torvalds entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); 389b591b6e9STakashi Iwai if (!entry) 390b591b6e9STakashi Iwai return -ENOMEM; 3911da177e4SLinus Torvalds entry->c.text.read = snd_minor_info_read; 392b591b6e9STakashi Iwai return snd_info_register(entry); /* freed in error path */ 3931da177e4SLinus Torvalds } 394*cd6a6503SJie Yang #endif /* CONFIG_SND_PROC_FS */ 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds /* 3971da177e4SLinus Torvalds * INIT PART 3981da177e4SLinus Torvalds */ 3991da177e4SLinus Torvalds 4001da177e4SLinus Torvalds static int __init alsa_sound_init(void) 4011da177e4SLinus Torvalds { 4021da177e4SLinus Torvalds snd_major = major; 4031da177e4SLinus Torvalds snd_ecards_limit = cards_limit; 4041da177e4SLinus Torvalds if (register_chrdev(major, "alsa", &snd_fops)) { 405f2f9307aSTakashi Iwai pr_err("ALSA core: unable to register native major device number %d\n", major); 4061da177e4SLinus Torvalds return -EIO; 4071da177e4SLinus Torvalds } 4081da177e4SLinus Torvalds if (snd_info_init() < 0) { 4091da177e4SLinus Torvalds unregister_chrdev(major, "alsa"); 4101da177e4SLinus Torvalds return -ENOMEM; 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds #ifndef MODULE 413f2f9307aSTakashi Iwai pr_info("Advanced Linux Sound Architecture Driver Initialized.\n"); 4141da177e4SLinus Torvalds #endif 4151da177e4SLinus Torvalds return 0; 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 4181da177e4SLinus Torvalds static void __exit alsa_sound_exit(void) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds snd_info_done(); 42168fc4fabSAkinobu Mita unregister_chrdev(major, "alsa"); 4221da177e4SLinus Torvalds } 4231da177e4SLinus Torvalds 424c181a13aSThadeu Lima de Souza Cascardo subsys_initcall(alsa_sound_init); 425c181a13aSThadeu Lima de Souza Cascardo module_exit(alsa_sound_exit); 426