| changeset 5876: | 2d6164f0bf0e |
| parent: | d773ad622068 |
| author: | tiwai |
| date: | Tue Feb 19 11:56:06 2008 +0100 (4 years ago) |
| permissions: | -rw-r--r-- |
| description: | Dont touch fs_struct in drivers The sound drivers and the pnpbios core test for current->root != NULL. This test seems to be unnecessary since we always have rootfs mounted before initializing the drivers. Patch-level: Merged Signed-off-by: Jan Blunck <jblunck@suse.de> Acked-by: Christoph Hellwig <hch@lst.de> Cc: Bjorn Helgaas <bjorn.helgaas@hp.com> Cc: Jaroslav Kysela <perex@suse.cz> Acked-by: Takashi Iwai <tiwai@suse.de> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> |
1/*2 * ALSA sequencer device management3 * Copyright (c) 1999 by Takashi Iwai <tiwai@suse.de>4 *5 * This program is free software; you can redistribute it and/or modify6 * it under the terms of the GNU General Public License as published by7 * the Free Software Foundation; either version 2 of the License, or8 * (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 of12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13 * GNU General Public License for more details.14 *15 * You should have received a copy of the GNU General Public License16 * along with this program; if not, write to the Free Software17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18 *19 *20 *----------------------------------------------------------------21 *22 * This device handler separates the card driver module from sequencer23 * stuff (sequencer core, synth drivers, etc), so that user can avoid24 * to spend unnecessary resources e.g. if he needs only listening to25 * MP3s.26 *27 * The card (or lowlevel) driver creates a sequencer device entry28 * via snd_seq_device_new(). This is an entry pointer to communicate29 * with the sequencer device "driver", which is involved with the30 * actual part to communicate with the sequencer core.31 * Each sequencer device entry has an id string and the corresponding32 * driver with the same id is loaded when required. For example,33 * lowlevel codes to access emu8000 chip on sbawe card are included in34 * emu8000-synth module. To activate this module, the hardware35 * resources like i/o port are passed via snd_seq_device argument.36 *37 */3839#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>4849MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");50MODULE_DESCRIPTION("ALSA sequencer device management");51MODULE_LICENSE("GPL");5253/* driver state */54#define DRIVER_EMPTY 055#define DRIVER_LOADED (1<<0)56#define DRIVER_REQUESTED (1<<1)57#define DRIVER_LOCKED (1<<2)5859struct ops_list {60 char id[ID_LEN]; /* driver id */61 int driver; /* driver state */62 int used; /* reference counter */63 int argsize; /* argument size */6465 /* operators */66 struct snd_seq_dev_ops ops;6768 /* 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;7374 struct list_head list; /* next driver */75};767778static LIST_HEAD(opslist);79static int num_ops;80static DEFINE_MUTEX(ops_mutex);81#ifdef CONFIG_PROC_FS82static struct snd_info_entry *info_entry;83#endif8485/*86 * prototypes87 */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);9293static 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);99100/*101 * show all drivers and their status102 */103104#ifdef CONFIG_PROC_FS105static void snd_seq_device_info(struct snd_info_entry *entry,106 struct snd_info_buffer *buffer)107{108 struct ops_list *ops;109110 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#endif122123/*124 * load all registered drivers (called from seq_clientmgr.c)125 */126127#ifdef CONFIG_KMOD128/* 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}134135void snd_seq_autoload_unlock(void)136{137 snd_seq_in_init--;138}139#endif140141void snd_seq_device_load_drivers(void)142{143#ifdef CONFIG_KMOD144 struct ops_list *ops;145146 /* Calling request_module during module_init()147 * may cause blocking.148 */149 if (snd_seq_in_init)150 return;151152 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#endif166}167168/*169 * register a sequencer device170 * card = card info (NULL allowed)171 * device = device number (if any)172 * id = id of driver173 * 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 };186187 if (result)188 *result = NULL;189190 snd_assert(id != NULL, return -EINVAL);191192 ops = find_driver(id, 1);193 if (ops == NULL)194 return -ENOMEM;195196 dev = kzalloc(sizeof(*dev)*2 + argsize, GFP_KERNEL);197 if (dev == NULL) {198 unlock_driver(ops);199 return -ENOMEM;200 }201202 /* set up device info */203 dev->card = card;204 dev->device = device;205 strlcpy(dev->id, id, sizeof(dev->id));206 dev->argsize = argsize;207 dev->status = SNDRV_SEQ_DEVICE_FREE;208209 /* add this device to the list */210 mutex_lock(&ops->reg_mutex);211 list_add_tail(&dev->list, &ops->dev_list);212 ops->num_devices++;213 mutex_unlock(&ops->reg_mutex);214215 unlock_driver(ops);216217 if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {218 snd_seq_device_free(dev);219 return err;220 }221222 if (result)223 *result = dev;224225 return 0;226}227228/*229 * free the existing device230 */231static int snd_seq_device_free(struct snd_seq_device *dev)232{233 struct ops_list *ops;234235 snd_assert(dev != NULL, return -EINVAL);236237 ops = find_driver(dev->id, 0);238 if (ops == NULL)239 return -ENXIO;240241 /* remove the device from the list */242 mutex_lock(&ops->reg_mutex);243 list_del(&dev->list);244 ops->num_devices--;245 mutex_unlock(&ops->reg_mutex);246247 free_device(dev, ops);248 if (dev->private_free)249 dev->private_free(dev);250 kfree(dev);251252 unlock_driver(ops);253254 return 0;255}256257static int snd_seq_device_dev_free(struct snd_device *device)258{259 struct snd_seq_device *dev = device->device_data;260 return snd_seq_device_free(dev);261}262263/*264 * register the device265 */266static int snd_seq_device_dev_register(struct snd_device *device)267{268 struct snd_seq_device *dev = device->device_data;269 struct ops_list *ops;270271 ops = find_driver(dev->id, 0);272 if (ops == NULL)273 return -ENOENT;274275 /* initialize this device if the corresponding driver was276 * already loaded277 */278 if (ops->driver & DRIVER_LOADED)279 init_device(dev, ops);280281 unlock_driver(ops);282 return 0;283}284285/*286 * disconnect the device287 */288static int snd_seq_device_dev_disconnect(struct snd_device *device)289{290 struct snd_seq_device *dev = device->device_data;291 struct ops_list *ops;292293 ops = find_driver(dev->id, 0);294 if (ops == NULL)295 return -ENOENT;296297 free_device(dev, ops);298299 unlock_driver(ops);300 return 0;301}302303/*304 * register device driver305 * id = driver id306 * entry = driver operators - duplicated to each instance307 */308int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,309 int argsize)310{311 struct ops_list *ops;312 struct snd_seq_device *dev;313314 if (id == NULL || entry == NULL ||315 entry->init_device == NULL || entry->free_device == NULL)316 return -EINVAL;317318 snd_seq_autoload_lock();319 ops = find_driver(id, 1);320 if (ops == NULL) {321 snd_seq_autoload_unlock();322 return -ENOMEM;323 }324 if (ops->driver & DRIVER_LOADED) {325 snd_printk(KERN_WARNING "driver_register: driver '%s' already exists\n", id);326 unlock_driver(ops);327 snd_seq_autoload_unlock();328 return -EBUSY;329 }330331 mutex_lock(&ops->reg_mutex);332 /* copy driver operators */333 ops->ops = *entry;334 ops->driver |= DRIVER_LOADED;335 ops->argsize = argsize;336337 /* initialize existing devices if necessary */338 list_for_each_entry(dev, &ops->dev_list, list) {339 init_device(dev, ops);340 }341 mutex_unlock(&ops->reg_mutex);342343 unlock_driver(ops);344 snd_seq_autoload_unlock();345346 return 0;347}348349350/*351 * create driver record352 */353static struct ops_list * create_driver(char *id)354{355 struct ops_list *ops;356357 ops = kzalloc(sizeof(*ops), GFP_KERNEL);358 if (ops == NULL)359 return ops;360361 /* set up driver entry */362 strlcpy(ops->id, id, sizeof(ops->id));363 mutex_init(&ops->reg_mutex);364 /*365 * The ->reg_mutex locking rules are per-driver, so we create366 * separate per-driver lock classes:367 */368 lockdep_set_class(&ops->reg_mutex, (struct lock_class_key *)id);369370 ops->driver = DRIVER_EMPTY;371 INIT_LIST_HEAD(&ops->dev_list);372 /* lock this instance */373 ops->used = 1;374375 /* register driver entry */376 mutex_lock(&ops_mutex);377 list_add_tail(&ops->list, &opslist);378 num_ops++;379 mutex_unlock(&ops_mutex);380381 return ops;382}383384385/*386 * unregister the specified driver387 */388int snd_seq_device_unregister_driver(char *id)389{390 struct ops_list *ops;391 struct snd_seq_device *dev;392393 ops = find_driver(id, 0);394 if (ops == NULL)395 return -ENXIO;396 if (! (ops->driver & DRIVER_LOADED) ||397 (ops->driver & DRIVER_LOCKED)) {398 snd_printk(KERN_ERR "driver_unregister: cannot unload driver '%s': status=%x\n",399 id, ops->driver);400 unlock_driver(ops);401 return -EBUSY;402 }403404 /* close and release all devices associated with this driver */405 mutex_lock(&ops->reg_mutex);406 ops->driver |= DRIVER_LOCKED; /* do not remove this driver recursively */407 list_for_each_entry(dev, &ops->dev_list, list) {408 free_device(dev, ops);409 }410411 ops->driver = 0;412 if (ops->num_init_devices > 0)413 snd_printk(KERN_ERR "free_driver: init_devices > 0!! (%d)\n",414 ops->num_init_devices);415 mutex_unlock(&ops->reg_mutex);416417 unlock_driver(ops);418419 /* remove empty driver entries */420 remove_drivers();421422 return 0;423}424425426/*427 * remove empty driver entries428 */429static void remove_drivers(void)430{431 struct list_head *head;432433 mutex_lock(&ops_mutex);434 head = opslist.next;435 while (head != &opslist) {436 struct ops_list *ops = list_entry(head, struct ops_list, list);437 if (! (ops->driver & DRIVER_LOADED) &&438 ops->used == 0 && ops->num_devices == 0) {439 head = head->next;440 list_del(&ops->list);441 kfree(ops);442 num_ops--;443 } else444 head = head->next;445 }446 mutex_unlock(&ops_mutex);447}448449/*450 * initialize the device - call init_device operator451 */452static int init_device(struct snd_seq_device *dev, struct ops_list *ops)453{454 if (! (ops->driver & DRIVER_LOADED))455 return 0; /* driver is not loaded yet */456 if (dev->status != SNDRV_SEQ_DEVICE_FREE)457 return 0; /* already initialized */458 if (ops->argsize != dev->argsize) {459 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",460 dev->name, ops->id, ops->argsize, dev->argsize);461 return -EINVAL;462 }463 if (ops->ops.init_device(dev) >= 0) {464 dev->status = SNDRV_SEQ_DEVICE_REGISTERED;465 ops->num_init_devices++;466 } else {467 snd_printk(KERN_ERR "init_device failed: %s: %s\n",468 dev->name, dev->id);469 }470471 return 0;472}473474/*475 * release the device - call free_device operator476 */477static int free_device(struct snd_seq_device *dev, struct ops_list *ops)478{479 int result;480481 if (! (ops->driver & DRIVER_LOADED))482 return 0; /* driver is not loaded yet */483 if (dev->status != SNDRV_SEQ_DEVICE_REGISTERED)484 return 0; /* not registered */485 if (ops->argsize != dev->argsize) {486 snd_printk(KERN_ERR "incompatible device '%s' for plug-in '%s' (%d %d)\n",487 dev->name, ops->id, ops->argsize, dev->argsize);488 return -EINVAL;489 }490 if ((result = ops->ops.free_device(dev)) >= 0 || result == -ENXIO) {491 dev->status = SNDRV_SEQ_DEVICE_FREE;492 dev->driver_data = NULL;493 ops->num_init_devices--;494 } else {495 snd_printk(KERN_ERR "free_device failed: %s: %s\n",496 dev->name, dev->id);497 }498499 return 0;500}501502/*503 * find the matching driver with given id504 */505static struct ops_list * find_driver(char *id, int create_if_empty)506{507 struct ops_list *ops;508509 mutex_lock(&ops_mutex);510 list_for_each_entry(ops, &opslist, list) {511 if (strcmp(ops->id, id) == 0) {512 ops->used++;513 mutex_unlock(&ops_mutex);514 return ops;515 }516 }517 mutex_unlock(&ops_mutex);518 if (create_if_empty)519 return create_driver(id);520 return NULL;521}522523static void unlock_driver(struct ops_list *ops)524{525 mutex_lock(&ops_mutex);526 ops->used--;527 mutex_unlock(&ops_mutex);528}529530531/*532 * module part533 */534535static int __init alsa_seq_device_init(void)536{537#ifdef CONFIG_PROC_FS538 info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",539 snd_seq_root);540 if (info_entry == NULL)541 return -ENOMEM;542 info_entry->content = SNDRV_INFO_CONTENT_TEXT;543 info_entry->c.text.read = snd_seq_device_info;544 if (snd_info_register(info_entry) < 0) {545 snd_info_free_entry(info_entry);546 return -ENOMEM;547 }548#endif549 return 0;550}551552static void __exit alsa_seq_device_exit(void)553{554 remove_drivers();555#ifdef CONFIG_PROC_FS556 snd_info_free_entry(info_entry);557#endif558 if (num_ops)559 snd_printk(KERN_ERR "drivers not released (%d)\n", num_ops);560}561562module_init(alsa_seq_device_init)563module_exit(alsa_seq_device_exit)564565EXPORT_SYMBOL(snd_seq_device_load_drivers);566EXPORT_SYMBOL(snd_seq_device_new);567EXPORT_SYMBOL(snd_seq_device_register_driver);568EXPORT_SYMBOL(snd_seq_device_unregister_driver);569#ifdef CONFIG_KMOD570EXPORT_SYMBOL(snd_seq_autoload_lock);571EXPORT_SYMBOL(snd_seq_autoload_unlock);572#endif