linux/drivers/staging/greybus/audio_manager.c
<<
>>
Prefs
   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>");
 187