Merge tag 'regulator-fix-v5.6-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / sound / aoa / core / core.c
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
14 MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
15 MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
16 MODULE_LICENSE("GPL");
17
18 /* We allow only one fabric. This simplifies things,
19  * and more don't really make that much sense */
20 static struct aoa_fabric *fabric;
21 static LIST_HEAD(codec_list);
22
23 static 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
57 int 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 }
70 EXPORT_SYMBOL_GPL(aoa_codec_register);
71
72 void 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 }
82 EXPORT_SYMBOL_GPL(aoa_codec_unregister);
83
84 int 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 }
113 EXPORT_SYMBOL_GPL(aoa_fabric_register);
114
115 void 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 }
131 EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
132
133 void 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 }
148 EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
149
150 static int __init aoa_init(void)
151 {
152         return 0;
153 }
154
155 static void __exit aoa_exit(void)
156 {
157         aoa_alsa_cleanup();
158 }
159
160 module_init(aoa_init);
161 module_exit(aoa_exit);