1 /* 2 * Advanced Linux Sound Architecture 3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz> 4 * 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20 */ 21 22 #include <sound/driver.h> 23 #include <linux/init.h> 24 #include <linux/slab.h> 25 #include <linux/time.h> 26 #include <linux/moduleparam.h> 27 #include <sound/core.h> 28 #include <sound/minors.h> 29 #include <sound/info.h> 30 #include <sound/version.h> 31 #include <sound/control.h> 32 #include <sound/initval.h> 33 #include <linux/kmod.h> 34 #include <linux/devfs_fs_kernel.h> 35 #include <linux/platform_device.h> 36 37 #define SNDRV_OS_MINORS 256 38 39 static int major = CONFIG_SND_MAJOR; 40 int snd_major; 41 static int cards_limit = 1; 42 static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; 43 44 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 45 MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); 46 MODULE_LICENSE("GPL"); 47 module_param(major, int, 0444); 48 MODULE_PARM_DESC(major, "Major # for sound driver."); 49 module_param(cards_limit, int, 0444); 50 MODULE_PARM_DESC(cards_limit, "Count of auto-loadable soundcards."); 51 #ifdef CONFIG_DEVFS_FS 52 module_param(device_mode, int, 0444); 53 MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs."); 54 #endif 55 MODULE_ALIAS_CHARDEV_MAJOR(CONFIG_SND_MAJOR); 56 57 /* this one holds the actual max. card number currently available. 58 * as default, it's identical with cards_limit option. when more 59 * modules are loaded manually, this limit number increases, too. 60 */ 61 int snd_ecards_limit; 62 63 static struct list_head snd_minors_hash[SNDRV_CARDS]; 64 65 static DECLARE_MUTEX(sound_mutex); 66 67 extern struct class *sound_class; 68 69 70 #ifdef CONFIG_KMOD 71 72 /** 73 * snd_request_card - try to load the card module 74 * @card: the card number 75 * 76 * Tries to load the module "snd-card-X" for the given card number 77 * via KMOD. Returns immediately if already loaded. 78 */ 79 void snd_request_card(int card) 80 { 81 int locked; 82 83 if (! current->fs->root) 84 return; 85 read_lock(&snd_card_rwlock); 86 locked = snd_cards_lock & (1 << card); 87 read_unlock(&snd_card_rwlock); 88 if (locked) 89 return; 90 if (card < 0 || card >= cards_limit) 91 return; 92 request_module("snd-card-%i", card); 93 } 94 95 static void snd_request_other(int minor) 96 { 97 char *str; 98 99 if (! current->fs->root) 100 return; 101 switch (minor) { 102 case SNDRV_MINOR_SEQUENCER: str = "snd-seq"; break; 103 case SNDRV_MINOR_TIMER: str = "snd-timer"; break; 104 default: return; 105 } 106 request_module(str); 107 } 108 109 #endif /* request_module support */ 110 111 static struct snd_minor *snd_minor_search(int minor) 112 { 113 struct list_head *list; 114 struct snd_minor *mptr; 115 116 list_for_each(list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]) { 117 mptr = list_entry(list, struct snd_minor, list); 118 if (mptr->number == minor) 119 return mptr; 120 } 121 return NULL; 122 } 123 124 static int snd_open(struct inode *inode, struct file *file) 125 { 126 int minor = iminor(inode); 127 int card = SNDRV_MINOR_CARD(minor); 128 int dev = SNDRV_MINOR_DEVICE(minor); 129 struct snd_minor *mptr = NULL; 130 struct file_operations *old_fops; 131 int err = 0; 132 133 if (dev != SNDRV_MINOR_GLOBAL) { 134 if (snd_cards[card] == NULL) { 135 #ifdef CONFIG_KMOD 136 snd_request_card(card); 137 if (snd_cards[card] == NULL) 138 #endif 139 return -ENODEV; 140 } 141 } else { 142 #ifdef CONFIG_KMOD 143 if ((mptr = snd_minor_search(minor)) == NULL) 144 snd_request_other(minor); 145 #endif 146 } 147 if (mptr == NULL && (mptr = snd_minor_search(minor)) == NULL) 148 return -ENODEV; 149 old_fops = file->f_op; 150 file->f_op = fops_get(mptr->f_ops); 151 if (file->f_op->open) 152 err = file->f_op->open(inode, file); 153 if (err) { 154 fops_put(file->f_op); 155 file->f_op = fops_get(old_fops); 156 } 157 fops_put(old_fops); 158 return err; 159 } 160 161 static struct file_operations snd_fops = 162 { 163 .owner = THIS_MODULE, 164 .open = snd_open 165 }; 166 167 static int snd_kernel_minor(int type, struct snd_card *card, int dev) 168 { 169 int minor; 170 171 switch (type) { 172 case SNDRV_DEVICE_TYPE_SEQUENCER: 173 case SNDRV_DEVICE_TYPE_TIMER: 174 minor = type; 175 break; 176 case SNDRV_DEVICE_TYPE_CONTROL: 177 snd_assert(card != NULL, return -EINVAL); 178 minor = SNDRV_MINOR(card->number, type); 179 break; 180 case SNDRV_DEVICE_TYPE_HWDEP: 181 case SNDRV_DEVICE_TYPE_RAWMIDI: 182 case SNDRV_DEVICE_TYPE_PCM_PLAYBACK: 183 case SNDRV_DEVICE_TYPE_PCM_CAPTURE: 184 snd_assert(card != NULL, return -EINVAL); 185 minor = SNDRV_MINOR(card->number, type + dev); 186 break; 187 default: 188 return -EINVAL; 189 } 190 snd_assert(minor >= 0 && minor < SNDRV_OS_MINORS, return -EINVAL); 191 return minor; 192 } 193 194 /** 195 * snd_register_device - Register the ALSA device file for the card 196 * @type: the device type, SNDRV_DEVICE_TYPE_XXX 197 * @card: the card instance 198 * @dev: the device index 199 * @reg: the struct snd_minor record 200 * @name: the device file name 201 * 202 * Registers an ALSA device file for the given card. 203 * The operators have to be set in reg parameter. 204 * 205 * Retrurns zero if successful, or a negative error code on failure. 206 */ 207 int snd_register_device(int type, struct snd_card *card, int dev, struct snd_minor * reg, const char *name) 208 { 209 int minor = snd_kernel_minor(type, card, dev); 210 struct snd_minor *preg; 211 struct device *device = NULL; 212 213 if (minor < 0) 214 return minor; 215 snd_assert(name, return -EINVAL); 216 preg = kmalloc(sizeof(struct snd_minor) + strlen(name) + 1, GFP_KERNEL); 217 if (preg == NULL) 218 return -ENOMEM; 219 *preg = *reg; 220 preg->number = minor; 221 preg->device = dev; 222 strcpy(preg->name, name); 223 down(&sound_mutex); 224 if (snd_minor_search(minor)) { 225 up(&sound_mutex); 226 kfree(preg); 227 return -EBUSY; 228 } 229 list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]); 230 if (strncmp(name, "controlC", 8) || card->number >= cards_limit) 231 devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); 232 if (card) 233 device = card->dev; 234 class_device_create(sound_class, NULL, MKDEV(major, minor), device, "%s", name); 235 236 up(&sound_mutex); 237 return 0; 238 } 239 240 /** 241 * snd_unregister_device - unregister the device on the given card 242 * @type: the device type, SNDRV_DEVICE_TYPE_XXX 243 * @card: the card instance 244 * @dev: the device index 245 * 246 * Unregisters the device file already registered via 247 * snd_register_device(). 248 * 249 * Returns zero if sucecessful, or a negative error code on failure 250 */ 251 int snd_unregister_device(int type, struct snd_card *card, int dev) 252 { 253 int minor = snd_kernel_minor(type, card, dev); 254 struct snd_minor *mptr; 255 256 if (minor < 0) 257 return minor; 258 down(&sound_mutex); 259 if ((mptr = snd_minor_search(minor)) == NULL) { 260 up(&sound_mutex); 261 return -EINVAL; 262 } 263 264 if (strncmp(mptr->name, "controlC", 8) || card->number >= cards_limit) /* created in sound.c */ 265 devfs_remove("snd/%s", mptr->name); 266 class_device_destroy(sound_class, MKDEV(major, minor)); 267 268 list_del(&mptr->list); 269 up(&sound_mutex); 270 kfree(mptr); 271 return 0; 272 } 273 274 /* 275 * INFO PART 276 */ 277 278 static struct snd_info_entry *snd_minor_info_entry = NULL; 279 280 static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) 281 { 282 int card, device; 283 struct list_head *list; 284 struct snd_minor *mptr; 285 286 down(&sound_mutex); 287 for (card = 0; card < SNDRV_CARDS; card++) { 288 list_for_each(list, &snd_minors_hash[card]) { 289 mptr = list_entry(list, struct snd_minor, list); 290 if (SNDRV_MINOR_DEVICE(mptr->number) != SNDRV_MINOR_GLOBAL) { 291 if ((device = mptr->device) >= 0) 292 snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", mptr->number, card, device, mptr->comment); 293 else 294 snd_iprintf(buffer, "%3i: [%i] : %s\n", mptr->number, card, mptr->comment); 295 } else { 296 snd_iprintf(buffer, "%3i: : %s\n", mptr->number, mptr->comment); 297 } 298 } 299 } 300 up(&sound_mutex); 301 } 302 303 int __init snd_minor_info_init(void) 304 { 305 struct snd_info_entry *entry; 306 307 entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL); 308 if (entry) { 309 entry->c.text.read_size = PAGE_SIZE; 310 entry->c.text.read = snd_minor_info_read; 311 if (snd_info_register(entry) < 0) { 312 snd_info_free_entry(entry); 313 entry = NULL; 314 } 315 } 316 snd_minor_info_entry = entry; 317 return 0; 318 } 319 320 int __exit snd_minor_info_done(void) 321 { 322 if (snd_minor_info_entry) 323 snd_info_unregister(snd_minor_info_entry); 324 return 0; 325 } 326 327 /* 328 * INIT PART 329 */ 330 331 #ifdef CONFIG_SND_GENERIC_DRIVER 332 extern struct platform_driver snd_generic_driver; 333 #endif 334 335 static int __init alsa_sound_init(void) 336 { 337 short controlnum; 338 int err; 339 int card; 340 341 snd_major = major; 342 snd_ecards_limit = cards_limit; 343 for (card = 0; card < SNDRV_CARDS; card++) 344 INIT_LIST_HEAD(&snd_minors_hash[card]); 345 if ((err = snd_oss_init_module()) < 0) 346 return err; 347 devfs_mk_dir("snd"); 348 if (register_chrdev(major, "alsa", &snd_fops)) { 349 snd_printk(KERN_ERR "unable to register native major device number %d\n", major); 350 devfs_remove("snd"); 351 return -EIO; 352 } 353 if (snd_info_init() < 0) { 354 unregister_chrdev(major, "alsa"); 355 devfs_remove("snd"); 356 return -ENOMEM; 357 } 358 snd_info_minor_register(); 359 #ifdef CONFIG_SND_GENERIC_DRIVER 360 platform_driver_register(&snd_generic_driver); 361 #endif 362 for (controlnum = 0; controlnum < cards_limit; controlnum++) 363 devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum); 364 #ifndef MODULE 365 printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); 366 #endif 367 return 0; 368 } 369 370 static void __exit alsa_sound_exit(void) 371 { 372 short controlnum; 373 374 for (controlnum = 0; controlnum < cards_limit; controlnum++) 375 devfs_remove("snd/controlC%d", controlnum); 376 377 #ifdef CONFIG_SND_GENERIC_DRIVER 378 platform_driver_unregister(&snd_generic_driver); 379 #endif 380 snd_info_minor_unregister(); 381 snd_info_done(); 382 if (unregister_chrdev(major, "alsa") != 0) 383 snd_printk(KERN_ERR "unable to unregister major device number %d\n", major); 384 devfs_remove("snd"); 385 } 386 387 module_init(alsa_sound_init) 388 module_exit(alsa_sound_exit) 389 390 /* sound.c */ 391 EXPORT_SYMBOL(snd_major); 392 EXPORT_SYMBOL(snd_ecards_limit); 393 #if defined(CONFIG_KMOD) 394 EXPORT_SYMBOL(snd_request_card); 395 #endif 396 EXPORT_SYMBOL(snd_register_device); 397 EXPORT_SYMBOL(snd_unregister_device); 398 #if defined(CONFIG_SND_OSSEMUL) 399 EXPORT_SYMBOL(snd_register_oss_device); 400 EXPORT_SYMBOL(snd_unregister_oss_device); 401 #endif 402 /* memory.c */ 403 EXPORT_SYMBOL(copy_to_user_fromio); 404 EXPORT_SYMBOL(copy_from_user_toio); 405 /* init.c */ 406 EXPORT_SYMBOL(snd_cards); 407 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE) 408 EXPORT_SYMBOL(snd_mixer_oss_notify_callback); 409 #endif 410 EXPORT_SYMBOL(snd_card_new); 411 EXPORT_SYMBOL(snd_card_disconnect); 412 EXPORT_SYMBOL(snd_card_free); 413 EXPORT_SYMBOL(snd_card_free_in_thread); 414 EXPORT_SYMBOL(snd_card_register); 415 EXPORT_SYMBOL(snd_component_add); 416 EXPORT_SYMBOL(snd_card_file_add); 417 EXPORT_SYMBOL(snd_card_file_remove); 418 #ifdef CONFIG_SND_GENERIC_DRIVER 419 EXPORT_SYMBOL(snd_card_set_generic_dev); 420 #endif 421 #ifdef CONFIG_PM 422 EXPORT_SYMBOL(snd_power_wait); 423 EXPORT_SYMBOL(snd_card_set_pm_callback); 424 #ifdef CONFIG_SND_GENERIC_DRIVER 425 EXPORT_SYMBOL(snd_card_set_generic_pm_callback); 426 #endif 427 #ifdef CONFIG_PCI 428 EXPORT_SYMBOL(snd_card_pci_suspend); 429 EXPORT_SYMBOL(snd_card_pci_resume); 430 #endif 431 #endif 432 /* device.c */ 433 EXPORT_SYMBOL(snd_device_new); 434 EXPORT_SYMBOL(snd_device_register); 435 EXPORT_SYMBOL(snd_device_free); 436 /* isadma.c */ 437 #ifdef CONFIG_ISA_DMA_API 438 EXPORT_SYMBOL(snd_dma_program); 439 EXPORT_SYMBOL(snd_dma_disable); 440 EXPORT_SYMBOL(snd_dma_pointer); 441 #endif 442 /* info.c */ 443 #ifdef CONFIG_PROC_FS 444 EXPORT_SYMBOL(snd_seq_root); 445 EXPORT_SYMBOL(snd_iprintf); 446 EXPORT_SYMBOL(snd_info_get_line); 447 EXPORT_SYMBOL(snd_info_get_str); 448 EXPORT_SYMBOL(snd_info_create_module_entry); 449 EXPORT_SYMBOL(snd_info_create_card_entry); 450 EXPORT_SYMBOL(snd_info_free_entry); 451 EXPORT_SYMBOL(snd_info_register); 452 EXPORT_SYMBOL(snd_info_unregister); 453 EXPORT_SYMBOL(snd_card_proc_new); 454 #endif 455 /* info_oss.c */ 456 #if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS) 457 EXPORT_SYMBOL(snd_oss_info_register); 458 #endif 459 /* control.c */ 460 EXPORT_SYMBOL(snd_ctl_new); 461 EXPORT_SYMBOL(snd_ctl_new1); 462 EXPORT_SYMBOL(snd_ctl_free_one); 463 EXPORT_SYMBOL(snd_ctl_add); 464 EXPORT_SYMBOL(snd_ctl_remove); 465 EXPORT_SYMBOL(snd_ctl_remove_id); 466 EXPORT_SYMBOL(snd_ctl_rename_id); 467 EXPORT_SYMBOL(snd_ctl_find_numid); 468 EXPORT_SYMBOL(snd_ctl_find_id); 469 EXPORT_SYMBOL(snd_ctl_notify); 470 EXPORT_SYMBOL(snd_ctl_register_ioctl); 471 EXPORT_SYMBOL(snd_ctl_unregister_ioctl); 472 #ifdef CONFIG_COMPAT 473 EXPORT_SYMBOL(snd_ctl_register_ioctl_compat); 474 EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat); 475 #endif 476 EXPORT_SYMBOL(snd_ctl_elem_read); 477 EXPORT_SYMBOL(snd_ctl_elem_write); 478 /* misc.c */ 479 EXPORT_SYMBOL(release_and_free_resource); 480 #ifdef CONFIG_SND_VERBOSE_PRINTK 481 EXPORT_SYMBOL(snd_verbose_printk); 482 #endif 483 #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_VERBOSE_PRINTK) 484 EXPORT_SYMBOL(snd_verbose_printd); 485 #endif 486