]> Git Repo - J-linux.git/blob - drivers/isdn/mISDN/dsp_pipeline.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / isdn / mISDN / dsp_pipeline.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * dsp_pipeline.c: pipelined audio processing
4  *
5  * Copyright (C) 2007, Nadi Sarrar
6  *
7  * Nadi Sarrar <[email protected]>
8  */
9
10 #include <linux/kernel.h>
11 #include <linux/slab.h>
12 #include <linux/list.h>
13 #include <linux/string.h>
14 #include <linux/mISDNif.h>
15 #include <linux/mISDNdsp.h>
16 #include <linux/export.h>
17 #include "dsp.h"
18 #include "dsp_hwec.h"
19
20 struct dsp_pipeline_entry {
21         struct mISDN_dsp_element *elem;
22         void                *p;
23         struct list_head     list;
24 };
25 struct dsp_element_entry {
26         struct mISDN_dsp_element *elem;
27         struct device        dev;
28         struct list_head     list;
29 };
30
31 static LIST_HEAD(dsp_elements);
32
33 /* sysfs */
34 static const struct class elements_class = {
35         .name = "dsp_pipeline",
36 };
37
38 static ssize_t
39 attr_show_args(struct device *dev, struct device_attribute *attr, char *buf)
40 {
41         struct mISDN_dsp_element *elem = dev_get_drvdata(dev);
42         int i;
43         char *p = buf;
44
45         *buf = 0;
46         for (i = 0; i < elem->num_args; i++)
47                 p += sprintf(p, "Name:        %s\n%s%s%sDescription: %s\n\n",
48                              elem->args[i].name,
49                              elem->args[i].def ? "Default:     " : "",
50                              elem->args[i].def ? elem->args[i].def : "",
51                              elem->args[i].def ? "\n" : "",
52                              elem->args[i].desc);
53
54         return p - buf;
55 }
56
57 static struct device_attribute element_attributes[] = {
58         __ATTR(args, 0444, attr_show_args, NULL),
59 };
60
61 static void
62 mISDN_dsp_dev_release(struct device *dev)
63 {
64         struct dsp_element_entry *entry =
65                 container_of(dev, struct dsp_element_entry, dev);
66         list_del(&entry->list);
67         kfree(entry);
68 }
69
70 int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
71 {
72         struct dsp_element_entry *entry;
73         int ret, i;
74
75         if (!elem)
76                 return -EINVAL;
77
78         entry = kzalloc(sizeof(struct dsp_element_entry), GFP_ATOMIC);
79         if (!entry)
80                 return -ENOMEM;
81
82         INIT_LIST_HEAD(&entry->list);
83         entry->elem = elem;
84
85         entry->dev.class = &elements_class;
86         entry->dev.release = mISDN_dsp_dev_release;
87         dev_set_drvdata(&entry->dev, elem);
88         dev_set_name(&entry->dev, "%s", elem->name);
89         ret = device_register(&entry->dev);
90         if (ret) {
91                 printk(KERN_ERR "%s: failed to register %s\n",
92                        __func__, elem->name);
93                 goto err1;
94         }
95         list_add_tail(&entry->list, &dsp_elements);
96
97         for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) {
98                 ret = device_create_file(&entry->dev,
99                                          &element_attributes[i]);
100                 if (ret) {
101                         printk(KERN_ERR "%s: failed to create device file\n",
102                                __func__);
103                         goto err2;
104                 }
105         }
106
107         return 0;
108
109 err2:
110         device_unregister(&entry->dev);
111         return ret;
112 err1:
113         put_device(&entry->dev);
114         return ret;
115 }
116 EXPORT_SYMBOL(mISDN_dsp_element_register);
117
118 void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem)
119 {
120         struct dsp_element_entry *entry, *n;
121
122         if (!elem)
123                 return;
124
125         list_for_each_entry_safe(entry, n, &dsp_elements, list)
126                 if (entry->elem == elem) {
127                         device_unregister(&entry->dev);
128                         return;
129                 }
130         printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);
131 }
132 EXPORT_SYMBOL(mISDN_dsp_element_unregister);
133
134 int dsp_pipeline_module_init(void)
135 {
136         int err;
137
138         err = class_register(&elements_class);
139         if (err)
140                 return err;
141
142         dsp_hwec_init();
143
144         return 0;
145 }
146
147 void dsp_pipeline_module_exit(void)
148 {
149         struct dsp_element_entry *entry, *n;
150
151         dsp_hwec_exit();
152
153         class_unregister(&elements_class);
154
155         list_for_each_entry_safe(entry, n, &dsp_elements, list) {
156                 list_del(&entry->list);
157                 printk(KERN_WARNING "%s: element was still registered: %s\n",
158                        __func__, entry->elem->name);
159                 kfree(entry);
160         }
161 }
162
163 int dsp_pipeline_init(struct dsp_pipeline *pipeline)
164 {
165         if (!pipeline)
166                 return -EINVAL;
167
168         INIT_LIST_HEAD(&pipeline->list);
169
170         return 0;
171 }
172
173 static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
174 {
175         struct dsp_pipeline_entry *entry, *n;
176
177         list_for_each_entry_safe(entry, n, &pipeline->list, list) {
178                 list_del(&entry->list);
179                 if (entry->elem == dsp_hwec)
180                         dsp_hwec_disable(container_of(pipeline, struct dsp,
181                                                       pipeline));
182                 else
183                         entry->elem->free(entry->p);
184                 kfree(entry);
185         }
186 }
187
188 void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
189 {
190
191         if (!pipeline)
192                 return;
193
194         _dsp_pipeline_destroy(pipeline);
195 }
196
197 int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
198 {
199         int found = 0;
200         char *dup, *next, *tok, *name, *args;
201         struct dsp_element_entry *entry, *n;
202         struct dsp_pipeline_entry *pipeline_entry;
203         struct mISDN_dsp_element *elem;
204
205         if (!pipeline)
206                 return -EINVAL;
207
208         if (!list_empty(&pipeline->list))
209                 _dsp_pipeline_destroy(pipeline);
210
211         dup = next = kstrdup(cfg, GFP_ATOMIC);
212         if (!dup)
213                 return 0;
214         while ((tok = strsep(&next, "|"))) {
215                 if (!strlen(tok))
216                         continue;
217                 name = strsep(&tok, "(");
218                 args = strsep(&tok, ")");
219                 if (args && !*args)
220                         args = NULL;
221
222                 list_for_each_entry_safe(entry, n, &dsp_elements, list)
223                         if (!strcmp(entry->elem->name, name)) {
224                                 elem = entry->elem;
225
226                                 pipeline_entry = kmalloc(sizeof(struct
227                                                                 dsp_pipeline_entry), GFP_ATOMIC);
228                                 if (!pipeline_entry) {
229                                         printk(KERN_ERR "%s: failed to add "
230                                                "entry to pipeline: %s (out of "
231                                                "memory)\n", __func__, elem->name);
232                                         goto _out;
233                                 }
234                                 pipeline_entry->elem = elem;
235
236                                 if (elem == dsp_hwec) {
237                                         /* This is a hack to make the hwec
238                                            available as a pipeline module */
239                                         dsp_hwec_enable(container_of(pipeline,
240                                                                      struct dsp, pipeline), args);
241                                         list_add_tail(&pipeline_entry->list,
242                                                       &pipeline->list);
243                                 } else {
244                                         pipeline_entry->p = elem->new(args);
245                                         if (pipeline_entry->p) {
246                                                 list_add_tail(&pipeline_entry->
247                                                               list, &pipeline->list);
248                                         } else {
249                                                 printk(KERN_ERR "%s: failed "
250                                                        "to add entry to pipeline: "
251                                                        "%s (new() returned NULL)\n",
252                                                        __func__, elem->name);
253                                                 kfree(pipeline_entry);
254                                         }
255                                 }
256                                 found = 1;
257                                 break;
258                         }
259
260                 if (found)
261                         found = 0;
262                 else
263                         printk(KERN_ERR "%s: element not found, skipping: "
264                                "%s\n", __func__, name);
265         }
266
267 _out:
268         if (!list_empty(&pipeline->list))
269                 pipeline->inuse = 1;
270         else
271                 pipeline->inuse = 0;
272
273         kfree(dup);
274         return 0;
275 }
276
277 void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len)
278 {
279         struct dsp_pipeline_entry *entry;
280
281         if (!pipeline)
282                 return;
283
284         list_for_each_entry(entry, &pipeline->list, list)
285                 if (entry->elem->process_tx)
286                         entry->elem->process_tx(entry->p, data, len);
287 }
288
289 void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len,
290                              unsigned int txlen)
291 {
292         struct dsp_pipeline_entry *entry;
293
294         if (!pipeline)
295                 return;
296
297         list_for_each_entry_reverse(entry, &pipeline->list, list)
298                 if (entry->elem->process_rx)
299                         entry->elem->process_rx(entry->p, data, len, txlen);
300 }
This page took 0.044159 seconds and 4 git commands to generate.