1 /* 2 * Apple Onboard Audio driver core 3 * 4 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 5 * 6 * GPL v2, can be found in COPYING. 7 */ 8 9 #include <linux/init.h> 10 #include <linux/module.h> 11 #include <linux/list.h> 12 #include "../aoa.h" 13 #include "alsa.h" 14 15 MODULE_DESCRIPTION("Apple Onboard Audio Sound Driver"); 16 MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>"); 17 MODULE_LICENSE("GPL"); 18 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); 23 24 static int attach_codec_to_fabric(struct aoa_codec *c) 25 { 26 int err; 27 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; 39 } 40 c->fabric = fabric; 41 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; 52 } 53 if (fabric->attached_codec) 54 fabric->attached_codec(c); 55 return 0; 56 } 57 58 int aoa_codec_register(struct aoa_codec *codec) 59 { 60 int err = 0; 61 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; 70 } 71 EXPORT_SYMBOL_GPL(aoa_codec_register); 72 73 void aoa_codec_unregister(struct aoa_codec *codec) 74 { 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); 82 } 83 EXPORT_SYMBOL_GPL(aoa_codec_unregister); 84 85 int aoa_fabric_register(struct aoa_fabric *new_fabric, struct device *dev) 86 { 87 struct aoa_codec *c; 88 int err; 89 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; 95 } 96 if (fabric) 97 return -EEXIST; 98 if (!new_fabric) 99 return -EINVAL; 100 101 err = aoa_alsa_init(new_fabric->name, new_fabric->owner, dev); 102 if (err) 103 return err; 104 105 fabric = new_fabric; 106 107 attach: 108 list_for_each_entry(c, &codec_list, list) { 109 if (c->fabric != fabric) 110 attach_codec_to_fabric(c); 111 } 112 return err; 113 } 114 EXPORT_SYMBOL_GPL(aoa_fabric_register); 115 116 void aoa_fabric_unregister(struct aoa_fabric *old_fabric) 117 { 118 struct aoa_codec *c; 119 120 if (fabric != old_fabric) 121 return; 122 123 list_for_each_entry(c, &codec_list, list) { 124 if (c->fabric) 125 aoa_fabric_unlink_codec(c); 126 } 127 128 aoa_alsa_cleanup(); 129 130 fabric = NULL; 131 } 132 EXPORT_SYMBOL_GPL(aoa_fabric_unregister); 133 134 void aoa_fabric_unlink_codec(struct aoa_codec *codec) 135 { 136 if (!codec->fabric) { 137 printk(KERN_ERR "snd-aoa: fabric unassigned " 138 "in aoa_fabric_unlink_codec\n"); 139 dump_stack(); 140 return; 141 } 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); 148 } 149 EXPORT_SYMBOL_GPL(aoa_fabric_unlink_codec); 150 151 static int __init aoa_init(void) 152 { 153 return 0; 154 } 155 156 static void __exit aoa_exit(void) 157 { 158 aoa_alsa_cleanup(); 159 } 160 161 module_init(aoa_init); 162 module_exit(aoa_exit); 163