root/drivers/isdn/mISDN/dsp_pipeline.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. attr_show_args
  2. mISDN_dsp_dev_release
  3. mISDN_dsp_element_register
  4. mISDN_dsp_element_unregister
  5. dsp_pipeline_module_init
  6. dsp_pipeline_module_exit
  7. dsp_pipeline_init
  8. _dsp_pipeline_destroy
  9. dsp_pipeline_destroy
  10. dsp_pipeline_build
  11. dsp_pipeline_process_tx
  12. dsp_pipeline_process_rx

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

/* [<][>][^][v][top][bottom][index][help] */