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