Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Apple Onboard Audio driver core
0004  *
0005  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
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 /* We allow only one fabric. This simplifies things,
0019  * and more don't really make that much sense */
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     /* found_codec has to be assigned */
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     /* if there's a fabric already, we can tell if we
0062      * will want to have this codec, so propagate error
0063      * through. Otherwise, this will happen later... */
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     /* allow querying for presence of fabric
0090      * (i.e. do this test first!) */
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);