Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/isdn/mISDN/dsp_pipeline.c
15111 views
1
/*
2
* dsp_pipeline.c: pipelined audio processing
3
*
4
* Copyright (C) 2007, Nadi Sarrar
5
*
6
* Nadi Sarrar <[email protected]>
7
*
8
* This program is free software; you can redistribute it and/or modify it
9
* under the terms of the GNU General Public License as published by the Free
10
* Software Foundation; either version 2 of the License, or (at your option)
11
* any later version.
12
*
13
* This program is distributed in the hope that it will be useful, but WITHOUT
14
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16
* more details.
17
*
18
* You should have received a copy of the GNU General Public License along with
19
* this program; if not, write to the Free Software Foundation, Inc., 59
20
* Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
*
22
* The full GNU General Public License is included in this distribution in the
23
* file called LICENSE.
24
*
25
*/
26
27
#include <linux/kernel.h>
28
#include <linux/slab.h>
29
#include <linux/list.h>
30
#include <linux/string.h>
31
#include <linux/mISDNif.h>
32
#include <linux/mISDNdsp.h>
33
#include "dsp.h"
34
#include "dsp_hwec.h"
35
36
/* uncomment for debugging */
37
/*#define PIPELINE_DEBUG*/
38
39
struct dsp_pipeline_entry {
40
struct mISDN_dsp_element *elem;
41
void *p;
42
struct list_head list;
43
};
44
struct dsp_element_entry {
45
struct mISDN_dsp_element *elem;
46
struct device dev;
47
struct list_head list;
48
};
49
50
static LIST_HEAD(dsp_elements);
51
52
/* sysfs */
53
static struct class *elements_class;
54
55
static ssize_t
56
attr_show_args(struct device *dev, struct device_attribute *attr, char *buf)
57
{
58
struct mISDN_dsp_element *elem = dev_get_drvdata(dev);
59
int i;
60
char *p = buf;
61
62
*buf = 0;
63
for (i = 0; i < elem->num_args; i++)
64
p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n",
65
elem->args[i].name,
66
elem->args[i].def ? "Default: " : "",
67
elem->args[i].def ? elem->args[i].def : "",
68
elem->args[i].def ? "\n" : "",
69
elem->args[i].desc);
70
71
return p - buf;
72
}
73
74
static struct device_attribute element_attributes[] = {
75
__ATTR(args, 0444, attr_show_args, NULL),
76
};
77
78
static void
79
mISDN_dsp_dev_release(struct device *dev)
80
{
81
struct dsp_element_entry *entry =
82
container_of(dev, struct dsp_element_entry, dev);
83
list_del(&entry->list);
84
kfree(entry);
85
}
86
87
int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
88
{
89
struct dsp_element_entry *entry;
90
int ret, i;
91
92
if (!elem)
93
return -EINVAL;
94
95
entry = kzalloc(sizeof(struct dsp_element_entry), GFP_ATOMIC);
96
if (!entry)
97
return -ENOMEM;
98
99
entry->elem = elem;
100
101
entry->dev.class = elements_class;
102
entry->dev.release = mISDN_dsp_dev_release;
103
dev_set_drvdata(&entry->dev, elem);
104
dev_set_name(&entry->dev, elem->name);
105
ret = device_register(&entry->dev);
106
if (ret) {
107
printk(KERN_ERR "%s: failed to register %s\n",
108
__func__, elem->name);
109
goto err1;
110
}
111
list_add_tail(&entry->list, &dsp_elements);
112
113
for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) {
114
ret = device_create_file(&entry->dev,
115
&element_attributes[i]);
116
if (ret) {
117
printk(KERN_ERR "%s: failed to create device file\n",
118
__func__);
119
goto err2;
120
}
121
}
122
123
#ifdef PIPELINE_DEBUG
124
printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name);
125
#endif
126
127
return 0;
128
129
err2:
130
device_unregister(&entry->dev);
131
return ret;
132
err1:
133
kfree(entry);
134
return ret;
135
}
136
EXPORT_SYMBOL(mISDN_dsp_element_register);
137
138
void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem)
139
{
140
struct dsp_element_entry *entry, *n;
141
142
if (!elem)
143
return;
144
145
list_for_each_entry_safe(entry, n, &dsp_elements, list)
146
if (entry->elem == elem) {
147
device_unregister(&entry->dev);
148
#ifdef PIPELINE_DEBUG
149
printk(KERN_DEBUG "%s: %s unregistered\n",
150
__func__, elem->name);
151
#endif
152
return;
153
}
154
printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);
155
}
156
EXPORT_SYMBOL(mISDN_dsp_element_unregister);
157
158
int dsp_pipeline_module_init(void)
159
{
160
elements_class = class_create(THIS_MODULE, "dsp_pipeline");
161
if (IS_ERR(elements_class))
162
return PTR_ERR(elements_class);
163
164
#ifdef PIPELINE_DEBUG
165
printk(KERN_DEBUG "%s: dsp pipeline module initialized\n", __func__);
166
#endif
167
168
dsp_hwec_init();
169
170
return 0;
171
}
172
173
void dsp_pipeline_module_exit(void)
174
{
175
struct dsp_element_entry *entry, *n;
176
177
dsp_hwec_exit();
178
179
class_destroy(elements_class);
180
181
list_for_each_entry_safe(entry, n, &dsp_elements, list) {
182
list_del(&entry->list);
183
printk(KERN_WARNING "%s: element was still registered: %s\n",
184
__func__, entry->elem->name);
185
kfree(entry);
186
}
187
188
#ifdef PIPELINE_DEBUG
189
printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__);
190
#endif
191
}
192
193
int dsp_pipeline_init(struct dsp_pipeline *pipeline)
194
{
195
if (!pipeline)
196
return -EINVAL;
197
198
INIT_LIST_HEAD(&pipeline->list);
199
200
#ifdef PIPELINE_DEBUG
201
printk(KERN_DEBUG "%s: dsp pipeline ready\n", __func__);
202
#endif
203
204
return 0;
205
}
206
207
static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
208
{
209
struct dsp_pipeline_entry *entry, *n;
210
211
list_for_each_entry_safe(entry, n, &pipeline->list, list) {
212
list_del(&entry->list);
213
if (entry->elem == dsp_hwec)
214
dsp_hwec_disable(container_of(pipeline, struct dsp,
215
pipeline));
216
else
217
entry->elem->free(entry->p);
218
kfree(entry);
219
}
220
}
221
222
void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
223
{
224
225
if (!pipeline)
226
return;
227
228
_dsp_pipeline_destroy(pipeline);
229
230
#ifdef PIPELINE_DEBUG
231
printk(KERN_DEBUG "%s: dsp pipeline destroyed\n", __func__);
232
#endif
233
}
234
235
int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
236
{
237
int len, incomplete = 0, found = 0;
238
char *dup, *tok, *name, *args;
239
struct dsp_element_entry *entry, *n;
240
struct dsp_pipeline_entry *pipeline_entry;
241
struct mISDN_dsp_element *elem;
242
243
if (!pipeline)
244
return -EINVAL;
245
246
if (!list_empty(&pipeline->list))
247
_dsp_pipeline_destroy(pipeline);
248
249
if (!cfg)
250
return 0;
251
252
len = strlen(cfg);
253
if (!len)
254
return 0;
255
256
dup = kmalloc(len + 1, GFP_ATOMIC);
257
if (!dup)
258
return 0;
259
strcpy(dup, cfg);
260
while ((tok = strsep(&dup, "|"))) {
261
if (!strlen(tok))
262
continue;
263
name = strsep(&tok, "(");
264
args = strsep(&tok, ")");
265
if (args && !*args)
266
args = NULL;
267
268
list_for_each_entry_safe(entry, n, &dsp_elements, list)
269
if (!strcmp(entry->elem->name, name)) {
270
elem = entry->elem;
271
272
pipeline_entry = kmalloc(sizeof(struct
273
dsp_pipeline_entry), GFP_ATOMIC);
274
if (!pipeline_entry) {
275
printk(KERN_ERR "%s: failed to add "
276
"entry to pipeline: %s (out of "
277
"memory)\n", __func__, elem->name);
278
incomplete = 1;
279
goto _out;
280
}
281
pipeline_entry->elem = elem;
282
283
if (elem == dsp_hwec) {
284
/* This is a hack to make the hwec
285
available as a pipeline module */
286
dsp_hwec_enable(container_of(pipeline,
287
struct dsp, pipeline), args);
288
list_add_tail(&pipeline_entry->list,
289
&pipeline->list);
290
} else {
291
pipeline_entry->p = elem->new(args);
292
if (pipeline_entry->p) {
293
list_add_tail(&pipeline_entry->
294
list, &pipeline->list);
295
#ifdef PIPELINE_DEBUG
296
printk(KERN_DEBUG "%s: created "
297
"instance of %s%s%s\n",
298
__func__, name, args ?
299
" with args " : "", args ?
300
args : "");
301
#endif
302
} else {
303
printk(KERN_ERR "%s: failed "
304
"to add entry to pipeline: "
305
"%s (new() returned NULL)\n",
306
__func__, elem->name);
307
kfree(pipeline_entry);
308
incomplete = 1;
309
}
310
}
311
found = 1;
312
break;
313
}
314
315
if (found)
316
found = 0;
317
else {
318
printk(KERN_ERR "%s: element not found, skipping: "
319
"%s\n", __func__, name);
320
incomplete = 1;
321
}
322
}
323
324
_out:
325
if (!list_empty(&pipeline->list))
326
pipeline->inuse = 1;
327
else
328
pipeline->inuse = 0;
329
330
#ifdef PIPELINE_DEBUG
331
printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n",
332
__func__, incomplete ? " incomplete" : "", cfg);
333
#endif
334
kfree(dup);
335
return 0;
336
}
337
338
void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len)
339
{
340
struct dsp_pipeline_entry *entry;
341
342
if (!pipeline)
343
return;
344
345
list_for_each_entry(entry, &pipeline->list, list)
346
if (entry->elem->process_tx)
347
entry->elem->process_tx(entry->p, data, len);
348
}
349
350
void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len,
351
unsigned int txlen)
352
{
353
struct dsp_pipeline_entry *entry;
354
355
if (!pipeline)
356
return;
357
358
list_for_each_entry_reverse(entry, &pipeline->list, list)
359
if (entry->elem->process_rx)
360
entry->elem->process_rx(entry->p, data, len, txlen);
361
}
362
363
364
365