audio_manager.c (3893B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Greybus operations 4 * 5 * Copyright 2015-2016 Google Inc. 6 */ 7 8#include <linux/string.h> 9#include <linux/sysfs.h> 10#include <linux/module.h> 11#include <linux/init.h> 12#include <linux/spinlock.h> 13#include <linux/idr.h> 14 15#include "audio_manager.h" 16#include "audio_manager_private.h" 17 18static struct kset *manager_kset; 19 20static LIST_HEAD(modules_list); 21static DECLARE_RWSEM(modules_rwsem); 22static DEFINE_IDA(module_id); 23 24/* helpers */ 25static struct gb_audio_manager_module *gb_audio_manager_get_locked(int id) 26{ 27 struct gb_audio_manager_module *module; 28 29 if (id < 0) 30 return NULL; 31 32 list_for_each_entry(module, &modules_list, list) { 33 if (module->id == id) 34 return module; 35 } 36 37 return NULL; 38} 39 40/* public API */ 41int gb_audio_manager_add(struct gb_audio_manager_module_descriptor *desc) 42{ 43 struct gb_audio_manager_module *module; 44 int id; 45 int err; 46 47 id = ida_simple_get(&module_id, 0, 0, GFP_KERNEL); 48 if (id < 0) 49 return id; 50 51 err = gb_audio_manager_module_create(&module, manager_kset, 52 id, desc); 53 if (err) { 54 ida_simple_remove(&module_id, id); 55 return err; 56 } 57 58 /* Add it to the list */ 59 down_write(&modules_rwsem); 60 list_add_tail(&module->list, &modules_list); 61 up_write(&modules_rwsem); 62 63 return module->id; 64} 65EXPORT_SYMBOL_GPL(gb_audio_manager_add); 66 67int gb_audio_manager_remove(int id) 68{ 69 struct gb_audio_manager_module *module; 70 71 down_write(&modules_rwsem); 72 73 module = gb_audio_manager_get_locked(id); 74 if (!module) { 75 up_write(&modules_rwsem); 76 return -EINVAL; 77 } 78 list_del(&module->list); 79 kobject_put(&module->kobj); 80 up_write(&modules_rwsem); 81 ida_simple_remove(&module_id, id); 82 return 0; 83} 84EXPORT_SYMBOL_GPL(gb_audio_manager_remove); 85 86void gb_audio_manager_remove_all(void) 87{ 88 struct gb_audio_manager_module *module, *next; 89 int is_empty; 90 91 down_write(&modules_rwsem); 92 93 list_for_each_entry_safe(module, next, &modules_list, list) { 94 list_del(&module->list); 95 ida_simple_remove(&module_id, module->id); 96 kobject_put(&module->kobj); 97 } 98 99 is_empty = list_empty(&modules_list); 100 101 up_write(&modules_rwsem); 102 103 if (!is_empty) 104 pr_warn("Not all nodes were deleted\n"); 105} 106EXPORT_SYMBOL_GPL(gb_audio_manager_remove_all); 107 108struct gb_audio_manager_module *gb_audio_manager_get_module(int id) 109{ 110 struct gb_audio_manager_module *module; 111 112 down_read(&modules_rwsem); 113 module = gb_audio_manager_get_locked(id); 114 kobject_get(&module->kobj); 115 up_read(&modules_rwsem); 116 return module; 117} 118EXPORT_SYMBOL_GPL(gb_audio_manager_get_module); 119 120void gb_audio_manager_put_module(struct gb_audio_manager_module *module) 121{ 122 kobject_put(&module->kobj); 123} 124EXPORT_SYMBOL_GPL(gb_audio_manager_put_module); 125 126int gb_audio_manager_dump_module(int id) 127{ 128 struct gb_audio_manager_module *module; 129 130 down_read(&modules_rwsem); 131 module = gb_audio_manager_get_locked(id); 132 up_read(&modules_rwsem); 133 134 if (!module) 135 return -EINVAL; 136 137 gb_audio_manager_module_dump(module); 138 return 0; 139} 140EXPORT_SYMBOL_GPL(gb_audio_manager_dump_module); 141 142void gb_audio_manager_dump_all(void) 143{ 144 struct gb_audio_manager_module *module; 145 int count = 0; 146 147 down_read(&modules_rwsem); 148 list_for_each_entry(module, &modules_list, list) { 149 gb_audio_manager_module_dump(module); 150 count++; 151 } 152 up_read(&modules_rwsem); 153 154 pr_info("Number of connected modules: %d\n", count); 155} 156EXPORT_SYMBOL_GPL(gb_audio_manager_dump_all); 157 158/* 159 * module init/deinit 160 */ 161static int __init manager_init(void) 162{ 163 manager_kset = kset_create_and_add(GB_AUDIO_MANAGER_NAME, NULL, 164 kernel_kobj); 165 if (!manager_kset) 166 return -ENOMEM; 167 168#ifdef GB_AUDIO_MANAGER_SYSFS 169 gb_audio_manager_sysfs_init(&manager_kset->kobj); 170#endif 171 172 return 0; 173} 174 175static void __exit manager_exit(void) 176{ 177 gb_audio_manager_remove_all(); 178 kset_unregister(manager_kset); 179 ida_destroy(&module_id); 180} 181 182module_init(manager_init); 183module_exit(manager_exit); 184 185MODULE_LICENSE("GPL"); 186MODULE_AUTHOR("Svetlin Ankov <ankov_svetlin@projectara.com>");