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(module: 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(module: 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(module: 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(c: codec);
66 if (!err)
67 list_add(new: &codec->list, head: &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(entry: &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(module: 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(name: new_fabric->name, mod: 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(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(module: 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

source code of linux/sound/aoa/core/core.c