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 21 static int major = CONFIG_SND_MAJOR; 22 int snd_major; 23 EXPORT_SYMBOL(snd_major); 24 25 static int cards_limit = 1; 26 27 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 28 MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); 29 MODULE_LICENSE("GPL"); 30 module_param(major, int, 0444); 31 MODULE_PARM_DESC(major, "Major # for sound driver."); 32 module_param(cards_limit, int, 0444); 33 MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); 34 MODULE_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 */ 40 int snd_ecards_limit; 41 EXPORT_SYMBOL(snd_ecards_limit); 42 43 #ifdef CONFIG_SND_DEBUG 44 struct dentry *sound_debugfs_root; 45 EXPORT_SYMBOL_GPL(sound_debugfs_root); 46 #endif 47 48 static struct snd_minor *snd_minors[SNDRV_OS_MINORS]; 49 static 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 */ 60 void 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 } 68 EXPORT_SYMBOL(snd_request_card); 69 70 static 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 */ 99 void *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 guard(mutex)(&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 return private_data; 115 } 116 EXPORT_SYMBOL(snd_lookup_minor_data); 117 118 #ifdef CONFIG_MODULES 119 static struct snd_minor *autoload_device(unsigned int minor) 120 { 121 int dev; 122 mutex_unlock(&sound_mutex); /* release lock temporarily */ 123 dev = SNDRV_MINOR_DEVICE(minor); 124 if (dev == SNDRV_MINOR_CONTROL) { 125 /* /dev/aloadC? */ 126 int card = SNDRV_MINOR_CARD(minor); 127 struct snd_card *ref = snd_card_ref(card); 128 if (!ref) 129 snd_request_card(card); 130 else 131 snd_card_unref(ref); 132 } else if (dev == SNDRV_MINOR_GLOBAL) { 133 /* /dev/aloadSEQ */ 134 snd_request_other(minor); 135 } 136 mutex_lock(&sound_mutex); /* reacuire lock */ 137 return snd_minors[minor]; 138 } 139 #else /* !CONFIG_MODULES */ 140 #define autoload_device(minor) NULL 141 #endif /* CONFIG_MODULES */ 142 143 static int snd_open(struct inode *inode, struct file *file) 144 { 145 unsigned int minor = iminor(inode); 146 struct snd_minor *mptr = NULL; 147 const struct file_operations *new_fops; 148 int err = 0; 149 150 if (minor >= ARRAY_SIZE(snd_minors)) 151 return -ENODEV; 152 scoped_guard(mutex, &sound_mutex) { 153 mptr = snd_minors[minor]; 154 if (mptr == NULL) { 155 mptr = autoload_device(minor); 156 if (!mptr) 157 return -ENODEV; 158 } 159 new_fops = fops_get(mptr->f_ops); 160 } 161 if (!new_fops) 162 return -ENODEV; 163 replace_fops(file, new_fops); 164 165 if (file->f_op->open) 166 err = file->f_op->open(inode, file); 167 return err; 168 } 169 170 static const struct file_operations snd_fops = 171 { 172 .owner = THIS_MODULE, 173 .open = snd_open, 174 .llseek = noop_llseek, 175 }; 176 177 #ifdef CONFIG_SND_DYNAMIC_MINORS 178 static int snd_find_free_minor(int type, struct snd_card *card, int dev) 179 { 180 int minor; 181 182 /* static minors for module auto loading */ 183 if (type == SNDRV_DEVICE_TYPE_SEQUENCER) 184 return SNDRV_MINOR_SEQUENCER; 185 if (type == SNDRV_DEVICE_TYPE_TIMER) 186 return SNDRV_MINOR_TIMER; 187 188 for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { 189 /* skip static minors still used for module auto loading */ 190 if (SNDRV_MINOR_DEVICE(minor) == SNDRV_MINOR_CONTROL) 191 continue; 192 if (minor == SNDRV_MINOR_SEQUENCER || 193 minor == SNDRV_MINOR_TIMER) 194 continue; 195 if (!snd_minors[minor]) 196 return minor; 197 } 198 return -EBUSY; 199 } 200 #else 201 static int snd_find_free_minor(int type, struct snd_card *card, int dev) 202 { 203 int minor; 204 205 switch (type) { 206 case SNDRV_DEVICE_TYPE_SEQUENCER: 207 case SNDRV_DEVICE_TYPE_TIMER: 208 minor = type; 209 break; 210 case SNDRV_DEVICE_TYPE_CONTROL: 211 if (snd_BUG_ON(!card)) 212 return -EINVAL; 213 minor = SNDRV_MINOR(card->number, type); 214 break; 215 case SNDRV_DEVICE_TYPE_HWDEP: 216 case SNDRV_DEVICE_TYPE_RAWMIDI: 217 case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 218 case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 219 case SNDRV_DEVICE_TYPE_COMPRESS: 220 if (snd_BUG_ON(!card)) 221 return -EINVAL; 222 minor = SNDRV_MINOR(card->number, type + dev); 223 break; 224 default: 225 return -EINVAL; 226 } 227 if (snd_BUG_ON(minor < 0 || minor >= SNDRV_OS_MINORS)) 228 return -EINVAL; 229 if (snd_minors[minor]) 230 return -EBUSY; 231 return minor; 232 } 233 #endif 234 235 /** 236 * snd_register_device - Register the ALSA device file for the card 237 * @type: the device type, SNDRV_DEVICE_TYPE_XXX 238 * @card: the card instance 239 * @dev: the device index 240 * @f_ops: the file operations 241 * @private_data: user pointer for f_ops->open() 242 * @device: the device to register 243 * 244 * Registers an ALSA device file for the given card. 245 * The operators have to be set in reg parameter. 246 * 247 * Return: Zero if successful, or a negative error code on failure. 248 */ 249 int snd_register_device(int type, struct snd_card *card, int dev, 250 const struct file_operations *f_ops, 251 void *private_data, struct device *device) 252 { 253 int minor; 254 int err = 0; 255 struct snd_minor *preg; 256 257 if (snd_BUG_ON(!device)) 258 return -EINVAL; 259 260 preg = kmalloc(sizeof *preg, GFP_KERNEL); 261 if (preg == NULL) 262 return -ENOMEM; 263 preg->type = type; 264 preg->card = card ? card->number : -1; 265 preg->device = dev; 266 preg->f_ops = f_ops; 267 preg->private_data = private_data; 268 preg->card_ptr = card; 269 guard(mutex)(&sound_mutex); 270 minor = snd_find_free_minor(type, card, dev); 271 if (minor < 0) { 272 err = minor; 273 goto error; 274 } 275 276 preg->dev = device; 277 device->devt = MKDEV(major, minor); 278 err = device_add(device); 279 if (err < 0) 280 goto error; 281 282 snd_minors[minor] = preg; 283 error: 284 if (err < 0) 285 kfree(preg); 286 return err; 287 } 288 EXPORT_SYMBOL(snd_register_device); 289 290 /** 291 * snd_unregister_device - unregister the device on the given card 292 * @dev: the device instance 293 * 294 * Unregisters the device file already registered via 295 * snd_register_device(). 296 * 297 * Return: Zero if successful, or a negative error code on failure. 298 */ 299 int snd_unregister_device(struct device *dev) 300 { 301 int minor; 302 struct snd_minor *preg; 303 304 guard(mutex)(&sound_mutex); 305 for (minor = 0; minor < ARRAY_SIZE(snd_minors); ++minor) { 306 preg = snd_minors[minor]; 307 if (preg && preg->dev == dev) { 308 snd_minors[minor] = NULL; 309 device_del(dev); 310 kfree(preg); 311 break; 312 } 313 } 314 if (minor >= ARRAY_SIZE(snd_minors)) 315 return -ENOENT; 316 return 0; 317 } 318 EXPORT_SYMBOL(snd_unregister_device); 319 320 #ifdef CONFIG_SND_PROC_FS 321 /* 322 * INFO PART 323 */ 324 static const char *snd_device_type_name(int type) 325 { 326 switch (type) { 327 case SNDRV_DEVICE_TYPE_CONTROL: 328 return "control"; 329 case SNDRV_DEVICE_TYPE_HWDEP: 330 return "hardware dependent"; 331 case SNDRV_DEVICE_TYPE_RAWMIDI: 332 return "raw midi"; 333 case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 334 return "digital audio playback"; 335 case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 336 return "digital audio capture"; 337 case SNDRV_DEVICE_TYPE_SEQUENCER: 338 return "sequencer"; 339 case SNDRV_DEVICE_TYPE_TIMER: 340 return "timer"; 341 case SNDRV_DEVICE_TYPE_COMPRESS: 342 return "compress"; 343 default: 344 return "?"; 345 } 346 } 347 348 static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 349 { 350 int minor; 351 struct snd_minor *mptr; 352 353 guard(mutex)(&sound_mutex); 354 for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) { 355 mptr = snd_minors[minor]; 356 if (!mptr) 357 continue; 358 if (mptr->card >= 0) { 359 if (mptr->device >= 0) 360 snd_iprintf(buffer, "%3i: [%2i-%2i]: %s\n", 361 minor, mptr->card, mptr->device, 362 snd_device_type_name(mptr->type)); 363 else 364 snd_iprintf(buffer, "%3i: [%2i] : %s\n", 365 minor, mptr->card, 366 snd_device_type_name(mptr->type)); 367 } else 368 snd_iprintf(buffer, "%3i: : %s\n", minor, 369 snd_device_type_name(mptr->type)); 370 } 371 } 372 373 int __init snd_minor_info_init(void) 374 { 375 struct snd_info_entry *entry; 376 377 entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); 378 if (!entry) 379 return -ENOMEM; 380 entry->c.text.read = snd_minor_info_read; 381 return snd_info_register(entry); /* freed in error path */ 382 } 383 #endif /* CONFIG_SND_PROC_FS */ 384 385 /* 386 * INIT PART 387 */ 388 389 static int __init alsa_sound_init(void) 390 { 391 snd_major = major; 392 snd_ecards_limit = cards_limit; 393 if (register_chrdev(major, "alsa", &snd_fops)) { 394 pr_err("ALSA core: unable to register native major device number %d\n", major); 395 return -EIO; 396 } 397 if (snd_info_init() < 0) { 398 unregister_chrdev(major, "alsa"); 399 return -ENOMEM; 400 } 401 402 #ifdef CONFIG_SND_DEBUG 403 sound_debugfs_root = debugfs_create_dir("sound", NULL); 404 #endif 405 #ifndef MODULE 406 pr_info("Advanced Linux Sound Architecture Driver Initialized.\n"); 407 #endif 408 return 0; 409 } 410 411 static void __exit alsa_sound_exit(void) 412 { 413 #ifdef CONFIG_SND_DEBUG 414 debugfs_remove(sound_debugfs_root); 415 #endif 416 snd_info_done(); 417 unregister_chrdev(major, "alsa"); 418 } 419 420 subsys_initcall(alsa_sound_init); 421 module_exit(alsa_sound_exit); 422
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.