at v2.6.30 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_MODULES 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_MODULES 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 if (snd_BUG_ON(!id)) 191 return -EINVAL; 192 193 ops = find_driver(id, 1); 194 if (ops == NULL) 195 return -ENOMEM; 196 197 dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL); 198 if (dev == NULL) { 199 unlock_driver(ops); 200 return -ENOMEM; 201 } 202 203 /* set up device info */ 204 dev->card = card; 205 dev->device = device; 206 strlcpy(dev->id, id, sizeof(dev->id)); 207 dev->argsize = argsize; 208 dev->status = SNDRV_SEQ_DEVICE_FREE; 209 210 /* add this device to the list */ 211 mutex_lock(&ops->reg_mutex); 212 list_add_tail(&dev->list, &ops->dev_list); 213 ops->num_devices++; 214 mutex_unlock(&ops->reg_mutex); 215 216 unlock_driver(ops); 217 218 if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) { 219 snd_seq_device_free(dev); 220 return err; 221 } 222 223 if (result) 224 *result = dev; 225 226 return 0; 227} 228 229/* 230 * free the existing device 231 */ 232static int snd_seq_device_free(struct snd_seq_device *dev) 233{ 234 struct ops_list *ops; 235 236 if (snd_BUG_ON(!dev)) 237 return -EINVAL; 238 239 ops = find_driver(dev->id, 0); 240 if (ops == NULL) 241 return -ENXIO; 242 243 /* remove the device from the list */ 244 mutex_lock(&ops->reg_mutex); 245 list_del(&dev->list); 246 ops->num_devices--; 247 mutex_unlock(&ops->reg_mutex); 248 249 free_device(dev, ops); 250 if (dev->private_free) 251 dev->private_free(dev); 252 kfree(dev); 253 254 unlock_driver(ops); 255 256 return 0; 257} 258 259static int snd_seq_device_dev_free(struct snd_device *device) 260{ 261 struct snd_seq_device *dev = device->device_data; 262 return snd_seq_device_free(dev); 263} 264 265/* 266 * register the device 267 */ 268static int snd_seq_device_dev_register(struct snd_device *device) 269{ 270 struct snd_seq_device *dev = device->device_data; 271 struct ops_list *ops; 272 273 ops = find_driver(dev->id, 0); 274 if (ops == NULL) 275 return -ENOENT; 276 277 /* initialize this device if the corresponding driver was 278 * already loaded 279 */ 280 if (ops->driver & DRIVER_LOADED) 281 init_device(dev, ops); 282 283 unlock_driver(ops); 284 return 0; 285} 286 287/* 288 * disconnect the device 289 */ 290static int snd_seq_device_dev_disconnect(struct snd_device *device) 291{ 292 struct snd_seq_device *dev = device->device_data; 293 struct ops_list *ops; 294 295 ops = find_driver(dev->id, 0); 296 if (ops == NULL) 297 return -ENOENT; 298 299 free_device(dev, ops); 300 301 unlock_driver(ops); 302 return 0; 303} 304 305/* 306 * register device driver 307 * id = driver id 308 * entry = driver operators - duplicated to each instance 309 */ 310int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry, 311 int argsize) 312{ 313 struct ops_list *ops; 314 struct snd_seq_device *dev; 315 316 if (id == NULL || entry == NULL || 317 entry->init_device == NULL || entry->free_device == NULL) 318 return -EINVAL; 319 320 snd_seq_autoload_lock(); 321 ops = find_driver(id, 1); 322 if (ops == NULL) { 323 snd_seq_autoload_unlock(); 324 return -ENOMEM; 325 } 326 if (ops->driver & DRIVER_LOADED) { 327 snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id); 328 unlock_driver(ops); 329 snd_seq_autoload_unlock(); 330 return -EBUSY; 331 } 332 333 mutex_lock(&ops->reg_mutex); 334 /* copy driver operators */ 335 ops->ops = *entry; 336 ops->driver |= DRIVER_LOADED; 337 ops->argsize = argsize; 338 339 /* initialize existing devices if necessary */ 340 list_for_each_entry(dev, &ops->dev_list, list) { 341 init_device(dev, ops); 342 } 343 mutex_unlock(&ops->reg_mutex); 344 345 unlock_driver(ops); 346 snd_seq_autoload_unlock(); 347 348 return 0; 349} 350 351 352/* 353 * create driver record 354 */ 355static struct ops_list * create_driver(char *id) 356{ 357 struct ops_list *ops; 358 359 ops = kzalloc(sizeof(*ops), GFP_KERNEL); 360 if (ops == NULL) 361 return ops; 362 363 /* set up driver entry */ 364 strlcpy(ops->id, id, sizeof(ops->id)); 365 mutex_init(&ops->reg_mutex); 366 /* 367 * The ->reg_mutex locking rules are per-driver, so we create 368 * separate per-driver lock classes: 369 */ 370 lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id); 371 372 ops->driver = DRIVER_EMPTY; 373 INIT_LIST_HEAD(&ops->dev_list); 374 /* lock this instance */ 375 ops->used = 1; 376 377 /* register driver entry */ 378 mutex_lock(&ops_mutex); 379 list_add_tail(&ops->list, &opslist); 380 num_ops++; 381 mutex_unlock(&ops_mutex); 382 383 return ops; 384} 385 386 387/* 388 * unregister the specified driver 389 */ 390int snd_seq_device_unregister_driver(char *id) 391{ 392 struct ops_list *ops; 393 struct snd_seq_device *dev; 394 395 ops = find_driver(id, 0); 396 if (ops == NULL) 397 return -ENXIO; 398 if (! (ops->driver & DRIVER_LOADED) || 399 (ops->driver & DRIVER_LOCKED)) { 400 snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n", 401 id, ops->driver); 402 unlock_driver(ops); 403 return -EBUSY; 404 } 405 406 /* close and release all devices associated with this driver */ 407 mutex_lock(&ops->reg_mutex); 408 ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */ 409 list_for_each_entry(dev, &ops->dev_list, list) { 410 free_device(dev, ops); 411 } 412 413 ops->driver = 0; 414 if (ops->num_init_devices > 0) 415 snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n", 416 ops->num_init_devices); 417 mutex_unlock(&ops->reg_mutex); 418 419 unlock_driver(ops); 420 421 /* remove empty driver entries */ 422 remove_drivers(); 423 424 return 0; 425} 426 427 428/* 429 * remove empty driver entries 430 */ 431static void remove_drivers(void) 432{ 433 struct list_head *head; 434 435 mutex_lock(&ops_mutex); 436 head = opslist.next; 437 while (head != &opslist) { 438 struct ops_list *ops = list_entry(head, struct ops_list, list); 439 if (! (ops->driver & DRIVER_LOADED) && 440 ops->used == 0 && ops->num_devices == 0) { 441 head = head->next; 442 list_del(&ops->list); 443 kfree(ops); 444 num_ops--; 445 } else 446 head = head->next; 447 } 448 mutex_unlock(&ops_mutex); 449} 450 451/* 452 * initialize the device - call init_device operator 453 */ 454static int init_device(struct snd_seq_device *dev, struct ops_list *ops) 455{ 456 if (! (ops->driver & DRIVER_LOADED)) 457 return 0; /* driver is not loaded yet */ 458 if (dev->status != SNDRV_SEQ_DEVICE_FREE) 459 return 0; /* already initialized */ 460 if (ops->argsize != dev->argsize) { 461 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", 462 dev->name, ops->id, ops->argsize, dev->argsize); 463 return -EINVAL; 464 } 465 if (ops->ops.init_device(dev) >= 0) { 466 dev->status = SNDRV_SEQ_DEVICE_REGISTERED; 467 ops->num_init_devices++; 468 } else { 469 snd_printk(KERN_ERR "init_device failed: %s: %s\n", 470 dev->name, dev->id); 471 } 472 473 return 0; 474} 475 476/* 477 * release the device - call free_device operator 478 */ 479static int free_device(struct snd_seq_device *dev, struct ops_list *ops) 480{ 481 int result; 482 483 if (! (ops->driver & DRIVER_LOADED)) 484 return 0; /* driver is not loaded yet */ 485 if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED) 486 return 0; /* not registered */ 487 if (ops->argsize != dev->argsize) { 488 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n", 489 dev->name, ops->id, ops->argsize, dev->argsize); 490 return -EINVAL; 491 } 492 if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) { 493 dev->status = SNDRV_SEQ_DEVICE_FREE; 494 dev->driver_data = NULL; 495 ops->num_init_devices--; 496 } else { 497 snd_printk(KERN_ERR "free_device failed: %s: %s\n", 498 dev->name, dev->id); 499 } 500 501 return 0; 502} 503 504/* 505 * find the matching driver with given id 506 */ 507static struct ops_list * find_driver(char *id, int create_if_empty) 508{ 509 struct ops_list *ops; 510 511 mutex_lock(&ops_mutex); 512 list_for_each_entry(ops, &opslist, list) { 513 if (strcmp(ops->id, id) == 0) { 514 ops->used++; 515 mutex_unlock(&ops_mutex); 516 return ops; 517 } 518 } 519 mutex_unlock(&ops_mutex); 520 if (create_if_empty) 521 return create_driver(id); 522 return NULL; 523} 524 525static void unlock_driver(struct ops_list *ops) 526{ 527 mutex_lock(&ops_mutex); 528 ops->used--; 529 mutex_unlock(&ops_mutex); 530} 531 532 533/* 534 * module part 535 */ 536 537static int __init alsa_seq_device_init(void) 538{ 539#ifdef CONFIG_PROC_FS 540 info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers", 541 snd_seq_root); 542 if (info_entry == NULL) 543 return -ENOMEM; 544 info_entry->content = SNDRV_INFO_CONTENT_TEXT; 545 info_entry->c.text.read = snd_seq_device_info; 546 if (snd_info_register(info_entry) < 0) { 547 snd_info_free_entry(info_entry); 548 return -ENOMEM; 549 } 550#endif 551 return 0; 552} 553 554static void __exit alsa_seq_device_exit(void) 555{ 556 remove_drivers(); 557#ifdef CONFIG_PROC_FS 558 snd_info_free_entry(info_entry); 559#endif 560 if (num_ops) 561 snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops); 562} 563 564module_init(alsa_seq_device_init) 565module_exit(alsa_seq_device_exit) 566 567EXPORT_SYMBOL(snd_seq_device_load_drivers); 568EXPORT_SYMBOL(snd_seq_device_new); 569EXPORT_SYMBOL(snd_seq_device_register_driver); 570EXPORT_SYMBOL(snd_seq_device_unregister_driver); 571EXPORT_SYMBOL(snd_seq_autoload_lock); 572EXPORT_SYMBOL(snd_seq_autoload_unlock);