0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/string.h>
0009 #include <linux/sysfs.h>
0010 #include <linux/module.h>
0011 #include <linux/init.h>
0012 #include <linux/spinlock.h>
0013 #include <linux/idr.h>
0014
0015 #include "audio_manager.h"
0016 #include "audio_manager_private.h"
0017
0018 static struct kset *manager_kset;
0019
0020 static LIST_HEAD(modules_list);
0021 static DECLARE_RWSEM(modules_rwsem);
0022 static DEFINE_IDA(module_id);
0023
0024
0025 static struct gb_audio_manager_module *gb_audio_manager_get_locked(int id)
0026 {
0027 struct gb_audio_manager_module *module;
0028
0029 if (id < 0)
0030 return NULL;
0031
0032 list_for_each_entry(module, &modules_list, list) {
0033 if (module->id == id)
0034 return module;
0035 }
0036
0037 return NULL;
0038 }
0039
0040
0041 int gb_audio_manager_add(struct gb_audio_manager_module_descriptor *desc)
0042 {
0043 struct gb_audio_manager_module *module;
0044 int id;
0045 int err;
0046
0047 id = ida_simple_get(&module_id, 0, 0, GFP_KERNEL);
0048 if (id < 0)
0049 return id;
0050
0051 err = gb_audio_manager_module_create(&module, manager_kset,
0052 id, desc);
0053 if (err) {
0054 ida_simple_remove(&module_id, id);
0055 return err;
0056 }
0057
0058
0059 down_write(&modules_rwsem);
0060 list_add_tail(&module->list, &modules_list);
0061 up_write(&modules_rwsem);
0062
0063 return module->id;
0064 }
0065 EXPORT_SYMBOL_GPL(gb_audio_manager_add);
0066
0067 int gb_audio_manager_remove(int id)
0068 {
0069 struct gb_audio_manager_module *module;
0070
0071 down_write(&modules_rwsem);
0072
0073 module = gb_audio_manager_get_locked(id);
0074 if (!module) {
0075 up_write(&modules_rwsem);
0076 return -EINVAL;
0077 }
0078 list_del(&module->list);
0079 kobject_put(&module->kobj);
0080 up_write(&modules_rwsem);
0081 ida_simple_remove(&module_id, id);
0082 return 0;
0083 }
0084 EXPORT_SYMBOL_GPL(gb_audio_manager_remove);
0085
0086 void gb_audio_manager_remove_all(void)
0087 {
0088 struct gb_audio_manager_module *module, *next;
0089 int is_empty;
0090
0091 down_write(&modules_rwsem);
0092
0093 list_for_each_entry_safe(module, next, &modules_list, list) {
0094 list_del(&module->list);
0095 ida_simple_remove(&module_id, module->id);
0096 kobject_put(&module->kobj);
0097 }
0098
0099 is_empty = list_empty(&modules_list);
0100
0101 up_write(&modules_rwsem);
0102
0103 if (!is_empty)
0104 pr_warn("Not all nodes were deleted\n");
0105 }
0106 EXPORT_SYMBOL_GPL(gb_audio_manager_remove_all);
0107
0108 struct gb_audio_manager_module *gb_audio_manager_get_module(int id)
0109 {
0110 struct gb_audio_manager_module *module;
0111
0112 down_read(&modules_rwsem);
0113 module = gb_audio_manager_get_locked(id);
0114 kobject_get(&module->kobj);
0115 up_read(&modules_rwsem);
0116 return module;
0117 }
0118 EXPORT_SYMBOL_GPL(gb_audio_manager_get_module);
0119
0120 void gb_audio_manager_put_module(struct gb_audio_manager_module *module)
0121 {
0122 kobject_put(&module->kobj);
0123 }
0124 EXPORT_SYMBOL_GPL(gb_audio_manager_put_module);
0125
0126 int gb_audio_manager_dump_module(int id)
0127 {
0128 struct gb_audio_manager_module *module;
0129
0130 down_read(&modules_rwsem);
0131 module = gb_audio_manager_get_locked(id);
0132 up_read(&modules_rwsem);
0133
0134 if (!module)
0135 return -EINVAL;
0136
0137 gb_audio_manager_module_dump(module);
0138 return 0;
0139 }
0140 EXPORT_SYMBOL_GPL(gb_audio_manager_dump_module);
0141
0142 void gb_audio_manager_dump_all(void)
0143 {
0144 struct gb_audio_manager_module *module;
0145 int count = 0;
0146
0147 down_read(&modules_rwsem);
0148 list_for_each_entry(module, &modules_list, list) {
0149 gb_audio_manager_module_dump(module);
0150 count++;
0151 }
0152 up_read(&modules_rwsem);
0153
0154 pr_info("Number of connected modules: %d\n", count);
0155 }
0156 EXPORT_SYMBOL_GPL(gb_audio_manager_dump_all);
0157
0158
0159
0160
0161 static int __init manager_init(void)
0162 {
0163 manager_kset = kset_create_and_add(GB_AUDIO_MANAGER_NAME, NULL,
0164 kernel_kobj);
0165 if (!manager_kset)
0166 return -ENOMEM;
0167
0168 #ifdef GB_AUDIO_MANAGER_SYSFS
0169 gb_audio_manager_sysfs_init(&manager_kset->kobj);
0170 #endif
0171
0172 return 0;
0173 }
0174
0175 static void __exit manager_exit(void)
0176 {
0177 gb_audio_manager_remove_all();
0178 kset_unregister(manager_kset);
0179 ida_destroy(&module_id);
0180 }
0181
0182 module_init(manager_init);
0183 module_exit(manager_exit);
0184
0185 MODULE_LICENSE("GPL");
0186 MODULE_AUTHOR("Svetlin Ankov <ankov_svetlin@projectara.com>");