11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * Advanced Linux Sound Architecture 31da177e4SLinus Torvalds * Copyright (c) by Jaroslav Kysela <perex@suse.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 <sound/driver.h> 231da177e4SLinus Torvalds #include <linux/init.h> 241da177e4SLinus Torvalds #include <linux/slab.h> 251da177e4SLinus Torvalds #include <linux/time.h> 269a1a2a1dSTakashi Iwai #include <linux/device.h> 271da177e4SLinus Torvalds #include <linux/moduleparam.h> 281da177e4SLinus Torvalds #include <sound/core.h> 291da177e4SLinus Torvalds #include <sound/minors.h> 301da177e4SLinus Torvalds #include <sound/info.h> 311da177e4SLinus Torvalds #include <sound/version.h> 321da177e4SLinus Torvalds #include <sound/control.h> 331da177e4SLinus Torvalds #include <sound/initval.h> 341da177e4SLinus Torvalds #include <linux/kmod.h> 351a60d4c5SIngo Molnar #include <linux/mutex.h> 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds #define SNDRV_OS_MINORS 256 381da177e4SLinus Torvalds 391da177e4SLinus Torvalds static int major = CONFIG_SND_MAJOR; 401da177e4SLinus Torvalds int snd_major; 41c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_major); 42c0d3fb39STakashi Iwai 431da177e4SLinus Torvalds static int cards_limit = 1; 441da177e4SLinus Torvalds 451da177e4SLinus Torvalds MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 461da177e4SLinus Torvalds MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); 471da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 481da177e4SLinus Torvalds module_param(major, int, 0444); 491da177e4SLinus Torvalds MODULE_PARM_DESC(major, "Major # for sound driver."); 501da177e4SLinus Torvalds module_param(cards_limit, int, 0444); 511da177e4SLinus Torvalds MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); 521da177e4SLinus Torvalds MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); 531da177e4SLinus Torvalds 541da177e4SLinus Torvalds /* this one holds the actual max. card number currently available. 551da177e4SLinus Torvalds * as default, it's identical with cards_limit option. when more 561da177e4SLinus Torvalds * modules are loaded manually, this limit number increases, too. 571da177e4SLinus Torvalds */ 581da177e4SLinus Torvalds int snd_ecards_limit; 59c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_ecards_limit); 601da177e4SLinus Torvalds 616983b724SClemens Ladisch static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; 621a60d4c5SIngo Molnar static DEFINE_MUTEX(sound_mutex); 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds #ifdef CONFIG_KMOD 651da177e4SLinus Torvalds 661da177e4SLinus Torvalds /** 671da177e4SLinus Torvalds * snd_request_card - try to load the card module 681da177e4SLinus Torvalds * @card: the card number 691da177e4SLinus Torvalds * 701da177e4SLinus Torvalds * Tries to load the module "snd-card-X" for the given card number 711da177e4SLinus Torvalds * via KMOD. Returns immediately if already loaded. 721da177e4SLinus Torvalds */ 731da177e4SLinus Torvalds void snd_request_card(int card) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds if (! current->fs->root) 761da177e4SLinus Torvalds return; 77746df948STakashi Iwai if (snd_card_locked(card)) 781da177e4SLinus Torvalds return; 791da177e4SLinus Torvalds if (card < 0 || card >= cards_limit) 801da177e4SLinus Torvalds return; 811da177e4SLinus Torvalds request_module("snd-card-%i", card); 821da177e4SLinus Torvalds } 831da177e4SLinus Torvalds 84c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_request_card); 85c0d3fb39STakashi Iwai 861da177e4SLinus Torvalds static void snd_request_other(int minor) 871da177e4SLinus Torvalds { 881da177e4SLinus Torvalds char *str; 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds if (! current->fs->root) 911da177e4SLinus Torvalds return; 921da177e4SLinus Torvalds switch (minor) { 931da177e4SLinus Torvalds case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; 941da177e4SLinus Torvalds case SNDRV_MINOR_TIMER: str = "snd-timer"; break; 951da177e4SLinus Torvalds default: return; 961da177e4SLinus Torvalds } 971da177e4SLinus Torvalds request_module(str); 981da177e4SLinus Torvalds } 991da177e4SLinus Torvalds 1001da177e4SLinus Torvalds #endif /* request_module support */ 1011da177e4SLinus Torvalds 102f87135f5SClemens Ladisch /** 103f87135f5SClemens Ladisch * snd_lookup_minor_data - get user data of a registered device 104f87135f5SClemens Ladisch * @minor: the minor number 105f87135f5SClemens Ladisch * @type: device type (SNDRV_DEVICE_TYPE_XXX) 106f87135f5SClemens Ladisch * 107f87135f5SClemens Ladisch * Checks that a minor device with the specified type is registered, and returns 108f87135f5SClemens Ladisch * its user data pointer. 109f87135f5SClemens Ladisch */ 110f87135f5SClemens Ladisch void *snd_lookup_minor_data(unsigned int minor, int type) 111f87135f5SClemens Ladisch { 112f87135f5SClemens Ladisch struct snd_minor *mreg; 113f87135f5SClemens Ladisch void *private_data; 114f87135f5SClemens Ladisch 1153a63e444SAdrian Bunk if (minor >= ARRAY_SIZE(snd_minors)) 116f87135f5SClemens Ladisch return NULL; 1171a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 118f87135f5SClemens Ladisch mreg = snd_minors[minor]; 119f87135f5SClemens Ladisch if (mreg && mreg->type == type) 120f87135f5SClemens Ladisch private_data = mreg->private_data; 121f87135f5SClemens Ladisch else 122f87135f5SClemens Ladisch private_data = NULL; 1231a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 124f87135f5SClemens Ladisch return private_data; 125f87135f5SClemens Ladisch } 126f87135f5SClemens Ladisch 127c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_lookup_minor_data); 128c0d3fb39STakashi Iwai 1291da177e4SLinus Torvalds static int snd_open(struct inode *inode, struct file *file) 1301da177e4SLinus Torvalds { 131332682b1SClemens Ladisch unsigned int minor = iminor(inode); 132512bbd6aSTakashi Iwai struct snd_minor *mptr = NULL; 13399ac48f5SArjan van de Ven const struct file_operations *old_fops; 1341da177e4SLinus Torvalds int err = 0; 1351da177e4SLinus Torvalds 1363a63e444SAdrian Bunk if (minor >= ARRAY_SIZE(snd_minors)) 137332682b1SClemens Ladisch return -ENODEV; 138332682b1SClemens Ladisch mptr = snd_minors[minor]; 139332682b1SClemens Ladisch if (mptr == NULL) { 1401da177e4SLinus Torvalds #ifdef CONFIG_KMOD 141332682b1SClemens Ladisch int dev = SNDRV_MINOR_DEVICE(minor); 142332682b1SClemens Ladisch if (dev == SNDRV_MINOR_CONTROL) { 143332682b1SClemens Ladisch /* /dev/aloadC? */ 144332682b1SClemens Ladisch int card = SNDRV_MINOR_CARD(minor); 1451da177e4SLinus Torvalds if (snd_cards[card] == NULL) 146332682b1SClemens Ladisch snd_request_card(card); 147332682b1SClemens Ladisch } else if (dev == SNDRV_MINOR_GLOBAL) { 148332682b1SClemens Ladisch /* /dev/aloadSEQ */ 1491da177e4SLinus Torvalds snd_request_other(minor); 1501da177e4SLinus Torvalds } 151332682b1SClemens Ladisch #ifndef CONFIG_SND_DYNAMIC_MINORS 152332682b1SClemens Ladisch /* /dev/snd/{controlC?,seq} */ 153332682b1SClemens Ladisch mptr = snd_minors[minor]; 154332682b1SClemens Ladisch if (mptr == NULL) 155332682b1SClemens Ladisch #endif 156332682b1SClemens Ladisch #endif 1571da177e4SLinus Torvalds return -ENODEV; 158332682b1SClemens Ladisch } 1591da177e4SLinus Torvalds old_fops = file->f_op; 1601da177e4SLinus Torvalds file->f_op = fops_get(mptr->f_ops); 1611da177e4SLinus Torvalds if (file->f_op->open) 1621da177e4SLinus Torvalds err = file->f_op->open(inode, file); 1631da177e4SLinus Torvalds if (err) { 1641da177e4SLinus Torvalds fops_put(file->f_op); 1651da177e4SLinus Torvalds file->f_op = fops_get(old_fops); 1661da177e4SLinus Torvalds } 1671da177e4SLinus Torvalds fops_put(old_fops); 1681da177e4SLinus Torvalds return err; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds static struct file_operations snd_fops = 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds .owner = THIS_MODULE, 1741da177e4SLinus Torvalds .open = snd_open 1751da177e4SLinus Torvalds }; 1761da177e4SLinus Torvalds 177332682b1SClemens Ladisch #ifdef CONFIG_SND_DYNAMIC_MINORS 178332682b1SClemens Ladisch static int snd_find_free_minor(void) 179332682b1SClemens Ladisch { 180332682b1SClemens Ladisch int minor; 181332682b1SClemens Ladisch 182332682b1SClemens Ladisch for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { 183332682b1SClemens Ladisch /* skip minors still used statically for autoloading devices */ 184332682b1SClemens Ladisch if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL || 185332682b1SClemens Ladisch minor == SNDRV_MINOR_SEQUENCER) 186332682b1SClemens Ladisch continue; 187332682b1SClemens Ladisch if (!snd_minors[minor]) 188332682b1SClemens Ladisch return minor; 189332682b1SClemens Ladisch } 190332682b1SClemens Ladisch return -EBUSY; 191332682b1SClemens Ladisch } 192332682b1SClemens Ladisch #else 193512bbd6aSTakashi Iwai static int snd_kernel_minor(int type, struct snd_card *card, int dev) 1941da177e4SLinus Torvalds { 1951da177e4SLinus Torvalds int minor; 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds switch (type) { 1981da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_SEQUENCER: 1991da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_TIMER: 2001da177e4SLinus Torvalds minor = type; 2011da177e4SLinus Torvalds break; 2021da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_CONTROL: 2031da177e4SLinus Torvalds snd_assert(card != NULL, return -EINVAL); 2041da177e4SLinus Torvalds minor = SNDRV_MINOR(card->number, type); 2051da177e4SLinus Torvalds break; 2061da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_HWDEP: 2071da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_RAWMIDI: 2081da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 2091da177e4SLinus Torvalds case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 2101da177e4SLinus Torvalds snd_assert(card != NULL, return -EINVAL); 2111da177e4SLinus Torvalds minor = SNDRV_MINOR(card->number, type + dev); 2121da177e4SLinus Torvalds break; 2131da177e4SLinus Torvalds default: 2141da177e4SLinus Torvalds return -EINVAL; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL); 2171da177e4SLinus Torvalds return minor; 2181da177e4SLinus Torvalds } 219332682b1SClemens Ladisch #endif 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds /** 222*12b131c4SJohannes Berg * snd_register_device_for_dev - Register the ALSA device file for the card 2231da177e4SLinus Torvalds * @type: the device type, SNDRV_DEVICE_TYPE_XXX 2241da177e4SLinus Torvalds * @card: the card instance 2251da177e4SLinus Torvalds * @dev: the device index 2262af677fcSClemens Ladisch * @f_ops: the file operations 227f87135f5SClemens Ladisch * @private_data: user pointer for f_ops->open() 2281da177e4SLinus Torvalds * @name: the device file name 229*12b131c4SJohannes Berg * @device: the &struct device to link this new device to 2301da177e4SLinus Torvalds * 2311da177e4SLinus Torvalds * Registers an ALSA device file for the given card. 2321da177e4SLinus Torvalds * The operators have to be set in reg parameter. 2331da177e4SLinus Torvalds * 234*12b131c4SJohannes Berg * Returns zero if successful, or a negative error code on failure. 2351da177e4SLinus Torvalds */ 236*12b131c4SJohannes Berg int snd_register_device_for_dev(int type, struct snd_card *card, int dev, 237*12b131c4SJohannes Berg const struct file_operations *f_ops, 238*12b131c4SJohannes Berg void *private_data, 239*12b131c4SJohannes Berg const char *name, struct device *device) 2401da177e4SLinus Torvalds { 241332682b1SClemens Ladisch int minor; 242512bbd6aSTakashi Iwai struct snd_minor *preg; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds snd_assert(name, return -EINVAL); 245562b590dSClemens Ladisch preg = kmalloc(sizeof *preg, GFP_KERNEL); 2461da177e4SLinus Torvalds if (preg == NULL) 2471da177e4SLinus Torvalds return -ENOMEM; 2482af677fcSClemens Ladisch preg->type = type; 2496983b724SClemens Ladisch preg->card = card ? card->number : -1; 2501da177e4SLinus Torvalds preg->device = dev; 2512af677fcSClemens Ladisch preg->f_ops = f_ops; 252f87135f5SClemens Ladisch preg->private_data = private_data; 2531a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 254332682b1SClemens Ladisch #ifdef CONFIG_SND_DYNAMIC_MINORS 255332682b1SClemens Ladisch minor = snd_find_free_minor(); 256332682b1SClemens Ladisch #else 257332682b1SClemens Ladisch minor = snd_kernel_minor(type, card, dev); 258332682b1SClemens Ladisch if (minor >= 0 && snd_minors[minor]) 259332682b1SClemens Ladisch minor = -EBUSY; 260332682b1SClemens Ladisch #endif 261332682b1SClemens Ladisch if (minor < 0) { 2621a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 2631da177e4SLinus Torvalds kfree(preg); 264332682b1SClemens Ladisch return minor; 2651da177e4SLinus Torvalds } 2666983b724SClemens Ladisch snd_minors[minor] = preg; 267d80f19faSGreg Kroah-Hartman preg->dev = device_create(sound_class, device, MKDEV(major, minor), 268d80f19faSGreg Kroah-Hartman "%s", name); 269d80f19faSGreg Kroah-Hartman if (preg->dev) 270d80f19faSGreg Kroah-Hartman dev_set_drvdata(preg->dev, private_data); 2711da177e4SLinus Torvalds 2721a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 2731da177e4SLinus Torvalds return 0; 2741da177e4SLinus Torvalds } 2751da177e4SLinus Torvalds 276*12b131c4SJohannes Berg EXPORT_SYMBOL(snd_register_device_for_dev); 277c0d3fb39STakashi Iwai 2789d19f48cSTakashi Iwai /* find the matching minor record 2799d19f48cSTakashi Iwai * return the index of snd_minor, or -1 if not found 2809d19f48cSTakashi Iwai */ 2819d19f48cSTakashi Iwai static int find_snd_minor(int type, struct snd_card *card, int dev) 2829d19f48cSTakashi Iwai { 2839d19f48cSTakashi Iwai int cardnum, minor; 2849d19f48cSTakashi Iwai struct snd_minor *mptr; 2859d19f48cSTakashi Iwai 2869d19f48cSTakashi Iwai cardnum = card ? card->number : -1; 2879d19f48cSTakashi Iwai for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) 2889d19f48cSTakashi Iwai if ((mptr = snd_minors[minor]) != NULL && 2899d19f48cSTakashi Iwai mptr->type == type && 2909d19f48cSTakashi Iwai mptr->card == cardnum && 2919d19f48cSTakashi Iwai mptr->device == dev) 2929d19f48cSTakashi Iwai return minor; 2939d19f48cSTakashi Iwai return -1; 2949d19f48cSTakashi Iwai } 2959d19f48cSTakashi Iwai 2961da177e4SLinus Torvalds /** 2971da177e4SLinus Torvalds * snd_unregister_device - unregister the device on the given card 2981da177e4SLinus Torvalds * @type: the device type, SNDRV_DEVICE_TYPE_XXX 2991da177e4SLinus Torvalds * @card: the card instance 3001da177e4SLinus Torvalds * @dev: the device index 3011da177e4SLinus Torvalds * 3021da177e4SLinus Torvalds * Unregisters the device file already registered via 3031da177e4SLinus Torvalds * snd_register_device(). 3041da177e4SLinus Torvalds * 3051da177e4SLinus Torvalds * Returns zero if sucecessful, or a negative error code on failure 3061da177e4SLinus Torvalds */ 307512bbd6aSTakashi Iwai int snd_unregister_device(int type, struct snd_card *card, int dev) 3081da177e4SLinus Torvalds { 3099d19f48cSTakashi Iwai int minor; 3101da177e4SLinus Torvalds 3111a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 3129d19f48cSTakashi Iwai minor = find_snd_minor(type, card, dev); 3139d19f48cSTakashi Iwai if (minor < 0) { 3141a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 3151da177e4SLinus Torvalds return -EINVAL; 3161da177e4SLinus Torvalds } 3171da177e4SLinus Torvalds 318d80f19faSGreg Kroah-Hartman device_destroy(sound_class, MKDEV(major, minor)); 3191da177e4SLinus Torvalds 3209d19f48cSTakashi Iwai kfree(snd_minors[minor]); 3216983b724SClemens Ladisch snd_minors[minor] = NULL; 3221a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 3231da177e4SLinus Torvalds return 0; 3241da177e4SLinus Torvalds } 3251da177e4SLinus Torvalds 326c0d3fb39STakashi Iwai EXPORT_SYMBOL(snd_unregister_device); 327c0d3fb39STakashi Iwai 3289d19f48cSTakashi Iwai int snd_add_device_sysfs_file(int type, struct snd_card *card, int dev, 329d80f19faSGreg Kroah-Hartman struct device_attribute *attr) 3309d19f48cSTakashi Iwai { 3319d19f48cSTakashi Iwai int minor, ret = -EINVAL; 332d80f19faSGreg Kroah-Hartman struct device *d; 3339d19f48cSTakashi Iwai 3349d19f48cSTakashi Iwai mutex_lock(&sound_mutex); 3359d19f48cSTakashi Iwai minor = find_snd_minor(type, card, dev); 336d80f19faSGreg Kroah-Hartman if (minor >= 0 && (d = snd_minors[minor]->dev) != NULL) 337d80f19faSGreg Kroah-Hartman ret = device_create_file(d, attr); 3389d19f48cSTakashi Iwai mutex_unlock(&sound_mutex); 3399d19f48cSTakashi Iwai return ret; 3409d19f48cSTakashi Iwai 3419d19f48cSTakashi Iwai } 3429d19f48cSTakashi Iwai 3439d19f48cSTakashi Iwai EXPORT_SYMBOL(snd_add_device_sysfs_file); 3449d19f48cSTakashi Iwai 345e28563ccSTakashi Iwai #ifdef CONFIG_PROC_FS 3461da177e4SLinus Torvalds /* 3471da177e4SLinus Torvalds * INFO PART 3481da177e4SLinus Torvalds */ 3491da177e4SLinus Torvalds 3506581f4e7STakashi Iwai static struct snd_info_entry *snd_minor_info_entry; 3511da177e4SLinus Torvalds 3522af677fcSClemens Ladisch static const char *snd_device_type_name(int type) 3532af677fcSClemens Ladisch { 3542af677fcSClemens Ladisch switch (type) { 3552af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_CONTROL: 3562af677fcSClemens Ladisch return "control"; 3572af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_HWDEP: 3582af677fcSClemens Ladisch return "hardware dependent"; 3592af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_RAWMIDI: 3602af677fcSClemens Ladisch return "raw midi"; 3612af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 3622af677fcSClemens Ladisch return "digital audio playback"; 3632af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 3642af677fcSClemens Ladisch return "digital audio capture"; 3652af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_SEQUENCER: 3662af677fcSClemens Ladisch return "sequencer"; 3672af677fcSClemens Ladisch case SNDRV_DEVICE_TYPE_TIMER: 3682af677fcSClemens Ladisch return "timer"; 3692af677fcSClemens Ladisch default: 3702af677fcSClemens Ladisch return "?"; 3712af677fcSClemens Ladisch } 3722af677fcSClemens Ladisch } 3732af677fcSClemens Ladisch 374512bbd6aSTakashi Iwai static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 3751da177e4SLinus Torvalds { 3766983b724SClemens Ladisch int minor; 377512bbd6aSTakashi Iwai struct snd_minor *mptr; 3781da177e4SLinus Torvalds 3791a60d4c5SIngo Molnar mutex_lock(&sound_mutex); 3806983b724SClemens Ladisch for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { 3816983b724SClemens Ladisch if (!(mptr = snd_minors[minor])) 3826983b724SClemens Ladisch continue; 3836983b724SClemens Ladisch if (mptr->card >= 0) { 3846983b724SClemens Ladisch if (mptr->device >= 0) 385d001544dSClemens Ladisch snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n", 3866983b724SClemens Ladisch minor, mptr->card, mptr->device, 3876983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3881da177e4SLinus Torvalds else 389d001544dSClemens Ladisch snd_iprintf(buffer, "%3i: [%2i] : %s\n", 3906983b724SClemens Ladisch minor, mptr->card, 3916983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3926983b724SClemens Ladisch } else 3936983b724SClemens Ladisch snd_iprintf(buffer, "%3i: : %s\n", minor, 3946983b724SClemens Ladisch snd_device_type_name(mptr->type)); 3951da177e4SLinus Torvalds } 3961a60d4c5SIngo Molnar mutex_unlock(&sound_mutex); 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds 3991da177e4SLinus Torvalds int __init snd_minor_info_init(void) 4001da177e4SLinus Torvalds { 401512bbd6aSTakashi Iwai struct snd_info_entry *entry; 4021da177e4SLinus Torvalds 4031da177e4SLinus Torvalds entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); 4041da177e4SLinus Torvalds if (entry) { 4051da177e4SLinus Torvalds entry->c.text.read = snd_minor_info_read; 4061da177e4SLinus Torvalds if (snd_info_register(entry) < 0) { 4071da177e4SLinus Torvalds snd_info_free_entry(entry); 4081da177e4SLinus Torvalds entry = NULL; 4091da177e4SLinus Torvalds } 4101da177e4SLinus Torvalds } 4111da177e4SLinus Torvalds snd_minor_info_entry = entry; 4121da177e4SLinus Torvalds return 0; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 4151da177e4SLinus Torvalds int __exit snd_minor_info_done(void) 4161da177e4SLinus Torvalds { 417746d4a02STakashi Iwai snd_info_free_entry(snd_minor_info_entry); 4181da177e4SLinus Torvalds return 0; 4191da177e4SLinus Torvalds } 420e28563ccSTakashi Iwai #endif /* CONFIG_PROC_FS */ 4211da177e4SLinus Torvalds 4221da177e4SLinus Torvalds /* 4231da177e4SLinus Torvalds * INIT PART 4241da177e4SLinus Torvalds */ 4251da177e4SLinus Torvalds 4261da177e4SLinus Torvalds static int __init alsa_sound_init(void) 4271da177e4SLinus Torvalds { 4281da177e4SLinus Torvalds snd_major = major; 4291da177e4SLinus Torvalds snd_ecards_limit = cards_limit; 4301da177e4SLinus Torvalds if (register_chrdev(major, "alsa", &snd_fops)) { 4311da177e4SLinus Torvalds snd_printk(KERN_ERR "unable to register native major device number %d\n", major); 4321da177e4SLinus Torvalds return -EIO; 4331da177e4SLinus Torvalds } 4341da177e4SLinus Torvalds if (snd_info_init() < 0) { 4351da177e4SLinus Torvalds unregister_chrdev(major, "alsa"); 4361da177e4SLinus Torvalds return -ENOMEM; 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds snd_info_minor_register(); 4391da177e4SLinus Torvalds #ifndef MODULE 4401da177e4SLinus Torvalds printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); 4411da177e4SLinus Torvalds #endif 4421da177e4SLinus Torvalds return 0; 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds 4451da177e4SLinus Torvalds static void __exit alsa_sound_exit(void) 4461da177e4SLinus Torvalds { 4471da177e4SLinus Torvalds snd_info_minor_unregister(); 4481da177e4SLinus Torvalds snd_info_done(); 4491da177e4SLinus Torvalds if (unregister_chrdev(major, "alsa") != 0) 4501da177e4SLinus Torvalds snd_printk(KERN_ERR "unable to unregister major device number %d\n", major); 4511da177e4SLinus Torvalds } 4521da177e4SLinus Torvalds 4531da177e4SLinus Torvalds module_init(alsa_sound_init) 4541da177e4SLinus Torvalds module_exit(alsa_sound_exit) 455