Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Greybus operations
0004  *
0005  * Copyright 2015-2016 Google Inc.
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 /* helpers */
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 /* public API */
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     /* Add it to the list */
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  * module init/deinit
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>");