at v2.6.25 572 lines 14 kB view raw
1/* 2 * ALSA sequencer device management 3 * Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 * 20 *---------------------------------------------------------------- 21 * 22 * This device handler separates the card driver module from sequencer 23 * stuff (sequencer core, synth drivers, etc), so that user can avoid 24 * to spend unnecessary resources e.g. if he needs only listening to 25 * MP3s. 26 * 27 * The card (or lowlevel) driver creates a sequencer device entry 28 * via snd_seq_device_new(). This is an entry pointer to communicate 29 * with the sequencer device "driver", which is involved with the 30 * actual part to communicate with the sequencer core. 31 * Each sequencer device entry has an id string and the corresponding 32 * driver with the same id is loaded when required. For example, 33 * lowlevel codes to access emu8000 chip on sbawe card are included in 34 * emu8000-synth module. To activate this module, the hardware 35 * resources like i/o port are passed via snd_seq_device argument. 36 * 37 */ 38 39#include <linux/init.h> 40#include <sound/core.h> 41#include <sound/info.h> 42#include <sound/seq_device.h> 43#include <sound/seq_kernel.h> 44#include <sound/initval.h> 45#include <linux/kmod.h> 46#include <linux/slab.h> 47#include <linux/mutex.h> 48 49MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 50MODULE_DESCRIPTION("ALSA sequencer device management"); 51MODULE_LICENSE("GPL"); 52 53/* driver state */ 54#define DRIVER_EMPTY 0 55#define DRIVER_LOADED (1<<0) 56#define DRIVER_REQUESTED (1<<1) 57#define DRIVER_LOCKED (1<<2) 58 59struct ops_list { 60 char id[ID_LEN]; /* driver id */ 61 int driver; /* driver state */ 62 int used; /* reference counter */ 63 int argsize; /* argument size */ 64 65 /* operators */ 66 struct snd_seq_dev_ops ops; 67 68 /* registred devices */ 69 struct list_head dev_list; /* list of devices */ 70 int num_devices; /* number of associated devices */ 71 int num_init_devices; /* number of initialized devices */ 72 struct mutex reg_mutex; 73 74 struct list_head list; /* next driver */ 75}; 76 77 78static LIST_HEAD(opslist); 79static int num_ops; 80static DEFINE_MUTEX(ops_mutex); 81#ifdef CONFIG_PROC_FS 82static struct snd_info_entry *info_entry; 83#endif 84 85/* 86 * prototypes 87 */ 88static int snd_seq_device_free(struct snd_seq_device *dev); 89static int snd_seq_device_dev_free(struct snd_device *device); 90static int snd_seq_device_dev_register(struct snd_device *device); 91static int snd_seq_device_dev_disconnect(struct snd_device *device); 92 93static int init_device(struct snd_seq_device *dev, struct ops_list *ops); 94static int free_device(struct snd_seq_device *dev, struct ops_list *ops); 95static struct ops_list *find_driver(char *id, int create_if_empty); 96static struct ops_list *create_driver(char *id); 97static void unlock_driver(struct ops_list *ops); 98static void remove_drivers(void); 99 100/* 101 * show all drivers and their status 102 */ 103 104#ifdef CONFIG_PROC_FS 105static void snd_seq_device_info(struct snd_info_entry *entry, 106 struct snd_info_buffer *buffer) 107{ 108 struct ops_list *ops; 109 110 mutex_lock(&ops_mutex); 111 list_for_each_entry(ops, &opslist, list) { 112 snd_iprintf(buffer, "snd-%s%s%s%s,%d\n", 113 ops->id, 114 ops->driver & DRIVER_LOADED ? ",loaded" : (ops->driver == DRIVER_EMPTY ? ",empty" : ""), 115 ops->driver & DRIVER_REQUESTED ? ",requested" : "", 116 ops->driver & DRIVER_LOCKED ? ",locked" : "", 117 ops->num_devices); 118 } 119 mutex_unlock(&ops_mutex); 120} 121#endif 122 123/* 124 * load all registered drivers (called from seq_clientmgr.c) 125 */ 126 127#ifdef CONFIG_KMOD 128/* avoid auto-loading during module_init() */ 129static int snd_seq_in_init; 130void snd_seq_autoload_lock(void) 131{ 132 snd_seq_in_init++; 133} 134 135void snd_seq_autoload_unlock(void) 136{ 137 snd_seq_in_init--; 138} 139#endif 140 141void snd_seq_device_load_drivers(void) 142{ 143#ifdef CONFIG_KMOD 144 struct ops_list *ops; 145 146 /* Calling request_module during module_init() 147 * may cause blocking. 148 */ 149 if (snd_seq_in_init) 150 return; 151 152 mutex_lock(&ops_mutex); 153 list_for_each_entry(ops, &opslist, list) { 154 if (! (ops->driver & DRIVER_LOADED) && 155 ! (ops->driver & DRIVER_REQUESTED)) { 156 ops->used++; 157 mutex_unlock(&ops_mutex); 158 ops->driver |= DRIVER_REQUESTED; 159 request_module("snd-%s", ops->id); 160 mutex_lock(&ops_mutex); 161 ops->used--; 162 } 163 } 164 mutex_unlock(&ops_mutex); 165#endif 166} 167 168/* 169 * register a sequencer device 170 * card = card info (NULL allowed) 171 * device = device number (if any) 172 * id = id of driver 173 * result = return pointer (NULL allowed if unnecessary) 174 */ 175int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize, 176 struct snd_seq_device **result) 177{ 178 struct snd_seq_device *dev; 179 struct ops_list *ops; 180 int err; 181 static struct snd_device_ops dops = { 182 .dev_free = snd_seq_device_dev_free, 183 .dev_register = snd_seq_device_dev_register, 184 .dev_disconnect = snd_seq_device_dev_disconnect, 185 }; 186 187 if (result) 188 *result = NULL; 189 190 snd_assert(id != NULL, return -EINVAL); 191 192 ops = find_driver(id, 1); 193 if (ops == NULL) 194 return -ENOMEM; 195 196 dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL); 197 if (dev == NULL) { 198 unlock_driver(ops); 199 return -ENOMEM; 200 } 201 202 /* set up device info */ 203 dev->card = card; 204 dev->device = device; 205 strlcpy(dev->id, id, sizeof(dev->id)); 206 dev->argsize = argsize; 207 dev->status = SNDRV_SEQ_DEVICE_FREE; 208 209 /* add this device to the list */ 210 mutex_lock(&ops->reg_mutex); 211 list_add_tail(&dev->list, &ops->dev_list); 212 ops->num_devices++; 213 mutex_unlock(&ops->reg_mutex); 214 215 unlock_driver(ops); 216 217 if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { 218 snd_seq_device_free(dev); 219 return err; 220 } 221 222 if (result) 223 *result = dev; 224 225 return 0; 226} 227 228/* 229 * free the existing device 230 */ 231static int snd_seq_device_free(struct snd_seq_device *dev) 232{ 233 struct ops_list *ops; 234 235 snd_assert(dev != NULL, return -EINVAL); 236 237 ops = find_driver(dev->id, 0); 238 if (ops == NULL) 239 return -ENXIO; 240 241 /* remove the device from the list */ 242 mutex_lock(&ops->reg_mutex); 243 list_del(&dev->list); 244 ops->num_devices--; 245 mutex_unlock(&ops->reg_mutex); 246 247 free_device(dev, ops); 248 if (dev->private_free) 249 dev->private_free(dev); 250 kfree(dev); 251 252 unlock_driver(ops); 253 254 return 0; 255} 256 257static int snd_seq_device_dev_free(struct snd_device *device) 258{ 259 struct snd_seq_device *dev = device->device_data; 260 return snd_seq_device_free(dev); 261} 262 263/* 264 * register the device 265 */ 266static int snd_seq_device_dev_register(struct snd_device *device) 267{ 268 struct snd_seq_device *dev = device->device_data; 269 struct ops_list *ops; 270 271 ops = find_driver(dev->id, 0); 272 if (ops == NULL) 273 return -ENOENT; 274 275 /* initialize this device if the corresponding driver was 276 * already loaded 277 */ 278 if (ops->driver & DRIVER_LOADED) 279 init_device(dev, ops); 280 281 unlock_driver(ops); 282 return 0; 283} 284 285/* 286 * disconnect the device 287 */ 288static int snd_seq_device_dev_disconnect(struct snd_device *device) 289{ 290 struct snd_seq_device *dev = device->device_data; 291 struct ops_list *ops; 292 293 ops = find_driver(dev->id, 0); 294 if (ops == NULL) 295 return -ENOENT; 296 297 free_device(dev, ops); 298 299 unlock_driver(ops); 300 return 0; 301} 302 303/* 304 * register device driver 305 * id = driver id 306 * entry = driver operators - duplicated to each instance 307 */ 308int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, 309 int argsize) 310{ 311 struct ops_list *ops; 312 struct snd_seq_device *dev; 313 314 if (id == NULL || entry == NULL || 315 entry->init_device == NULL || entry->free_device == NULL) 316 return -EINVAL; 317 318 snd_seq_autoload_lock(); 319 ops = find_driver(id, 1); 320 if (ops == NULL) { 321 snd_seq_autoload_unlock(); 322 return -ENOMEM; 323 } 324 if (ops->driver & DRIVER_LOADED) { 325 snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id); 326 unlock_driver(ops); 327 snd_seq_autoload_unlock(); 328 return -EBUSY; 329 } 330 331 mutex_lock(&ops->reg_mutex); 332 /* copy driver operators */ 333 ops->ops = *entry; 334 ops->driver |= DRIVER_LOADED; 335 ops->argsize = argsize; 336 337 /* initialize existing devices if necessary */ 338 list_for_each_entry(dev, &ops->dev_list, list) { 339 init_device(dev, ops); 340 } 341 mutex_unlock(&ops->reg_mutex); 342 343 unlock_driver(ops); 344 snd_seq_autoload_unlock(); 345 346 return 0; 347} 348 349 350/* 351 * create driver record 352 */ 353static struct ops_list * create_driver(char *id) 354{ 355 struct ops_list *ops; 356 357 ops = kzalloc(sizeof(*ops), GFP_KERNEL); 358 if (ops == NULL) 359 return ops; 360 361 /* set up driver entry */ 362 strlcpy(ops->id, id, sizeof(ops->id)); 363 mutex_init(&ops->reg_mutex); 364 /* 365 * The ->reg_mutex locking rules are per-driver, so we create 366 * separate per-driver lock classes: 367 */ 368 lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id); 369 370 ops->driver = DRIVER_EMPTY; 371 INIT_LIST_HEAD(&ops->dev_list); 372 /* lock this instance */ 373 ops->used = 1; 374 375 /* register driver entry */ 376 mutex_lock(&ops_mutex); 377 list_add_tail(&ops->list, &opslist); 378 num_ops++; 379 mutex_unlock(&ops_mutex); 380 381 return ops; 382} 383 384 385/* 386 * unregister the specified driver 387 */ 388int snd_seq_device_unregister_driver(char *id) 389{ 390 struct ops_list *ops; 391 struct snd_seq_device *dev; 392 393 ops = find_driver(id, 0); 394 if (ops == NULL) 395 return -ENXIO; 396 if (! (ops->driver & DRIVER_LOADED) || 397 (ops->driver & DRIVER_LOCKED)) { 398 snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n", 399 id, ops->driver); 400 unlock_driver(ops); 401 return -EBUSY; 402 } 403 404 /* close and release all devices associated with this driver */ 405 mutex_lock(&ops->reg_mutex); 406 ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ 407 list_for_each_entry(dev, &ops->dev_list, list) { 408 free_device(dev, ops); 409 } 410 411 ops->driver = 0; 412 if (ops->num_init_devices > 0) 413 snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n", 414 ops->num_init_devices); 415 mutex_unlock(&ops->reg_mutex); 416 417 unlock_driver(ops); 418 419 /* remove empty driver entries */ 420 remove_drivers(); 421 422 return 0; 423} 424 425 426/* 427 * remove empty driver entries 428 */ 429static void remove_drivers(void) 430{ 431 struct list_head *head; 432 433 mutex_lock(&ops_mutex); 434 head = opslist.next; 435 while (head != &opslist) { 436 struct ops_list *ops = list_entry(head, struct ops_list, list); 437 if (! (ops->driver & DRIVER_LOADED) && 438 ops->used == 0 && ops->num_devices == 0) { 439 head = head->next; 440 list_del(&ops->list); 441 kfree(ops); 442 num_ops--; 443 } else 444 head = head->next; 445 } 446 mutex_unlock(&ops_mutex); 447} 448 449/* 450 * initialize the device - call init_device operator 451 */ 452static int init_device(struct snd_seq_device *dev, struct ops_list *ops) 453{ 454 if (! (ops->driver & DRIVER_LOADED)) 455 return 0; /* driver is not loaded yet */ 456 if (dev->status != SNDRV_SEQ_DEVICE_FREE) 457 return 0; /* already initialized */ 458 if (ops->argsize != dev->argsize) { 459 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", 460 dev->name, ops->id, ops->argsize, dev->argsize); 461 return -EINVAL; 462 } 463 if (ops->ops.init_device(dev) >= 0) { 464 dev->status = SNDRV_SEQ_DEVICE_REGISTERED; 465 ops->num_init_devices++; 466 } else { 467 snd_printk(KERN_ERR "init_device failed: %s: %s\n", 468 dev->name, dev->id); 469 } 470 471 return 0; 472} 473 474/* 475 * release the device - call free_device operator 476 */ 477static int free_device(struct snd_seq_device *dev, struct ops_list *ops) 478{ 479 int result; 480 481 if (! (ops->driver & DRIVER_LOADED)) 482 return 0; /* driver is not loaded yet */ 483 if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED) 484 return 0; /* not registered */ 485 if (ops->argsize != dev->argsize) { 486 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", 487 dev->name, ops->id, ops->argsize, dev->argsize); 488 return -EINVAL; 489 } 490 if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { 491 dev->status = SNDRV_SEQ_DEVICE_FREE; 492 dev->driver_data = NULL; 493 ops->num_init_devices--; 494 } else { 495 snd_printk(KERN_ERR "free_device failed: %s: %s\n", 496 dev->name, dev->id); 497 } 498 499 return 0; 500} 501 502/* 503 * find the matching driver with given id 504 */ 505static struct ops_list * find_driver(char *id, int create_if_empty) 506{ 507 struct ops_list *ops; 508 509 mutex_lock(&ops_mutex); 510 list_for_each_entry(ops, &opslist, list) { 511 if (strcmp(ops->id, id) == 0) { 512 ops->used++; 513 mutex_unlock(&ops_mutex); 514 return ops; 515 } 516 } 517 mutex_unlock(&ops_mutex); 518 if (create_if_empty) 519 return create_driver(id); 520 return NULL; 521} 522 523static void unlock_driver(struct ops_list *ops) 524{ 525 mutex_lock(&ops_mutex); 526 ops->used--; 527 mutex_unlock(&ops_mutex); 528} 529 530 531/* 532 * module part 533 */ 534 535static int __init alsa_seq_device_init(void) 536{ 537#ifdef CONFIG_PROC_FS 538 info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", 539 snd_seq_root); 540 if (info_entry == NULL) 541 return -ENOMEM; 542 info_entry->content = SNDRV_INFO_CONTENT_TEXT; 543 info_entry->c.text.read = snd_seq_device_info; 544 if (snd_info_register(info_entry) < 0) { 545 snd_info_free_entry(info_entry); 546 return -ENOMEM; 547 } 548#endif 549 return 0; 550} 551 552static void __exit alsa_seq_device_exit(void) 553{ 554 remove_drivers(); 555#ifdef CONFIG_PROC_FS 556 snd_info_free_entry(info_entry); 557#endif 558 if (num_ops) 559 snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops); 560} 561 562module_init(alsa_seq_device_init) 563module_exit(alsa_seq_device_exit) 564 565EXPORT_SYMBOL(snd_seq_device_load_drivers); 566EXPORT_SYMBOL(snd_seq_device_new); 567EXPORT_SYMBOL(snd_seq_device_register_driver); 568EXPORT_SYMBOL(snd_seq_device_unregister_driver); 569#ifdef CONFIG_KMOD 570EXPORT_SYMBOL(snd_seq_autoload_lock); 571EXPORT_SYMBOL(snd_seq_autoload_unlock); 572#endif