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); 162