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