linux/sound/aoa/core/core.c
<<
>>
Prefs
   1/*
   2 * Apple Onboard Audio driver core
   3 *
   4 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
   5 *
   6 * GPL v2, can be found in COPYING.
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/module.h>
  11#include <linux/list.h>
  12#include "../aoa.h"
  13#include "alsa.h"
  14
  15MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
  16MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
  17MODULE_LICENSE("GPL");
  18
  19/* We allow only one fabric. This simplifies things,
  20 * and more don't really make that much sense */
  21static struct aoa_fabric *fabric;
  22static LIST_HEAD(codec_list);
  23
  24static int attach_codec_to_fabric(struct aoa_codec *c)
  25{
  26        int err;
  27
  28        if (!try_module_get(c->owner))
  29                return -EBUSY;
  30        /* found_codec has to be assigned */
  31        err = -ENOENT;
  32        if (fabric->found_codec)
  33                err = fabric->found_codec(c);
  34        if (err) {
  35                module_put(c->owner);
  36                printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n",
  37                                c->name);
  38                return err;
  39        }
  40        c->fabric = fabric;
  41
  42        err = 0;
  43        if (c->init)
  44                err = c->init(c);
  45        if (err) {
  46                printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name);
  47                c->fabric = NULL;
  48                if (fabric->remove_codec)
  49                        fabric->remove_codec(c);
  50                module_put(c->owner);
  51                return err;
  52        }
  53        if (fabric->attached_codec)
  54                fabric->attached_codec(c);
  55        return 0;
  56}
  57
  58int aoa_codec_register(struct aoa_codec *codec)
  59{
  60        int err = 0;
  61
  62        /* if there's a fabric already, we can tell if we
  63         * will want to have this codec, so propagate error
  64         * through. Otherwise, this will happen later... */
  65        if (fabric)
  66                err = attach_codec_to_fabric(codec);
  67        if (!err)
  68                list_add(&codec->list, &codec_list);
  69        return err;
  70}
  71EXPORT_SYMBOL_GPL(aoa_codec_register);
  72
  73void aoa_codec_unregister(struct aoa_codec *codec)
  74{
  75        list_del(&codec->list);
  76        if (codec->fabric && codec->exit)
  77                codec->exit(codec);
  78        if (fabric && fabric->remove_codec)
  79                fabric->remove_codec(codec);
  80        codec->fabric = NULL;
  81        module_put(codec->owner);
  82}
  83EXPORT_SYMBOL_GPL(aoa_codec_unregister);
  84
  85int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
  86{
  87        struct aoa_codec *c;
  88        int err;
  89
  90        /* allow querying for presence of fabric
  91         * (i.e. do this test first!) */
  92        if (new_fabric == fabric) {
  93                err = -EALREADY;
  94                goto attach;
  95        }
  96        if (fabric)
  97                return -EEXIST;
  98        if (!new_fabric)
  99                return -EINVAL;
 100
 101        err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
 102        if (err)
 103                return err;
 104
 105        fabric = new_fabric;
 106
 107 attach:
 108        list_for_each_entry(c, &codec_list, list) {
 109                if (c->fabric != fabric)
 110                        attach_codec_to_fabric(c);
 111        }
 112        return err;
 113}
 114EXPORT_SYMBOL_GPL(aoa_fabric_register);
 115
 116void aoa_fabric_unregister(struct aoa_fabric *old_fabric)
 117{
 118        struct aoa_codec *c;
 119
 120        if (fabric != old_fabric)
 121                return;
 122
 123        list_for_each_entry(c, &codec_list, list) {
 124                if (c->fabric)
 125                        aoa_fabric_unlink_codec(c);
 126        }
 127
 128        aoa_alsa_cleanup();
 129
 130        fabric = NULL;
 131}
 132EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
 133
 134void aoa_fabric_unlink_codec(struct aoa_codec *codec)
 135{
 136        if (!codec->fabric) {
 137                printk(KERN_ERR "snd-aoa: fabric unassigned "
 138                                "in aoa_fabric_unlink_codec\n");
 139                dump_stack();
 140                return;
 141        }
 142        if (codec->exit)
 143                codec->exit(codec);
 144        if (codec->fabric->remove_codec)
 145                codec->fabric->remove_codec(codec);
 146        codec->fabric = NULL;
 147        module_put(codec->owner);
 148}
 149EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
 150
 151static int __init aoa_init(void)
 152{
 153        return 0;
 154}
 155
 156static void __exit aoa_exit(void)
 157{
 158        aoa_alsa_cleanup();
 159}
 160
 161module_init(aoa_init);
 162module_exit(aoa_exit);
 163