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