Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/core/seq/seq_device.c
10817 views
1
/*
2
* ALSA sequencer device management
3
* Copyright (c) 1999 by Takashi Iwai <[email protected]>
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
49
MODULE_AUTHOR("Takashi Iwai <[email protected]>");
50
MODULE_DESCRIPTION("ALSA sequencer device management");
51
MODULE_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
59
struct 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
78
static LIST_HEAD(opslist);
79
static int num_ops;
80
static DEFINE_MUTEX(ops_mutex);
81
#ifdef CONFIG_PROC_FS
82
static struct snd_info_entry *info_entry;
83
#endif
84
85
/*
86
* prototypes
87
*/
88
static int snd_seq_device_free(struct snd_seq_device *dev);
89
static int snd_seq_device_dev_free(struct snd_device *device);
90
static int snd_seq_device_dev_register(struct snd_device *device);
91
static int snd_seq_device_dev_disconnect(struct snd_device *device);
92
93
static int init_device(struct snd_seq_device *dev, struct ops_list *ops);
94
static int free_device(struct snd_seq_device *dev, struct ops_list *ops);
95
static struct ops_list *find_driver(char *id, int create_if_empty);
96
static struct ops_list *create_driver(char *id);
97
static void unlock_driver(struct ops_list *ops);
98
static void remove_drivers(void);
99
100
/*
101
* show all drivers and their status
102
*/
103
104
#ifdef CONFIG_PROC_FS
105
static 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() */
129
static int snd_seq_in_init;
130
void snd_seq_autoload_lock(void)
131
{
132
snd_seq_in_init++;
133
}
134
135
void snd_seq_autoload_unlock(void)
136
{
137
snd_seq_in_init--;
138
}
139
#endif
140
141
void 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
*/
175
int 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
*/
232
static 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
259
static 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
*/
268
static 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
*/
290
static 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
*/
310
int 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
*/
355
static 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
*/
390
int 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
*/
431
static 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
*/
454
static 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
*/
479
static 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
*/
507
static 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
525
static 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
537
static 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
554
static 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
564
module_init(alsa_seq_device_init)
565
module_exit(alsa_seq_device_exit)
566
567
EXPORT_SYMBOL(snd_seq_device_load_drivers);
568
EXPORT_SYMBOL(snd_seq_device_new);
569
EXPORT_SYMBOL(snd_seq_device_register_driver);
570
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
571
EXPORT_SYMBOL(snd_seq_autoload_lock);
572
EXPORT_SYMBOL(snd_seq_autoload_unlock);
573
574