0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/init.h>
0009 #include <linux/module.h>
0010 #include <linux/list.h>
0011 #include "../aoa.h"
0012 #include "alsa.h"
0013
0014 MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver");
0015 MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
0016 MODULE_LICENSE("GPL");
0017
0018
0019
0020 static struct aoa_fabric *fabric;
0021 static LIST_HEAD(codec_list);
0022
0023 static int attach_codec_to_fabric(struct aoa_codec *c)
0024 {
0025 int err;
0026
0027 if (!try_module_get(c->owner))
0028 return -EBUSY;
0029
0030 err = -ENOENT;
0031 if (fabric->found_codec)
0032 err = fabric->found_codec(c);
0033 if (err) {
0034 module_put(c->owner);
0035 printk(KERN_ERR "snd-aoa: fabric didn't like codec %s\n",
0036 c->name);
0037 return err;
0038 }
0039 c->fabric = fabric;
0040
0041 err = 0;
0042 if (c->init)
0043 err = c->init(c);
0044 if (err) {
0045 printk(KERN_ERR "snd-aoa: codec %s didn't init\n", c->name);
0046 c->fabric = NULL;
0047 if (fabric->remove_codec)
0048 fabric->remove_codec(c);
0049 module_put(c->owner);
0050 return err;
0051 }
0052 if (fabric->attached_codec)
0053 fabric->attached_codec(c);
0054 return 0;
0055 }
0056
0057 int aoa_codec_register(struct aoa_codec *codec)
0058 {
0059 int err = 0;
0060
0061
0062
0063
0064 if (fabric)
0065 err = attach_codec_to_fabric(codec);
0066 if (!err)
0067 list_add(&codec->list, &codec_list);
0068 return err;
0069 }
0070 EXPORT_SYMBOL_GPL(aoa_codec_register);
0071
0072 void aoa_codec_unregister(struct aoa_codec *codec)
0073 {
0074 list_del(&codec->list);
0075 if (codec->fabric && codec->exit)
0076 codec->exit(codec);
0077 if (fabric && fabric->remove_codec)
0078 fabric->remove_codec(codec);
0079 codec->fabric = NULL;
0080 module_put(codec->owner);
0081 }
0082 EXPORT_SYMBOL_GPL(aoa_codec_unregister);
0083
0084 int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev)
0085 {
0086 struct aoa_codec *c;
0087 int err;
0088
0089
0090
0091 if (new_fabric == fabric) {
0092 err = -EALREADY;
0093 goto attach;
0094 }
0095 if (fabric)
0096 return -EEXIST;
0097 if (!new_fabric)
0098 return -EINVAL;
0099
0100 err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev);
0101 if (err)
0102 return err;
0103
0104 fabric = new_fabric;
0105
0106 attach:
0107 list_for_each_entry(c, &codec_list, list) {
0108 if (c->fabric != fabric)
0109 attach_codec_to_fabric(c);
0110 }
0111 return err;
0112 }
0113 EXPORT_SYMBOL_GPL(aoa_fabric_register);
0114
0115 void aoa_fabric_unregister(struct aoa_fabric *old_fabric)
0116 {
0117 struct aoa_codec *c;
0118
0119 if (fabric != old_fabric)
0120 return;
0121
0122 list_for_each_entry(c, &codec_list, list) {
0123 if (c->fabric)
0124 aoa_fabric_unlink_codec(c);
0125 }
0126
0127 aoa_alsa_cleanup();
0128
0129 fabric = NULL;
0130 }
0131 EXPORT_SYMBOL_GPL(aoa_fabric_unregister);
0132
0133 void aoa_fabric_unlink_codec(struct aoa_codec *codec)
0134 {
0135 if (!codec->fabric) {
0136 printk(KERN_ERR "snd-aoa: fabric unassigned "
0137 "in aoa_fabric_unlink_codec\n");
0138 dump_stack();
0139 return;
0140 }
0141 if (codec->exit)
0142 codec->exit(codec);
0143 if (codec->fabric->remove_codec)
0144 codec->fabric->remove_codec(codec);
0145 codec->fabric = NULL;
0146 module_put(codec->owner);
0147 }
0148 EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec);
0149
0150 static int __init aoa_init(void)
0151 {
0152 return 0;
0153 }
0154
0155 static void __exit aoa_exit(void)
0156 {
0157 aoa_alsa_cleanup();
0158 }
0159
0160 module_init(aoa_init);
0161 module_exit(aoa_exit);