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