Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-btrfs-devel.git] / sound / aoa / core / core.c
blob10bec6c6138203463c3368766295b9c79ebd858d
1 /*
2 * Apple Onboard Audio driver core
4 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
6 * GPL v2, can be found in COPYING.
7 */
9 #include <linux/init.h>
10 #include <linux/module.h>
11 #include <linux/list.h>
12 #include "../aoa.h"
13 #include "alsa.h"
15 MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
16 MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
17 MODULE_LICENSE("GPL");
19 /* We allow only one fabric. This simplifies things,
20 * and more don't really make that much sense */
21 static struct aoa_fabric *fabric;
22 static LIST_HEAD(codec_list);
24 static int attach_codec_to_fabric(struct aoa_codec *c)
26 int err;
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;
40 c->fabric = fabric;
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;
53 if (fabric->attached_codec)
54 fabric->attached_codec(c);
55 return 0;
58 int aoa_codec_register(struct aoa_codec *codec)
60 int err = 0;
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;
71 EXPORT_SYMBOL_GPL(aoa_codec_register);
73 void aoa_codec_unregister(struct aoa_codec *codec)
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);
83 EXPORT_SYMBOL_GPL(aoa_codec_unregister);
85 int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
87 struct aoa_codec *c;
88 int err;
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;
96 if (fabric)
97 return -EEXIST;
98 if (!new_fabric)
99 return -EINVAL;
101 err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
102 if (err)
103 return err;
105 fabric = new_fabric;
107 attach:
108 list_for_each_entry(c, &codec_list, list) {
109 if (c->fabric != fabric)
110 attach_codec_to_fabric(c);
112 return err;
114 EXPORT_SYMBOL_GPL(aoa_fabric_register);
116 void aoa_fabric_unregister(struct aoa_fabric *old_fabric)
118 struct aoa_codec *c;
120 if (fabric != old_fabric)
121 return;
123 list_for_each_entry(c, &codec_list, list) {
124 if (c->fabric)
125 aoa_fabric_unlink_codec(c);
128 aoa_alsa_cleanup();
130 fabric = NULL;
132 EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
134 void aoa_fabric_unlink_codec(struct aoa_codec *codec)
136 if (!codec->fabric) {
137 printk(KERN_ERR "snd-aoa: fabric unassigned "
138 "in aoa_fabric_unlink_codec\n");
139 dump_stack();
140 return;
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);
149 EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
151 static int __init aoa_init(void)
153 return 0;
156 static void __exit aoa_exit(void)
158 aoa_alsa_cleanup();
161 module_init(aoa_init);
162 module_exit(aoa_exit);