Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dsp_pipeline.c
Go to the documentation of this file.
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 <linux/export.h>
34 #include "dsp.h"
35 #include "dsp_hwec.h"
36 
37 /* uncomment for debugging */
38 /*#define PIPELINE_DEBUG*/
39 
42  void *p;
43  struct list_head list;
44 };
47  struct device dev;
48  struct list_head list;
49 };
50 
51 static LIST_HEAD(dsp_elements);
52 
53 /* sysfs */
54 static struct class *elements_class;
55 
56 static ssize_t
57 attr_show_args(struct device *dev, struct device_attribute *attr, char *buf)
58 {
59  struct mISDN_dsp_element *elem = dev_get_drvdata(dev);
60  int i;
61  char *p = buf;
62 
63  *buf = 0;
64  for (i = 0; i < elem->num_args; i++)
65  p += sprintf(p, "Name: %s\n%s%s%sDescription: %s\n\n",
66  elem->args[i].name,
67  elem->args[i].def ? "Default: " : "",
68  elem->args[i].def ? elem->args[i].def : "",
69  elem->args[i].def ? "\n" : "",
70  elem->args[i].desc);
71 
72  return p - buf;
73 }
74 
75 static struct device_attribute element_attributes[] = {
76  __ATTR(args, 0444, attr_show_args, NULL),
77 };
78 
79 static void
80 mISDN_dsp_dev_release(struct device *dev)
81 {
82  struct dsp_element_entry *entry =
83  container_of(dev, struct dsp_element_entry, dev);
84  list_del(&entry->list);
85  kfree(entry);
86 }
87 
89 {
90  struct dsp_element_entry *entry;
91  int ret, i;
92 
93  if (!elem)
94  return -EINVAL;
95 
96  entry = kzalloc(sizeof(struct dsp_element_entry), GFP_ATOMIC);
97  if (!entry)
98  return -ENOMEM;
99 
100  entry->elem = elem;
101 
102  entry->dev.class = elements_class;
103  entry->dev.release = mISDN_dsp_dev_release;
104  dev_set_drvdata(&entry->dev, elem);
105  dev_set_name(&entry->dev, elem->name);
106  ret = device_register(&entry->dev);
107  if (ret) {
108  printk(KERN_ERR "%s: failed to register %s\n",
109  __func__, elem->name);
110  goto err1;
111  }
112  list_add_tail(&entry->list, &dsp_elements);
113 
114  for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) {
115  ret = device_create_file(&entry->dev,
116  &element_attributes[i]);
117  if (ret) {
118  printk(KERN_ERR "%s: failed to create device file\n",
119  __func__);
120  goto err2;
121  }
122  }
123 
124 #ifdef PIPELINE_DEBUG
125  printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name);
126 #endif
127 
128  return 0;
129 
130 err2:
131  device_unregister(&entry->dev);
132  return ret;
133 err1:
134  kfree(entry);
135  return ret;
136 }
138 
140 {
141  struct dsp_element_entry *entry, *n;
142 
143  if (!elem)
144  return;
145 
146  list_for_each_entry_safe(entry, n, &dsp_elements, list)
147  if (entry->elem == elem) {
148  device_unregister(&entry->dev);
149 #ifdef PIPELINE_DEBUG
150  printk(KERN_DEBUG "%s: %s unregistered\n",
151  __func__, elem->name);
152 #endif
153  return;
154  }
155  printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);
156 }
158 
160 {
161  elements_class = class_create(THIS_MODULE, "dsp_pipeline");
162  if (IS_ERR(elements_class))
163  return PTR_ERR(elements_class);
164 
165 #ifdef PIPELINE_DEBUG
166  printk(KERN_DEBUG "%s: dsp pipeline module initialized\n", __func__);
167 #endif
168 
169  dsp_hwec_init();
170 
171  return 0;
172 }
173 
175 {
176  struct dsp_element_entry *entry, *n;
177 
178  dsp_hwec_exit();
179 
180  class_destroy(elements_class);
181 
182  list_for_each_entry_safe(entry, n, &dsp_elements, list) {
183  list_del(&entry->list);
184  printk(KERN_WARNING "%s: element was still registered: %s\n",
185  __func__, entry->elem->name);
186  kfree(entry);
187  }
188 
189 #ifdef PIPELINE_DEBUG
190  printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__);
191 #endif
192 }
193 
194 int dsp_pipeline_init(struct dsp_pipeline *pipeline)
195 {
196  if (!pipeline)
197  return -EINVAL;
198 
199  INIT_LIST_HEAD(&pipeline->list);
200 
201 #ifdef PIPELINE_DEBUG
202  printk(KERN_DEBUG "%s: dsp pipeline ready\n", __func__);
203 #endif
204 
205  return 0;
206 }
207 
208 static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
209 {
210  struct dsp_pipeline_entry *entry, *n;
211 
212  list_for_each_entry_safe(entry, n, &pipeline->list, list) {
213  list_del(&entry->list);
214  if (entry->elem == dsp_hwec)
215  dsp_hwec_disable(container_of(pipeline, struct dsp,
216  pipeline));
217  else
218  entry->elem->free(entry->p);
219  kfree(entry);
220  }
221 }
222 
223 void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
224 {
225 
226  if (!pipeline)
227  return;
228 
229  _dsp_pipeline_destroy(pipeline);
230 
231 #ifdef PIPELINE_DEBUG
232  printk(KERN_DEBUG "%s: dsp pipeline destroyed\n", __func__);
233 #endif
234 }
235 
236 int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
237 {
238  int len, incomplete = 0, found = 0;
239  char *dup, *tok, *name, *args;
240  struct dsp_element_entry *entry, *n;
241  struct dsp_pipeline_entry *pipeline_entry;
242  struct mISDN_dsp_element *elem;
243 
244  if (!pipeline)
245  return -EINVAL;
246 
247  if (!list_empty(&pipeline->list))
248  _dsp_pipeline_destroy(pipeline);
249 
250  if (!cfg)
251  return 0;
252 
253  len = strlen(cfg);
254  if (!len)
255  return 0;
256 
257  dup = kmalloc(len + 1, GFP_ATOMIC);
258  if (!dup)
259  return 0;
260  strcpy(dup, cfg);
261  while ((tok = strsep(&dup, "|"))) {
262  if (!strlen(tok))
263  continue;
264  name = strsep(&tok, "(");
265  args = strsep(&tok, ")");
266  if (args && !*args)
267  args = NULL;
268 
269  list_for_each_entry_safe(entry, n, &dsp_elements, list)
270  if (!strcmp(entry->elem->name, name)) {
271  elem = entry->elem;
272 
273  pipeline_entry = kmalloc(sizeof(struct
275  if (!pipeline_entry) {
276  printk(KERN_ERR "%s: failed to add "
277  "entry to pipeline: %s (out of "
278  "memory)\n", __func__, elem->name);
279  incomplete = 1;
280  goto _out;
281  }
282  pipeline_entry->elem = elem;
283 
284  if (elem == dsp_hwec) {
285  /* This is a hack to make the hwec
286  available as a pipeline module */
287  dsp_hwec_enable(container_of(pipeline,
288  struct dsp, pipeline), args);
289  list_add_tail(&pipeline_entry->list,
290  &pipeline->list);
291  } else {
292  pipeline_entry->p = elem->new(args);
293  if (pipeline_entry->p) {
294  list_add_tail(&pipeline_entry->
295  list, &pipeline->list);
296 #ifdef PIPELINE_DEBUG
297  printk(KERN_DEBUG "%s: created "
298  "instance of %s%s%s\n",
299  __func__, name, args ?
300  " with args " : "", args ?
301  args : "");
302 #endif
303  } else {
304  printk(KERN_ERR "%s: failed "
305  "to add entry to pipeline: "
306  "%s (new() returned NULL)\n",
307  __func__, elem->name);
308  kfree(pipeline_entry);
309  incomplete = 1;
310  }
311  }
312  found = 1;
313  break;
314  }
315 
316  if (found)
317  found = 0;
318  else {
319  printk(KERN_ERR "%s: element not found, skipping: "
320  "%s\n", __func__, name);
321  incomplete = 1;
322  }
323  }
324 
325 _out:
326  if (!list_empty(&pipeline->list))
327  pipeline->inuse = 1;
328  else
329  pipeline->inuse = 0;
330 
331 #ifdef PIPELINE_DEBUG
332  printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n",
333  __func__, incomplete ? " incomplete" : "", cfg);
334 #endif
335  kfree(dup);
336  return 0;
337 }
338 
339 void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len)
340 {
341  struct dsp_pipeline_entry *entry;
342 
343  if (!pipeline)
344  return;
345 
346  list_for_each_entry(entry, &pipeline->list, list)
347  if (entry->elem->process_tx)
348  entry->elem->process_tx(entry->p, data, len);
349 }
350 
351 void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len,
352  unsigned int txlen)
353 {
354  struct dsp_pipeline_entry *entry;
355 
356  if (!pipeline)
357  return;
358 
359  list_for_each_entry_reverse(entry, &pipeline->list, list)
360  if (entry->elem->process_rx)
361  entry->elem->process_rx(entry->p, data, len, txlen);
362 }