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