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