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